2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2014 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2014-03-26 16:55:20 +06:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup bke
|
2014-03-26 16:55:20 +06:00
|
|
|
*/
|
|
|
|
|
|
2023-07-22 11:27:25 +10:00
|
|
|
#include <cstdlib>
|
2014-03-26 16:55:20 +06:00
|
|
|
|
|
|
|
|
#include "DNA_anim_types.h"
|
|
|
|
|
|
2016-03-24 12:28:41 +01:00
|
|
|
#include "BLI_ghash.h"
|
|
|
|
|
#include "BLI_linklist_stack.h"
|
2020-04-03 17:38:58 +02:00
|
|
|
#include "BLI_listbase.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2014-03-26 16:55:20 +06:00
|
|
|
|
2020-04-03 13:07:36 +02:00
|
|
|
#include "BKE_anim_data.h"
|
Datablock ID Properties
The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the [[http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.67/Python_Nodes|Python Nodes release notes]]. So this patch allows Python scripts to create ID Properties which reference datablocks.
This functionality is implemented for `PointerProperty` and now such properties can be created with Python.
In addition to the standard update callback, `PointerProperty` can have a `poll` callback (standard RNA) which is useful for search menus. For details see the test included in this patch.
Original author: @artfunkel
Alexander (Blend4Web Team)
Reviewers: brecht, artfunkel, mont29, campbellbarton
Reviewed By: mont29, campbellbarton
Subscribers: jta, sergey, campbellbarton, wisaac, poseidon4o, mont29, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov, fjuhec, sharlybg, cardboard, duarteframos, blueprintrandom, a.romanov, BYOB, disnel, aditiapratama, bliblubli, dfelinto, lukastoenne
Maniphest Tasks: T37754
Differential Revision: https://developer.blender.org/D113
2017-04-13 12:30:03 +03:00
|
|
|
#include "BKE_idprop.h"
|
2024-01-20 19:17:36 +01:00
|
|
|
#include "BKE_idtype.hh"
|
2024-01-15 12:44:04 -05:00
|
|
|
#include "BKE_lib_id.hh"
|
2024-01-18 12:20:42 +01:00
|
|
|
#include "BKE_lib_query.hh"
|
2023-12-01 19:43:16 +01:00
|
|
|
#include "BKE_main.hh"
|
2024-02-19 15:54:48 +01:00
|
|
|
#include "BKE_node.h"
|
2014-03-26 16:55:20 +06:00
|
|
|
|
2016-03-24 12:28:41 +01:00
|
|
|
/* status */
|
|
|
|
|
enum {
|
|
|
|
|
IDWALK_STOP = 1 << 0,
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
struct LibraryForeachIDData {
|
2020-02-13 15:13:19 +01:00
|
|
|
Main *bmain;
|
2020-03-11 12:47:25 +01:00
|
|
|
/**
|
2021-03-01 11:00:22 +11:00
|
|
|
* 'Real' ID, the one that might be in `bmain`, only differs from self_id when the later is a
|
2020-03-11 12:47:25 +01:00
|
|
|
* private one.
|
|
|
|
|
*/
|
2020-02-13 15:13:19 +01:00
|
|
|
ID *owner_id;
|
2020-03-11 12:47:25 +01:00
|
|
|
/**
|
|
|
|
|
* ID from which the current ID pointer is being processed. It may be an embedded ID like master
|
|
|
|
|
* collection or root node tree.
|
|
|
|
|
*/
|
2014-03-26 16:55:20 +06:00
|
|
|
ID *self_id;
|
2020-02-13 15:13:19 +01:00
|
|
|
|
2021-05-06 08:09:05 +10:00
|
|
|
/** Flags controlling the behavior of the 'foreach id' looping code. */
|
2014-03-26 16:55:20 +06:00
|
|
|
int flag;
|
2021-05-05 12:51:12 +02:00
|
|
|
/** Generic flags to be passed to all callback calls for current processed data. */
|
2017-01-31 10:41:25 +01:00
|
|
|
int cb_flag;
|
2021-05-05 12:51:12 +02:00
|
|
|
/** Callback flags that are forbidden for all callback calls for current processed data. */
|
2019-02-18 15:17:06 +01:00
|
|
|
int cb_flag_clear;
|
2021-05-05 12:51:12 +02:00
|
|
|
|
|
|
|
|
/* Function to call for every ID pointers of current processed data, and its opaque user data
|
|
|
|
|
* pointer. */
|
2014-03-26 16:55:20 +06:00
|
|
|
LibraryIDLinkCallback callback;
|
|
|
|
|
void *user_data;
|
2021-05-05 12:51:12 +02:00
|
|
|
/** Store the returned value from the callback, to decide how to continue the processing of ID
|
|
|
|
|
* pointers for current data. */
|
2016-03-24 12:28:41 +01:00
|
|
|
int status;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-24 12:28:41 +01:00
|
|
|
/* To handle recursion. */
|
|
|
|
|
GSet *ids_handled; /* All IDs that are either already done, or still in ids_todo stack. */
|
|
|
|
|
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
|
2023-07-17 10:46:26 +02:00
|
|
|
};
|
2014-03-26 16:55:20 +06:00
|
|
|
|
2023-06-29 10:56:33 +10:00
|
|
|
bool BKE_lib_query_foreachid_iter_stop(const LibraryForeachIDData *data)
|
2021-10-26 17:23:38 +02:00
|
|
|
{
|
|
|
|
|
return (data->status & IDWALK_STOP) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-27 12:16:31 +02:00
|
|
|
void BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag)
|
2020-05-07 12:36:35 +02:00
|
|
|
{
|
2021-10-27 12:16:31 +02:00
|
|
|
if (BKE_lib_query_foreachid_iter_stop(data)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-05-05 12:31:38 +02:00
|
|
|
|
2021-10-27 12:16:31 +02:00
|
|
|
const int flag = data->flag;
|
|
|
|
|
ID *old_id = *id_pp;
|
|
|
|
|
|
|
|
|
|
/* Update the callback flags with the ones defined (or forbidden) in `data` by the generic
|
|
|
|
|
* caller code. */
|
|
|
|
|
cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear);
|
|
|
|
|
|
|
|
|
|
/* Update the callback flags with some extra information regarding overrides: all 'loopback',
|
|
|
|
|
* 'internal', 'embedded' etc. ID pointers are never overridable. */
|
|
|
|
|
if (cb_flag & (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
|
|
|
|
|
cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
LibraryIDLinkCallbackData callback_data{};
|
|
|
|
|
callback_data.user_data = data->user_data;
|
|
|
|
|
callback_data.bmain = data->bmain;
|
|
|
|
|
callback_data.owner_id = data->owner_id;
|
|
|
|
|
callback_data.self_id = data->self_id;
|
|
|
|
|
callback_data.id_pointer = id_pp;
|
|
|
|
|
callback_data.cb_flag = cb_flag;
|
|
|
|
|
const int callback_return = data->callback(&callback_data);
|
2021-10-27 12:16:31 +02:00
|
|
|
if (flag & IDWALK_READONLY) {
|
|
|
|
|
BLI_assert(*(id_pp) == old_id);
|
|
|
|
|
}
|
|
|
|
|
if (old_id && (flag & IDWALK_RECURSE)) {
|
|
|
|
|
if (BLI_gset_add((data)->ids_handled, old_id)) {
|
|
|
|
|
if (!(callback_return & IDWALK_RET_STOP_RECURSION)) {
|
|
|
|
|
BLI_LINKSTACK_PUSH(data->ids_todo, old_id);
|
2020-05-07 12:36:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-27 12:16:31 +02:00
|
|
|
if (callback_return & IDWALK_RET_STOP_ITER) {
|
|
|
|
|
data->status |= IDWALK_STOP;
|
|
|
|
|
}
|
2020-05-07 12:36:35 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-29 10:56:33 +10:00
|
|
|
int BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
|
2020-05-18 18:51:06 +02:00
|
|
|
{
|
|
|
|
|
return data->flag;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-21 19:09:48 +02:00
|
|
|
int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData *data,
|
|
|
|
|
const int cb_flag,
|
|
|
|
|
const bool do_replace)
|
|
|
|
|
{
|
|
|
|
|
const int cb_flag_backup = data->cb_flag;
|
|
|
|
|
if (do_replace) {
|
|
|
|
|
data->cb_flag = cb_flag;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
data->cb_flag |= cb_flag;
|
|
|
|
|
}
|
|
|
|
|
return cb_flag_backup;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-27 12:04:36 +02:00
|
|
|
static bool library_foreach_ID_link(Main *bmain,
|
2023-05-16 18:14:43 +02:00
|
|
|
ID *owner_id,
|
2019-03-04 16:14:36 +01:00
|
|
|
ID *id,
|
|
|
|
|
LibraryIDLinkCallback callback,
|
|
|
|
|
void *user_data,
|
|
|
|
|
int flag,
|
|
|
|
|
LibraryForeachIDData *inherit_data);
|
|
|
|
|
|
2020-05-07 12:36:35 +02:00
|
|
|
void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void *user_data)
|
Datablock ID Properties
The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the [[http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.67/Python_Nodes|Python Nodes release notes]]. So this patch allows Python scripts to create ID Properties which reference datablocks.
This functionality is implemented for `PointerProperty` and now such properties can be created with Python.
In addition to the standard update callback, `PointerProperty` can have a `poll` callback (standard RNA) which is useful for search menus. For details see the test included in this patch.
Original author: @artfunkel
Alexander (Blend4Web Team)
Reviewers: brecht, artfunkel, mont29, campbellbarton
Reviewed By: mont29, campbellbarton
Subscribers: jta, sergey, campbellbarton, wisaac, poseidon4o, mont29, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov, fjuhec, sharlybg, cardboard, duarteframos, blueprintrandom, a.romanov, BYOB, disnel, aditiapratama, bliblubli, dfelinto, lukastoenne
Maniphest Tasks: T37754
Differential Revision: https://developer.blender.org/D113
2017-04-13 12:30:03 +03:00
|
|
|
{
|
2020-04-25 20:58:55 +02:00
|
|
|
BLI_assert(id_prop->type == IDP_ID);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-25 20:58:55 +02:00
|
|
|
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
|
2021-05-05 12:44:05 +02:00
|
|
|
const int cb_flag = IDWALK_CB_USER | ((id_prop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) ?
|
|
|
|
|
0 :
|
|
|
|
|
IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE);
|
|
|
|
|
BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, cb_flag);
|
Datablock ID Properties
The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the [[http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.67/Python_Nodes|Python Nodes release notes]]. So this patch allows Python scripts to create ID Properties which reference datablocks.
This functionality is implemented for `PointerProperty` and now such properties can be created with Python.
In addition to the standard update callback, `PointerProperty` can have a `poll` callback (standard RNA) which is useful for search menus. For details see the test included in this patch.
Original author: @artfunkel
Alexander (Blend4Web Team)
Reviewers: brecht, artfunkel, mont29, campbellbarton
Reviewed By: mont29, campbellbarton
Subscribers: jta, sergey, campbellbarton, wisaac, poseidon4o, mont29, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov, fjuhec, sharlybg, cardboard, duarteframos, blueprintrandom, a.romanov, BYOB, disnel, aditiapratama, bliblubli, dfelinto, lukastoenne
Maniphest Tasks: T37754
Differential Revision: https://developer.blender.org/D113
2017-04-13 12:30:03 +03:00
|
|
|
}
|
|
|
|
|
|
2021-10-27 12:16:31 +02:00
|
|
|
void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
|
2016-10-04 15:03:34 +02:00
|
|
|
{
|
2023-08-23 11:39:47 +02:00
|
|
|
/* Needed e.g. for callbacks handling relationships. This call should be absolutely read-only. */
|
2017-01-30 21:34:23 +01:00
|
|
|
ID *id = *id_pp;
|
2020-04-30 18:01:47 +02:00
|
|
|
const int flag = data->flag;
|
|
|
|
|
|
2021-10-27 12:16:31 +02:00
|
|
|
BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED);
|
|
|
|
|
if (BKE_lib_query_foreachid_iter_stop(data)) {
|
|
|
|
|
return;
|
2020-05-07 12:36:35 +02:00
|
|
|
}
|
2017-01-30 21:34:23 +01:00
|
|
|
BLI_assert(id == *id_pp);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (id == nullptr) {
|
2021-10-27 12:16:31 +02:00
|
|
|
return;
|
2020-05-07 12:36:35 +02:00
|
|
|
}
|
|
|
|
|
|
2020-03-11 17:25:31 +01:00
|
|
|
if (flag & IDWALK_IGNORE_EMBEDDED_ID) {
|
|
|
|
|
/* Do Nothing. */
|
|
|
|
|
}
|
|
|
|
|
else if (flag & IDWALK_RECURSE) {
|
2019-04-27 12:07:07 +10:00
|
|
|
/* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in
|
2023-02-12 14:37:16 +11:00
|
|
|
* IDWALK_RECURSE case is troublesome, see #49553. */
|
2020-02-13 15:13:19 +01:00
|
|
|
/* XXX note that this breaks the 'owner id' thing now, we likely want to handle that
|
|
|
|
|
* differently at some point, but for now it should not be a problem in practice. */
|
2018-12-02 08:13:31 +11:00
|
|
|
if (BLI_gset_add(data->ids_handled, id)) {
|
2016-10-04 15:03:34 +02:00
|
|
|
BLI_LINKSTACK_PUSH(data->ids_todo, id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2021-10-27 12:16:31 +02:00
|
|
|
if (!library_foreach_ID_link(
|
|
|
|
|
data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data))
|
|
|
|
|
{
|
|
|
|
|
data->status |= IDWALK_STOP;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-10-04 15:03:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-03-26 16:55:20 +06:00
|
|
|
|
2021-10-27 12:04:36 +02:00
|
|
|
static void library_foreach_ID_data_cleanup(LibraryForeachIDData *data)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
if (data->ids_handled != nullptr) {
|
|
|
|
|
BLI_gset_free(data->ids_handled, nullptr);
|
2021-10-27 12:04:36 +02:00
|
|
|
BLI_LINKSTACK_FREE(data->ids_todo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \return false in case iteration over ID pointers must be stopped, true otherwise. */
|
|
|
|
|
static bool library_foreach_ID_link(Main *bmain,
|
2023-05-16 18:14:43 +02:00
|
|
|
ID *owner_id,
|
2019-03-04 16:14:36 +01:00
|
|
|
ID *id,
|
|
|
|
|
LibraryIDLinkCallback callback,
|
|
|
|
|
void *user_data,
|
|
|
|
|
int flag,
|
|
|
|
|
LibraryForeachIDData *inherit_data)
|
2014-03-26 16:55:20 +06:00
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
LibraryForeachIDData data{};
|
|
|
|
|
data.bmain = bmain;
|
2014-03-26 16:55:20 +06:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(inherit_data == nullptr || data.bmain == inherit_data->bmain);
|
2023-08-23 11:39:47 +02:00
|
|
|
/* `IDWALK_NO_ORIG_POINTERS_ACCESS` is mutually exclusive with `IDWALK_RECURSE`. */
|
2023-04-24 15:30:04 +02:00
|
|
|
BLI_assert((flag & (IDWALK_NO_ORIG_POINTERS_ACCESS | IDWALK_RECURSE)) !=
|
|
|
|
|
(IDWALK_NO_ORIG_POINTERS_ACCESS | IDWALK_RECURSE));
|
2020-02-13 15:13:19 +01:00
|
|
|
|
2016-03-24 12:28:41 +01:00
|
|
|
if (flag & IDWALK_RECURSE) {
|
2021-03-12 09:39:23 +01:00
|
|
|
/* For now, recursion implies read-only, and no internal pointers. */
|
2016-03-24 12:28:41 +01:00
|
|
|
flag |= IDWALK_READONLY;
|
2021-03-12 09:39:23 +01:00
|
|
|
flag &= ~IDWALK_DO_INTERNAL_RUNTIME_POINTERS;
|
2016-03-24 12:28:41 +01:00
|
|
|
|
2021-10-26 17:22:10 +02:00
|
|
|
/* NOTE: This function itself should never be called recursively when IDWALK_RECURSE is set,
|
|
|
|
|
* see also comments in #BKE_library_foreach_ID_embedded.
|
|
|
|
|
* This is why we can always create this data here, and do not need to try and re-use it from
|
|
|
|
|
* `inherit_data`. */
|
2016-03-24 12:28:41 +01:00
|
|
|
data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
|
|
|
|
|
BLI_LINKSTACK_INIT(data.ids_todo);
|
2016-10-04 15:03:34 +02:00
|
|
|
|
|
|
|
|
BLI_gset_add(data.ids_handled, id);
|
2016-03-24 12:28:41 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2023-07-17 10:46:26 +02:00
|
|
|
data.ids_handled = nullptr;
|
2016-03-24 12:28:41 +01:00
|
|
|
}
|
2014-03-26 16:55:20 +06:00
|
|
|
data.flag = flag;
|
2016-03-26 16:07:57 +01:00
|
|
|
data.status = 0;
|
2014-03-26 16:55:20 +06:00
|
|
|
data.callback = callback;
|
|
|
|
|
data.user_data = user_data;
|
|
|
|
|
|
2020-05-21 19:36:05 +02:00
|
|
|
#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
|
2021-10-27 12:04:36 +02:00
|
|
|
{ \
|
|
|
|
|
CHECK_TYPE_ANY((check_id), ID *, void *); \
|
|
|
|
|
BKE_lib_query_foreachid_process(&data, (ID **)&(check_id), (cb_flag)); \
|
|
|
|
|
if (BKE_lib_query_foreachid_iter_stop(&data)) { \
|
|
|
|
|
library_foreach_ID_data_cleanup(&data); \
|
|
|
|
|
return false; \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
((void)0)
|
2014-03-26 16:55:20 +06:00
|
|
|
|
|
|
|
|
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
|
2021-10-27 12:04:36 +02:00
|
|
|
{ \
|
|
|
|
|
CHECK_TYPE(&((check_id_super)->id), ID *); \
|
|
|
|
|
BKE_lib_query_foreachid_process(&data, (ID **)&(check_id_super), (cb_flag)); \
|
|
|
|
|
if (BKE_lib_query_foreachid_iter_stop(&data)) { \
|
|
|
|
|
library_foreach_ID_data_cleanup(&data); \
|
|
|
|
|
return false; \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
((void)0)
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-18 14:55:33 +10:00
|
|
|
for (; id != nullptr; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : nullptr)
|
2023-07-17 10:46:26 +02:00
|
|
|
{
|
2016-03-24 12:28:41 +01:00
|
|
|
data.self_id = id;
|
2020-03-11 14:35:03 +01:00
|
|
|
/* Note that we may call this functions sometime directly on an embedded ID, without any
|
|
|
|
|
* knowledge of the owner ID then.
|
|
|
|
|
* While not great, and that should be probably sanitized at some point, we cal live with it
|
|
|
|
|
* for now. */
|
2023-07-17 10:46:26 +02:00
|
|
|
data.owner_id = ((id->flag & LIB_EMBEDDED_DATA) != 0 && owner_id != nullptr) ? owner_id :
|
|
|
|
|
data.self_id;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
/* inherit_data is non-nullptr when this function is called for some sub-data ID
|
2021-03-01 11:00:22 +11:00
|
|
|
* (like root node-tree of a material).
|
2019-04-27 12:07:07 +10:00
|
|
|
* In that case, we do not want to generate those 'generic flags' from our current sub-data ID
|
|
|
|
|
* (the node tree), but re-use those generated for the 'owner' ID (the material). */
|
2023-07-17 10:46:26 +02:00
|
|
|
if (inherit_data == nullptr) {
|
2019-03-04 16:14:36 +01:00
|
|
|
data.cb_flag = ID_IS_LINKED(id) ? IDWALK_CB_INDIRECT_USAGE : 0;
|
2023-01-03 10:19:27 +11:00
|
|
|
/* When an ID is defined as not reference-counting its ID usages, it should never do it. */
|
2021-05-26 11:45:27 +02:00
|
|
|
data.cb_flag_clear = (id->tag & LIB_TAG_NO_USER_REFCOUNT) ?
|
|
|
|
|
IDWALK_CB_USER | IDWALK_CB_USER_ONE :
|
|
|
|
|
0;
|
2019-03-04 16:14:36 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
data.cb_flag = inherit_data->cb_flag;
|
|
|
|
|
data.cb_flag_clear = inherit_data->cb_flag_clear;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-08-22 15:42:19 +02:00
|
|
|
bool use_bmain_relations = bmain != nullptr && bmain->relations != nullptr &&
|
|
|
|
|
(flag & IDWALK_READONLY);
|
|
|
|
|
/* Including UI-related ID pointers should match with the relevant setting in Main relations
|
|
|
|
|
* cache. */
|
|
|
|
|
if (use_bmain_relations && (((bmain->relations->flag & MAINIDRELATIONS_INCLUDE_UI) == 0) !=
|
|
|
|
|
((data.flag & IDWALK_INCLUDE_UI) == 0)))
|
2020-02-18 11:21:34 +01:00
|
|
|
{
|
2023-08-22 15:42:19 +02:00
|
|
|
use_bmain_relations = false;
|
|
|
|
|
}
|
|
|
|
|
/* No special 'internal' handling of ID pointers is covered by Main relations cache. */
|
|
|
|
|
if (use_bmain_relations &&
|
|
|
|
|
(flag & (IDWALK_DO_INTERNAL_RUNTIME_POINTERS | IDWALK_DO_LIBRARY_POINTER |
|
|
|
|
|
IDWALK_DO_DEPRECATED_POINTERS)))
|
|
|
|
|
{
|
|
|
|
|
use_bmain_relations = false;
|
|
|
|
|
}
|
|
|
|
|
if (use_bmain_relations) {
|
2019-04-27 12:07:07 +10:00
|
|
|
/* Note that this is minor optimization, even in worst cases (like id being an object with
|
|
|
|
|
* lots of drivers and constraints and modifiers, or material etc. with huge node tree),
|
|
|
|
|
* but we might as well use it (Main->relations is always assumed valid,
|
|
|
|
|
* it's responsibility of code creating it to free it,
|
|
|
|
|
* especially if/when it starts modifying Main database). */
|
2023-07-17 10:46:26 +02:00
|
|
|
MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
|
|
|
|
|
BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
|
|
|
|
|
for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
|
2021-01-21 14:52:40 +01:00
|
|
|
to_id_entry = to_id_entry->next)
|
|
|
|
|
{
|
|
|
|
|
BKE_lib_query_foreachid_process(
|
|
|
|
|
&data, to_id_entry->id_pointer.to, to_id_entry->usage_flag);
|
2021-10-27 12:04:36 +02:00
|
|
|
if (BKE_lib_query_foreachid_iter_stop(&data)) {
|
|
|
|
|
library_foreach_ID_data_cleanup(&data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-01-30 21:41:44 +01:00
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-02-06 17:31:01 +01:00
|
|
|
if (flag & IDWALK_DO_LIBRARY_POINTER) {
|
|
|
|
|
CALLBACK_INVOKE(id->lib, IDWALK_CB_NEVER_SELF);
|
|
|
|
|
}
|
2020-02-14 11:09:40 +01:00
|
|
|
|
2021-03-12 09:39:23 +01:00
|
|
|
if (flag & IDWALK_DO_INTERNAL_RUNTIME_POINTERS) {
|
|
|
|
|
CALLBACK_INVOKE_ID(id->newid, IDWALK_CB_INTERNAL);
|
|
|
|
|
CALLBACK_INVOKE_ID(id->orig_id, IDWALK_CB_INTERNAL);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (id->override_library != nullptr) {
|
2019-06-14 23:16:04 +02:00
|
|
|
CALLBACK_INVOKE_ID(id->override_library->reference,
|
|
|
|
|
IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
|
|
|
|
|
CALLBACK_INVOKE_ID(id->override_library->storage,
|
|
|
|
|
IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
|
2022-01-12 10:43:42 +01:00
|
|
|
|
|
|
|
|
CALLBACK_INVOKE_ID(id->override_library->hierarchy_root, IDWALK_CB_LOOPBACK);
|
LibOverride: Add ID pointer to operations over ID pointers.
In RNA collections storing ID references, the name of the collection
item may not always be unique, when several IDs from different libraries
are present.
While rare, this situation can become deadly to liboverride, by causing
random but exponential liboverride hierarchies corruptions.
This has already been alleviated by using preferably both name and index
in items lookup (a05419f18b) and by reducing the risk of name collision
in general between liboverrides and their linked reference (b9becc47de).
This commit goes further, by ensuring that references to items of RNA
collections of IDs stored in liboverride operations become completely
unambiguous. This is achieved by storing an extra pointer to the item's
ID itself, when relevant.
Lookup then requires a complete match `name + ID` to be successful,
which is guaranteed to match at most a single item in the whole RNA
collection (since RNA collection of IDs do not allow duplicates, and
the ID pointer is always unique).
Note that this ID pointer is implemented as an `std::optional` one
(either directly in C++ code, or using an new liboverride operation `flag`
in DNA). This allows to smoothly transition from existing data to the
added ID pointer info (when needed), without needing any dedicated
versioning. This solution also preserves forward compatibility as much
as possible.
It may also provide marginal performances improvements in some cases, as
looking up for ID items in RNA collections will first check for the
ID pointer, which should be faster than a string comparision.
Implements #110421.
Pull Request: https://projects.blender.org/blender/blender/pulls/110773
2023-08-03 20:32:36 +02:00
|
|
|
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
|
|
|
|
|
LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
|
|
|
|
|
CALLBACK_INVOKE_ID(opop->subitem_reference_id,
|
|
|
|
|
IDWALK_CB_DIRECT_WEAK_LINK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
|
|
|
|
|
CALLBACK_INVOKE_ID(opop->subitem_local_id,
|
|
|
|
|
IDWALK_CB_DIRECT_WEAK_LINK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-18 20:17:44 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-05-07 12:36:35 +02:00
|
|
|
IDP_foreach_property(id->properties,
|
|
|
|
|
IDP_TYPE_FILTER_ID,
|
|
|
|
|
BKE_lib_query_idpropertiesForeachIDLink_callback,
|
|
|
|
|
&data);
|
2021-10-27 12:04:36 +02:00
|
|
|
if (BKE_lib_query_foreachid_iter_stop(&data)) {
|
|
|
|
|
library_foreach_ID_data_cleanup(&data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-24 12:28:41 +01:00
|
|
|
AnimData *adt = BKE_animdata_from_id(id);
|
|
|
|
|
if (adt) {
|
2020-05-26 11:53:00 +02:00
|
|
|
BKE_animdata_foreach_id(adt, &data);
|
2021-10-27 12:04:36 +02:00
|
|
|
if (BKE_lib_query_foreachid_iter_stop(&data)) {
|
|
|
|
|
library_foreach_ID_data_cleanup(&data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-03-24 12:28:41 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-05-07 12:36:35 +02:00
|
|
|
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
|
2023-07-17 10:46:26 +02:00
|
|
|
if (id_type->foreach_id != nullptr) {
|
2020-05-07 12:36:35 +02:00
|
|
|
id_type->foreach_id(id, &data);
|
|
|
|
|
|
2021-10-27 12:04:36 +02:00
|
|
|
if (BKE_lib_query_foreachid_iter_stop(&data)) {
|
|
|
|
|
library_foreach_ID_data_cleanup(&data);
|
|
|
|
|
return false;
|
2020-05-07 12:36:35 +02:00
|
|
|
}
|
2014-05-03 18:51:53 +09:00
|
|
|
}
|
2017-01-30 21:41:44 +01:00
|
|
|
}
|
2016-03-24 12:28:41 +01:00
|
|
|
|
2021-10-27 12:04:36 +02:00
|
|
|
library_foreach_ID_data_cleanup(&data);
|
|
|
|
|
return true;
|
2014-03-26 16:55:20 +06:00
|
|
|
|
2014-03-31 05:44:32 +11:00
|
|
|
#undef CALLBACK_INVOKE_ID
|
|
|
|
|
#undef CALLBACK_INVOKE
|
2014-03-26 16:55:20 +06:00
|
|
|
}
|
|
|
|
|
|
2019-03-04 16:14:36 +01:00
|
|
|
void BKE_library_foreach_ID_link(
|
|
|
|
|
Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
library_foreach_ID_link(bmain, nullptr, id, callback, user_data, flag, nullptr);
|
2019-03-04 16:14:36 +01:00
|
|
|
}
|
|
|
|
|
|
2017-01-31 10:41:25 +01:00
|
|
|
void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
|
2015-10-08 20:29:49 +11:00
|
|
|
{
|
2017-01-31 10:41:25 +01:00
|
|
|
if (cb_flag & IDWALK_CB_USER) {
|
2015-10-08 20:29:49 +11:00
|
|
|
id_us_min(id_src);
|
|
|
|
|
id_us_plus(id_dst);
|
|
|
|
|
}
|
2017-01-31 10:41:25 +01:00
|
|
|
else if (cb_flag & IDWALK_CB_USER_ONE) {
|
2015-11-09 21:15:11 +01:00
|
|
|
id_us_ensure_real(id_dst);
|
2015-10-08 20:29:49 +11:00
|
|
|
}
|
2015-10-08 14:38:48 +02:00
|
|
|
}
|
2016-01-06 19:34:42 +01:00
|
|
|
|
2024-02-19 15:54:48 +01:00
|
|
|
uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include_ui)
|
2016-07-07 20:51:21 +02:00
|
|
|
{
|
Datablock ID Properties
The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the [[http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.67/Python_Nodes|Python Nodes release notes]]. So this patch allows Python scripts to create ID Properties which reference datablocks.
This functionality is implemented for `PointerProperty` and now such properties can be created with Python.
In addition to the standard update callback, `PointerProperty` can have a `poll` callback (standard RNA) which is useful for search menus. For details see the test included in this patch.
Original author: @artfunkel
Alexander (Blend4Web Team)
Reviewers: brecht, artfunkel, mont29, campbellbarton
Reviewed By: mont29, campbellbarton
Subscribers: jta, sergey, campbellbarton, wisaac, poseidon4o, mont29, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov, fjuhec, sharlybg, cardboard, duarteframos, blueprintrandom, a.romanov, BYOB, disnel, aditiapratama, bliblubli, dfelinto, lukastoenne
Maniphest Tasks: T37754
Differential Revision: https://developer.blender.org/D113
2017-04-13 12:30:03 +03:00
|
|
|
/* any type of ID can be used in custom props. */
|
2023-05-16 18:14:43 +02:00
|
|
|
if (owner_id->properties) {
|
2022-02-11 08:23:52 +01:00
|
|
|
return FILTER_ID_ALL;
|
Datablock ID Properties
The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the [[http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.67/Python_Nodes|Python Nodes release notes]]. So this patch allows Python scripts to create ID Properties which reference datablocks.
This functionality is implemented for `PointerProperty` and now such properties can be created with Python.
In addition to the standard update callback, `PointerProperty` can have a `poll` callback (standard RNA) which is useful for search menus. For details see the test included in this patch.
Original author: @artfunkel
Alexander (Blend4Web Team)
Reviewers: brecht, artfunkel, mont29, campbellbarton
Reviewed By: mont29, campbellbarton
Subscribers: jta, sergey, campbellbarton, wisaac, poseidon4o, mont29, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov, fjuhec, sharlybg, cardboard, duarteframos, blueprintrandom, a.romanov, BYOB, disnel, aditiapratama, bliblubli, dfelinto, lukastoenne
Maniphest Tasks: T37754
Differential Revision: https://developer.blender.org/D113
2017-04-13 12:30:03 +03:00
|
|
|
}
|
2024-02-19 15:54:48 +01:00
|
|
|
const short id_type_owner = GS(owner_id->name);
|
|
|
|
|
|
|
|
|
|
/* IDProps of armature bones and nodes, and bNode->id can use virtually any type of ID. */
|
|
|
|
|
if (ELEM(id_type_owner, ID_NT, ID_AR)) {
|
|
|
|
|
return FILTER_ID_ALL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Screen UI IDs can also link to virtually any ID (through e.g. the Outliner). */
|
|
|
|
|
if (include_ui && id_type_owner == ID_SCR) {
|
2023-05-10 16:05:56 +02:00
|
|
|
return FILTER_ID_ALL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 10:28:59 +01:00
|
|
|
/* Casting to non const.
|
|
|
|
|
* TODO(jbakker): We should introduce a ntree_id_has_tree function as we are actually not
|
|
|
|
|
* interested in the result. */
|
2024-02-19 15:54:48 +01:00
|
|
|
if (ntreeFromID((ID *)owner_id)) {
|
2022-02-11 08:23:52 +01:00
|
|
|
return FILTER_ID_ALL;
|
Datablock ID Properties
The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the [[http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.67/Python_Nodes|Python Nodes release notes]]. So this patch allows Python scripts to create ID Properties which reference datablocks.
This functionality is implemented for `PointerProperty` and now such properties can be created with Python.
In addition to the standard update callback, `PointerProperty` can have a `poll` callback (standard RNA) which is useful for search menus. For details see the test included in this patch.
Original author: @artfunkel
Alexander (Blend4Web Team)
Reviewers: brecht, artfunkel, mont29, campbellbarton
Reviewed By: mont29, campbellbarton
Subscribers: jta, sergey, campbellbarton, wisaac, poseidon4o, mont29, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov, fjuhec, sharlybg, cardboard, duarteframos, blueprintrandom, a.romanov, BYOB, disnel, aditiapratama, bliblubli, dfelinto, lukastoenne
Maniphest Tasks: T37754
Differential Revision: https://developer.blender.org/D113
2017-04-13 12:30:03 +03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-05-16 18:14:43 +02:00
|
|
|
if (BKE_animdata_from_id(owner_id)) {
|
2019-06-12 09:04:10 +10:00
|
|
|
/* AnimationData can use virtually any kind of data-blocks, through drivers especially. */
|
2022-02-11 08:23:52 +01:00
|
|
|
return FILTER_ID_ALL;
|
2016-07-07 20:51:21 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-05-16 18:14:43 +02:00
|
|
|
if (ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) {
|
2023-05-12 16:58:47 +02:00
|
|
|
/* LibOverride data 'hierarchy root' can virtually point back to any type of ID. */
|
|
|
|
|
return FILTER_ID_ALL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-19 15:54:48 +01:00
|
|
|
switch ((ID_Type)id_type_owner) {
|
|
|
|
|
case ID_LI:
|
|
|
|
|
return FILTER_ID_LI;
|
|
|
|
|
case ID_SCE:
|
|
|
|
|
return FILTER_ID_OB | FILTER_ID_WO | FILTER_ID_SCE | FILTER_ID_MC | FILTER_ID_MA |
|
|
|
|
|
FILTER_ID_GR | FILTER_ID_TXT | FILTER_ID_LS | FILTER_ID_MSK | FILTER_ID_SO |
|
|
|
|
|
FILTER_ID_GD_LEGACY | FILTER_ID_BR | FILTER_ID_PAL | FILTER_ID_IM | FILTER_ID_NT;
|
|
|
|
|
case ID_OB:
|
|
|
|
|
/* Could be more specific, but simpler to just always say 'yes' here. */
|
|
|
|
|
return FILTER_ID_ALL;
|
|
|
|
|
case ID_ME:
|
|
|
|
|
return FILTER_ID_ME | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_KE;
|
|
|
|
|
case ID_CU_LEGACY:
|
|
|
|
|
return FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_VF | FILTER_ID_KE;
|
|
|
|
|
case ID_MB:
|
|
|
|
|
return FILTER_ID_MA;
|
|
|
|
|
case ID_MA:
|
|
|
|
|
return FILTER_ID_TE | FILTER_ID_GR;
|
|
|
|
|
case ID_TE:
|
|
|
|
|
return FILTER_ID_IM | FILTER_ID_OB;
|
|
|
|
|
case ID_LT:
|
|
|
|
|
return FILTER_ID_KE;
|
|
|
|
|
case ID_LA:
|
|
|
|
|
return FILTER_ID_TE;
|
|
|
|
|
case ID_CA:
|
|
|
|
|
return FILTER_ID_OB | FILTER_ID_IM;
|
|
|
|
|
case ID_KE:
|
|
|
|
|
/* Warning! key->from, could be more types in future? */
|
|
|
|
|
return FILTER_ID_ME | FILTER_ID_CU_LEGACY | FILTER_ID_LT;
|
|
|
|
|
case ID_SCR:
|
|
|
|
|
return FILTER_ID_SCE;
|
|
|
|
|
case ID_WO:
|
|
|
|
|
return FILTER_ID_TE;
|
|
|
|
|
case ID_SPK:
|
|
|
|
|
return FILTER_ID_SO;
|
|
|
|
|
case ID_GR:
|
|
|
|
|
return FILTER_ID_OB | FILTER_ID_GR;
|
|
|
|
|
case ID_NT:
|
|
|
|
|
/* Could be more specific, but node.id has no type restriction... */
|
|
|
|
|
return FILTER_ID_ALL;
|
|
|
|
|
case ID_BR:
|
|
|
|
|
return FILTER_ID_BR | FILTER_ID_IM | FILTER_ID_PC | FILTER_ID_TE | FILTER_ID_MA;
|
|
|
|
|
case ID_PA:
|
|
|
|
|
return FILTER_ID_OB | FILTER_ID_GR | FILTER_ID_TE;
|
|
|
|
|
case ID_MC:
|
|
|
|
|
return FILTER_ID_GD_LEGACY | FILTER_ID_IM;
|
|
|
|
|
case ID_MSK:
|
|
|
|
|
/* WARNING! mask->parent.id, not typed. */
|
|
|
|
|
return FILTER_ID_MC;
|
|
|
|
|
case ID_LS:
|
|
|
|
|
return FILTER_ID_TE | FILTER_ID_OB;
|
|
|
|
|
case ID_LP:
|
|
|
|
|
return FILTER_ID_IM;
|
|
|
|
|
case ID_GD_LEGACY:
|
|
|
|
|
return FILTER_ID_MA;
|
|
|
|
|
case ID_GP:
|
|
|
|
|
return FILTER_ID_GP | FILTER_ID_MA;
|
|
|
|
|
case ID_WS:
|
|
|
|
|
return FILTER_ID_SCE;
|
|
|
|
|
case ID_CV:
|
|
|
|
|
return FILTER_ID_MA | FILTER_ID_OB;
|
|
|
|
|
case ID_PT:
|
|
|
|
|
return FILTER_ID_MA;
|
|
|
|
|
case ID_VO:
|
|
|
|
|
return FILTER_ID_MA;
|
|
|
|
|
case ID_WM:
|
|
|
|
|
return FILTER_ID_SCE | FILTER_ID_WS;
|
|
|
|
|
case ID_IM:
|
|
|
|
|
case ID_VF:
|
|
|
|
|
case ID_TXT:
|
|
|
|
|
case ID_SO:
|
|
|
|
|
case ID_AR:
|
|
|
|
|
case ID_AC:
|
|
|
|
|
case ID_PAL:
|
|
|
|
|
case ID_PC:
|
|
|
|
|
case ID_CF:
|
|
|
|
|
/* Those types never use/reference other IDs... */
|
|
|
|
|
return 0;
|
|
|
|
|
case ID_IP:
|
|
|
|
|
/* Deprecated... */
|
|
|
|
|
return 0;
|
2022-02-11 08:23:52 +01:00
|
|
|
}
|
2024-02-19 15:54:48 +01:00
|
|
|
|
2022-07-13 16:10:03 +02:00
|
|
|
BLI_assert_unreachable();
|
2022-02-11 08:23:52 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-16 18:14:43 +02:00
|
|
|
bool BKE_library_id_can_use_idtype(ID *owner_id, const short id_type_used)
|
2022-02-11 08:23:52 +01:00
|
|
|
{
|
2024-02-19 15:54:48 +01:00
|
|
|
/* any type of ID can be used in custom props. */
|
|
|
|
|
if (owner_id->properties) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const short id_type_owner = GS(owner_id->name);
|
|
|
|
|
/* Exception for ID_LI as they don't exist as a filter. */
|
|
|
|
|
if (id_type_used == ID_LI) {
|
|
|
|
|
return id_type_owner == ID_LI;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Exception: ID_KE aren't available as filter_id. */
|
|
|
|
|
if (id_type_used == ID_KE) {
|
|
|
|
|
return ELEM(id_type_owner, ID_ME, ID_CU_LEGACY, ID_LT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Exception: ID_SCR aren't available as filter_id. */
|
|
|
|
|
if (id_type_used == ID_SCR) {
|
|
|
|
|
return ELEM(id_type_owner, ID_WS);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 08:23:52 +01:00
|
|
|
const uint64_t filter_id_type_used = BKE_idtype_idcode_to_idfilter(id_type_used);
|
2024-02-19 15:54:48 +01:00
|
|
|
const uint64_t can_be_used = BKE_library_id_can_use_filter_id(owner_id, false);
|
2022-02-11 08:23:52 +01:00
|
|
|
return (can_be_used & filter_id_type_used) != 0;
|
2016-07-07 20:51:21 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-06 19:34:42 +01:00
|
|
|
/* ***** ID users iterator. ***** */
|
2023-07-17 10:46:26 +02:00
|
|
|
struct IDUsersIter {
|
2016-01-06 19:34:42 +01:00
|
|
|
ID *id;
|
|
|
|
|
|
2021-03-04 18:39:07 +01:00
|
|
|
ListBase *lb_array[INDEX_ID_MAX];
|
2016-01-06 19:34:42 +01:00
|
|
|
int lb_idx;
|
|
|
|
|
|
|
|
|
|
ID *curr_id;
|
2016-07-08 19:33:22 +02:00
|
|
|
int count_direct, count_indirect; /* Set by callback. */
|
2023-07-17 10:46:26 +02:00
|
|
|
};
|
2016-01-06 19:34:42 +01:00
|
|
|
|
2020-02-13 12:56:10 +01:00
|
|
|
static int foreach_libblock_id_users_callback(LibraryIDLinkCallbackData *cb_data)
|
2016-01-06 19:34:42 +01:00
|
|
|
{
|
2020-02-13 12:56:10 +01:00
|
|
|
ID **id_p = cb_data->id_pointer;
|
|
|
|
|
const int cb_flag = cb_data->cb_flag;
|
2023-07-17 10:46:26 +02:00
|
|
|
IDUsersIter *iter = static_cast<IDUsersIter *>(cb_data->user_data);
|
2016-01-06 19:34:42 +01:00
|
|
|
|
2016-10-19 14:29:43 +02:00
|
|
|
if (*id_p) {
|
2022-02-03 17:57:40 +01:00
|
|
|
/* 'Loopback' ID pointers (the ugly 'from' ones, like Key->from).
|
2017-05-05 16:13:01 +02:00
|
|
|
* Those are not actually ID usage, we can ignore them here.
|
2016-10-19 14:29:43 +02:00
|
|
|
*/
|
2017-05-05 16:13:01 +02:00
|
|
|
if (cb_flag & IDWALK_CB_LOOPBACK) {
|
2016-10-19 14:29:43 +02:00
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
Fix T48971: Append creates linked image textures if object has shape keys.
Hating all those not-so-real ID types... Here there were two causes for the issue:
1) Linked shapekey ID was made local twice (once from mesh's make local, once by itself).
Solved by not explicitely making shapekeys (nor any other non-linkable datatype) local.
2) Key->from 'back pointer' to its owner was messing 'still in used' detection of linked data
after localization. Fixed with a hack for now, thinking correct solution might actually
be to not consider this pointer at all in libquery ID looper, since it's nothing like
and actual usage of mesh/lattice/curve.
Again, shapekeys as ID is a joke, those should be mere struct, they have absolutely nothing to do in Main, period. :(
Point 2) still demonstrates the need for better handling of IDs dependencies though,
so far we only hit corner cases, but think there could also be valid cases generating those
'dependency cycles' between IDs (ID a using ID b which uses ID a), this will have to be addressed some day...
2016-07-29 17:00:29 +02:00
|
|
|
|
2016-10-19 14:29:43 +02:00
|
|
|
if (*id_p == iter->id) {
|
ID-Remap - Step one: core work (cleanup and rework of generic ID datablock handling).
This commit changes a lot of how IDs are handled internally, especially the unlinking/freeing
processes. So far, this was very fuzy, to summarize cleanly deleting or replacing a datablock
was pretty much impossible, except for a few special cases.
Also, unlinking was handled by each datatype, in a rather messy and prone-to-errors way (quite
a few ID usages were missed or wrongly handled that way).
One of the main goal of id-remap branch was to cleanup this, and fatorize ID links handling
by using library_query utils to allow generic handling of those, which is now the case
(now, generic ID links handling is only "knwon" from readfile.c and library_query.c).
This commit also adds backends to allow live replacement and deletion of datablocks in Blender
(so-called 'remapping' process, where we replace all usages of a given ID pointer by a new one,
or NULL one in case of unlinking).
This will allow nice new features, like ability to easily reload or relocate libraries, real immediate
deletion of datablocks in blender, replacement of one datablock by another, etc.
Some of those are for next commits.
A word of warning: this commit is highly risky, because it affects potentially a lot in Blender core.
Though it was tested rather deeply, being totally impossible to check all possible ID usage cases,
it's likely there are some remaining issues and bugs in new code... Please report them! ;)
Review task: D2027 (https://developer.blender.org/D2027).
Reviewed by campbellbarton, thanks a bunch.
2016-06-22 17:29:38 +02:00
|
|
|
#if 0
|
2019-04-17 08:24:14 +02:00
|
|
|
printf(
|
|
|
|
|
"%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, "
|
|
|
|
|
"indirect_usage: %d)\n",
|
|
|
|
|
iter->curr_id->name,
|
|
|
|
|
iter->id->name,
|
|
|
|
|
(cb_flag & IDWALK_USER) ? 1 : 0,
|
|
|
|
|
(cb_flag & IDWALK_USER_ONE) ? 1 : 0,
|
|
|
|
|
(iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0,
|
|
|
|
|
(iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
|
|
|
|
|
(cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
|
ID-Remap - Step one: core work (cleanup and rework of generic ID datablock handling).
This commit changes a lot of how IDs are handled internally, especially the unlinking/freeing
processes. So far, this was very fuzy, to summarize cleanly deleting or replacing a datablock
was pretty much impossible, except for a few special cases.
Also, unlinking was handled by each datatype, in a rather messy and prone-to-errors way (quite
a few ID usages were missed or wrongly handled that way).
One of the main goal of id-remap branch was to cleanup this, and fatorize ID links handling
by using library_query utils to allow generic handling of those, which is now the case
(now, generic ID links handling is only "knwon" from readfile.c and library_query.c).
This commit also adds backends to allow live replacement and deletion of datablocks in Blender
(so-called 'remapping' process, where we replace all usages of a given ID pointer by a new one,
or NULL one in case of unlinking).
This will allow nice new features, like ability to easily reload or relocate libraries, real immediate
deletion of datablocks in blender, replacement of one datablock by another, etc.
Some of those are for next commits.
A word of warning: this commit is highly risky, because it affects potentially a lot in Blender core.
Though it was tested rather deeply, being totally impossible to check all possible ID usage cases,
it's likely there are some remaining issues and bugs in new code... Please report them! ;)
Review task: D2027 (https://developer.blender.org/D2027).
Reviewed by campbellbarton, thanks a bunch.
2016-06-22 17:29:38 +02:00
|
|
|
#endif
|
2017-01-31 09:47:59 +01:00
|
|
|
if (cb_flag & IDWALK_CB_INDIRECT_USAGE) {
|
2016-10-19 14:29:43 +02:00
|
|
|
iter->count_indirect++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
iter->count_direct++;
|
|
|
|
|
}
|
2016-07-08 19:33:22 +02:00
|
|
|
}
|
2016-01-06 19:34:42 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-24 12:28:41 +01:00
|
|
|
return IDWALK_RET_NOP;
|
2016-01-06 19:34:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
|
|
|
|
|
{
|
|
|
|
|
IDUsersIter iter;
|
|
|
|
|
|
|
|
|
|
/* We do not care about iter.lb_array/lb_idx here... */
|
|
|
|
|
iter.id = id_used;
|
|
|
|
|
iter.curr_id = id_user;
|
2016-07-08 19:33:22 +02:00
|
|
|
iter.count_direct = iter.count_indirect = 0;
|
2016-01-06 19:34:42 +01:00
|
|
|
|
2017-01-30 21:41:44 +01:00
|
|
|
BKE_library_foreach_ID_link(
|
2023-07-17 10:46:26 +02:00
|
|
|
nullptr, iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_READONLY);
|
2016-01-06 19:34:42 +01:00
|
|
|
|
2016-07-08 19:33:22 +02:00
|
|
|
return iter.count_direct + iter.count_indirect;
|
"Fix" crash when deleting linked object which has indirect usages.
This is in fact very hairy situation here... Objects are only refcounted by scenes,
any other usage is 'free', which means once all object instanciations are gone Blender
considers it can delete it.
There is a trap here though: indirect usages. Typically, we should never modify linked data
(because it is essencially useless, changes would be ignored and ost on next reload or
even undo/redo). This means indirect usages are not affected by default 'safe' remapping/unlinking.
For unlinking preceeding deletion however, this is not acceptable - we are likely to end with
a zero-user ID (aka deletable one) which is still actually used by other linked data.
Solution choosen here is double:
I) From 'user-space' (i.e. outliner, operators...), we check for cases where deleting datablocks
should not be allowed (indirect data or indirectly used data), and abort (with report) if needed.
II) From 'lower' level (BKE_library_remap and RNA), we also unlink from linked data,
which makes actual deletion possible and safe.
Note that with previous behavior (2.77 one), linked object would be deleted, including from linked data -
but then, once file is saved and reloaded, indirect usage would link back the deleted object,
without any instanciation in scene, which made it somehow virtual and unreachable...
With new behavior, this is no more possible, but on the other hand it means that in situations of dependency cycles
(two linked objects using each other), linked objects become impossible to delete (from user space).
Not sure what's best here, behavior with those corner cases of library linking is very poorly defined... :(
2016-07-01 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-07 19:39:14 +02:00
|
|
|
static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
|
"Fix" crash when deleting linked object which has indirect usages.
This is in fact very hairy situation here... Objects are only refcounted by scenes,
any other usage is 'free', which means once all object instanciations are gone Blender
considers it can delete it.
There is a trap here though: indirect usages. Typically, we should never modify linked data
(because it is essencially useless, changes would be ignored and ost on next reload or
even undo/redo). This means indirect usages are not affected by default 'safe' remapping/unlinking.
For unlinking preceeding deletion however, this is not acceptable - we are likely to end with
a zero-user ID (aka deletable one) which is still actually used by other linked data.
Solution choosen here is double:
I) From 'user-space' (i.e. outliner, operators...), we check for cases where deleting datablocks
should not be allowed (indirect data or indirectly used data), and abort (with report) if needed.
II) From 'lower' level (BKE_library_remap and RNA), we also unlink from linked data,
which makes actual deletion possible and safe.
Note that with previous behavior (2.77 one), linked object would be deleted, including from linked data -
but then, once file is saved and reloaded, indirect usage would link back the deleted object,
without any instanciation in scene, which made it somehow virtual and unreachable...
With new behavior, this is no more possible, but on the other hand it means that in situations of dependency cycles
(two linked objects using each other), linked objects become impossible to delete (from user space).
Not sure what's best here, behavior with those corner cases of library linking is very poorly defined... :(
2016-07-01 17:51:08 +02:00
|
|
|
{
|
|
|
|
|
IDUsersIter iter;
|
2021-03-04 18:39:07 +01:00
|
|
|
ListBase *lb_array[INDEX_ID_MAX];
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(idv);
|
"Fix" crash when deleting linked object which has indirect usages.
This is in fact very hairy situation here... Objects are only refcounted by scenes,
any other usage is 'free', which means once all object instanciations are gone Blender
considers it can delete it.
There is a trap here though: indirect usages. Typically, we should never modify linked data
(because it is essencially useless, changes would be ignored and ost on next reload or
even undo/redo). This means indirect usages are not affected by default 'safe' remapping/unlinking.
For unlinking preceeding deletion however, this is not acceptable - we are likely to end with
a zero-user ID (aka deletable one) which is still actually used by other linked data.
Solution choosen here is double:
I) From 'user-space' (i.e. outliner, operators...), we check for cases where deleting datablocks
should not be allowed (indirect data or indirectly used data), and abort (with report) if needed.
II) From 'lower' level (BKE_library_remap and RNA), we also unlink from linked data,
which makes actual deletion possible and safe.
Note that with previous behavior (2.77 one), linked object would be deleted, including from linked data -
but then, once file is saved and reloaded, indirect usage would link back the deleted object,
without any instanciation in scene, which made it somehow virtual and unreachable...
With new behavior, this is no more possible, but on the other hand it means that in situations of dependency cycles
(two linked objects using each other), linked objects become impossible to delete (from user space).
Not sure what's best here, behavior with those corner cases of library linking is very poorly defined... :(
2016-07-01 17:51:08 +02:00
|
|
|
int i = set_listbasepointers(bmain, lb_array);
|
2016-07-07 19:39:14 +02:00
|
|
|
bool is_defined = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-07-07 21:18:04 +02:00
|
|
|
iter.id = id;
|
2016-07-08 19:33:22 +02:00
|
|
|
iter.count_direct = iter.count_indirect = 0;
|
2016-07-07 19:39:14 +02:00
|
|
|
while (i-- && !is_defined) {
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id_curr = static_cast<ID *>(lb_array[i]->first);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Datablock ID Properties
The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the [[http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.67/Python_Nodes|Python Nodes release notes]]. So this patch allows Python scripts to create ID Properties which reference datablocks.
This functionality is implemented for `PointerProperty` and now such properties can be created with Python.
In addition to the standard update callback, `PointerProperty` can have a `poll` callback (standard RNA) which is useful for search menus. For details see the test included in this patch.
Original author: @artfunkel
Alexander (Blend4Web Team)
Reviewers: brecht, artfunkel, mont29, campbellbarton
Reviewed By: mont29, campbellbarton
Subscribers: jta, sergey, campbellbarton, wisaac, poseidon4o, mont29, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov, fjuhec, sharlybg, cardboard, duarteframos, blueprintrandom, a.romanov, BYOB, disnel, aditiapratama, bliblubli, dfelinto, lukastoenne
Maniphest Tasks: T37754
Differential Revision: https://developer.blender.org/D113
2017-04-13 12:30:03 +03:00
|
|
|
if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
|
2016-07-07 21:18:04 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
for (; id_curr && !is_defined; id_curr = static_cast<ID *>(id_curr->next)) {
|
2016-07-26 15:12:43 +02:00
|
|
|
if (id_curr == id) {
|
|
|
|
|
/* We are not interested in self-usages (mostly from drivers or bone constraints...). */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
"Fix" crash when deleting linked object which has indirect usages.
This is in fact very hairy situation here... Objects are only refcounted by scenes,
any other usage is 'free', which means once all object instanciations are gone Blender
considers it can delete it.
There is a trap here though: indirect usages. Typically, we should never modify linked data
(because it is essencially useless, changes would be ignored and ost on next reload or
even undo/redo). This means indirect usages are not affected by default 'safe' remapping/unlinking.
For unlinking preceeding deletion however, this is not acceptable - we are likely to end with
a zero-user ID (aka deletable one) which is still actually used by other linked data.
Solution choosen here is double:
I) From 'user-space' (i.e. outliner, operators...), we check for cases where deleting datablocks
should not be allowed (indirect data or indirectly used data), and abort (with report) if needed.
II) From 'lower' level (BKE_library_remap and RNA), we also unlink from linked data,
which makes actual deletion possible and safe.
Note that with previous behavior (2.77 one), linked object would be deleted, including from linked data -
but then, once file is saved and reloaded, indirect usage would link back the deleted object,
without any instanciation in scene, which made it somehow virtual and unreachable...
With new behavior, this is no more possible, but on the other hand it means that in situations of dependency cycles
(two linked objects using each other), linked objects become impossible to delete (from user space).
Not sure what's best here, behavior with those corner cases of library linking is very poorly defined... :(
2016-07-01 17:51:08 +02:00
|
|
|
iter.curr_id = id_curr;
|
|
|
|
|
BKE_library_foreach_ID_link(
|
2017-01-30 21:41:44 +01:00
|
|
|
bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-07-08 19:33:22 +02:00
|
|
|
is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
|
"Fix" crash when deleting linked object which has indirect usages.
This is in fact very hairy situation here... Objects are only refcounted by scenes,
any other usage is 'free', which means once all object instanciations are gone Blender
considers it can delete it.
There is a trap here though: indirect usages. Typically, we should never modify linked data
(because it is essencially useless, changes would be ignored and ost on next reload or
even undo/redo). This means indirect usages are not affected by default 'safe' remapping/unlinking.
For unlinking preceeding deletion however, this is not acceptable - we are likely to end with
a zero-user ID (aka deletable one) which is still actually used by other linked data.
Solution choosen here is double:
I) From 'user-space' (i.e. outliner, operators...), we check for cases where deleting datablocks
should not be allowed (indirect data or indirectly used data), and abort (with report) if needed.
II) From 'lower' level (BKE_library_remap and RNA), we also unlink from linked data,
which makes actual deletion possible and safe.
Note that with previous behavior (2.77 one), linked object would be deleted, including from linked data -
but then, once file is saved and reloaded, indirect usage would link back the deleted object,
without any instanciation in scene, which made it somehow virtual and unreachable...
With new behavior, this is no more possible, but on the other hand it means that in situations of dependency cycles
(two linked objects using each other), linked objects become impossible to delete (from user space).
Not sure what's best here, behavior with those corner cases of library linking is very poorly defined... :(
2016-07-01 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-07-07 19:39:14 +02:00
|
|
|
return is_defined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
|
|
|
|
|
{
|
|
|
|
|
return library_ID_is_used(bmain, idv, false);
|
"Fix" crash when deleting linked object which has indirect usages.
This is in fact very hairy situation here... Objects are only refcounted by scenes,
any other usage is 'free', which means once all object instanciations are gone Blender
considers it can delete it.
There is a trap here though: indirect usages. Typically, we should never modify linked data
(because it is essencially useless, changes would be ignored and ost on next reload or
even undo/redo). This means indirect usages are not affected by default 'safe' remapping/unlinking.
For unlinking preceeding deletion however, this is not acceptable - we are likely to end with
a zero-user ID (aka deletable one) which is still actually used by other linked data.
Solution choosen here is double:
I) From 'user-space' (i.e. outliner, operators...), we check for cases where deleting datablocks
should not be allowed (indirect data or indirectly used data), and abort (with report) if needed.
II) From 'lower' level (BKE_library_remap and RNA), we also unlink from linked data,
which makes actual deletion possible and safe.
Note that with previous behavior (2.77 one), linked object would be deleted, including from linked data -
but then, once file is saved and reloaded, indirect usage would link back the deleted object,
without any instanciation in scene, which made it somehow virtual and unreachable...
With new behavior, this is no more possible, but on the other hand it means that in situations of dependency cycles
(two linked objects using each other), linked objects become impossible to delete (from user space).
Not sure what's best here, behavior with those corner cases of library linking is very poorly defined... :(
2016-07-01 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-07 19:39:14 +02:00
|
|
|
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
|
|
|
|
|
{
|
|
|
|
|
return library_ID_is_used(bmain, idv, true);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-30 10:42:18 +11:00
|
|
|
void BKE_library_ID_test_usages(Main *bmain,
|
|
|
|
|
void *idv,
|
|
|
|
|
bool *r_is_used_local,
|
|
|
|
|
bool *r_is_used_linked)
|
2016-07-07 19:39:14 +02:00
|
|
|
{
|
2016-07-08 19:33:22 +02:00
|
|
|
IDUsersIter iter;
|
2021-03-04 18:39:07 +01:00
|
|
|
ListBase *lb_array[INDEX_ID_MAX];
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(idv);
|
2016-07-07 19:39:14 +02:00
|
|
|
int i = set_listbasepointers(bmain, lb_array);
|
|
|
|
|
bool is_defined = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-07-08 19:33:22 +02:00
|
|
|
iter.id = id;
|
|
|
|
|
iter.count_direct = iter.count_indirect = 0;
|
2016-07-07 19:39:14 +02:00
|
|
|
while (i-- && !is_defined) {
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id_curr = static_cast<ID *>(lb_array[i]->first);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Datablock ID Properties
The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the [[http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.67/Python_Nodes|Python Nodes release notes]]. So this patch allows Python scripts to create ID Properties which reference datablocks.
This functionality is implemented for `PointerProperty` and now such properties can be created with Python.
In addition to the standard update callback, `PointerProperty` can have a `poll` callback (standard RNA) which is useful for search menus. For details see the test included in this patch.
Original author: @artfunkel
Alexander (Blend4Web Team)
Reviewers: brecht, artfunkel, mont29, campbellbarton
Reviewed By: mont29, campbellbarton
Subscribers: jta, sergey, campbellbarton, wisaac, poseidon4o, mont29, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov, fjuhec, sharlybg, cardboard, duarteframos, blueprintrandom, a.romanov, BYOB, disnel, aditiapratama, bliblubli, dfelinto, lukastoenne
Maniphest Tasks: T37754
Differential Revision: https://developer.blender.org/D113
2017-04-13 12:30:03 +03:00
|
|
|
if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
|
2016-07-07 21:18:04 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
for (; id_curr && !is_defined; id_curr = static_cast<ID *>(id_curr->next)) {
|
2016-07-26 15:12:43 +02:00
|
|
|
if (id_curr == id) {
|
|
|
|
|
/* We are not interested in self-usages (mostly from drivers or bone constraints...). */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2016-07-08 19:33:22 +02:00
|
|
|
iter.curr_id = id_curr;
|
2017-01-30 21:41:44 +01:00
|
|
|
BKE_library_foreach_ID_link(
|
|
|
|
|
bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-07-08 19:33:22 +02:00
|
|
|
is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
|
2016-07-07 19:39:14 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-11-30 10:42:18 +11:00
|
|
|
*r_is_used_local = (iter.count_direct != 0);
|
|
|
|
|
*r_is_used_linked = (iter.count_indirect != 0);
|
2016-07-07 19:39:14 +02:00
|
|
|
}
|
2016-10-19 14:29:43 +02:00
|
|
|
|
2016-11-11 22:29:54 +01:00
|
|
|
/* ***** IDs usages.checking/tagging. ***** */
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
|
|
|
|
|
/* Returns `true` if given ID is detected as part of at least one dependency loop, false otherwise.
|
|
|
|
|
*/
|
2024-02-19 15:54:48 +01:00
|
|
|
static bool lib_query_unused_ids_tag_recurse(Main *bmain,
|
|
|
|
|
const int tag,
|
|
|
|
|
const bool do_local_ids,
|
|
|
|
|
const bool do_linked_ids,
|
|
|
|
|
ID *id,
|
|
|
|
|
int *r_num_tagged)
|
2021-02-25 12:37:31 +01:00
|
|
|
{
|
|
|
|
|
/* We should never deal with embedded, not-in-main IDs here. */
|
|
|
|
|
BLI_assert((id->flag & LIB_EMBEDDED_DATA) == 0);
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
MainIDRelationsEntry *id_relations = static_cast<MainIDRelationsEntry *>(
|
2024-02-19 15:54:48 +01:00
|
|
|
BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
|
2021-02-25 12:37:31 +01:00
|
|
|
if ((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) != 0) {
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2024-01-19 12:08:40 -05:00
|
|
|
if ((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS) != 0) {
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
/* This ID has not yet been fully processed. If this condition is reached, it means this is a
|
|
|
|
|
* dependency loop case. */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-19 15:54:48 +01:00
|
|
|
if ((!do_linked_ids && ID_IS_LINKED(id)) || (!do_local_ids && !ID_IS_LINKED(id))) {
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
|
|
|
|
|
return false;
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
2024-02-19 15:54:48 +01:00
|
|
|
if ((id->tag & tag) != 0) {
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
|
|
|
|
|
return false;
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((id->flag & LIB_FAKEUSER) != 0) {
|
|
|
|
|
/* This ID is forcefully kept around, and therefore never unused, no need to check it further.
|
|
|
|
|
*/
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
|
|
|
|
|
return false;
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ELEM(GS(id->name), ID_WM, ID_WS, ID_SCE, ID_SCR, ID_LI)) {
|
|
|
|
|
/* Some 'root' ID types are never unused (even though they may not have actual users), unless
|
2021-03-01 11:00:22 +11:00
|
|
|
* their actual user-count is set to 0. */
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
|
|
|
|
|
return false;
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-11-16 14:51:44 +01:00
|
|
|
if (ELEM(GS(id->name), ID_IM)) {
|
|
|
|
|
/* Images which have a 'viewer' source (e.g. render results) should not be considered as
|
|
|
|
|
* orphaned/unused data. */
|
2023-07-07 16:00:50 +10:00
|
|
|
const Image *image = (Image *)id;
|
2022-11-16 14:51:44 +01:00
|
|
|
if (image->source == IMA_SRC_VIEWER) {
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
|
|
|
|
|
return false;
|
2022-11-16 14:51:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-25 12:37:31 +01:00
|
|
|
/* An ID user is 'valid' (i.e. may affect the 'used'/'not used' status of the ID it uses) if it
|
|
|
|
|
* does not match `ignored_usages`, and does match `required_usages`. */
|
2023-04-14 13:25:06 +02:00
|
|
|
const int ignored_usages = (IDWALK_CB_LOOPBACK | IDWALK_CB_EMBEDDED |
|
|
|
|
|
IDWALK_CB_EMBEDDED_NOT_OWNING);
|
2021-02-25 12:37:31 +01:00
|
|
|
const int required_usages = (IDWALK_CB_USER | IDWALK_CB_USER_ONE);
|
|
|
|
|
|
|
|
|
|
/* This ID may be tagged as unused if none of its users are 'valid', as defined above.
|
|
|
|
|
*
|
|
|
|
|
* First recursively check all its valid users, if all of them can be tagged as
|
|
|
|
|
* unused, then we can tag this ID as such too. */
|
|
|
|
|
bool has_valid_from_users = false;
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
bool is_part_of_dependency_loop = false;
|
|
|
|
|
id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS;
|
2023-07-17 10:46:26 +02:00
|
|
|
for (MainIDRelationsEntryItem *id_from_item = id_relations->from_ids; id_from_item != nullptr;
|
2021-02-25 12:37:31 +01:00
|
|
|
id_from_item = id_from_item->next)
|
|
|
|
|
{
|
|
|
|
|
if ((id_from_item->usage_flag & ignored_usages) != 0 ||
|
|
|
|
|
(id_from_item->usage_flag & required_usages) == 0)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ID *id_from = id_from_item->id_pointer.from;
|
|
|
|
|
if ((id_from->flag & LIB_EMBEDDED_DATA) != 0) {
|
|
|
|
|
/* Directly 'by-pass' to actual real ID owner. */
|
2022-09-08 13:06:40 +02:00
|
|
|
id_from = BKE_id_owner_get(id_from);
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(id_from != nullptr);
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
2024-02-19 15:54:48 +01:00
|
|
|
if (lib_query_unused_ids_tag_recurse(
|
|
|
|
|
bmain, tag, do_local_ids, do_linked_ids, id_from, r_num_tagged))
|
|
|
|
|
{
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
/* Dependency loop case, ignore the `id_from` tag value here (as it should not be considered
|
2023-09-14 13:25:24 +10:00
|
|
|
* as valid yet), and presume that this is a 'valid user' case for now. */
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
is_part_of_dependency_loop = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-02-19 15:54:48 +01:00
|
|
|
if ((id_from->tag & tag) == 0) {
|
2021-02-25 12:37:31 +01:00
|
|
|
has_valid_from_users = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
if (!has_valid_from_users && !is_part_of_dependency_loop) {
|
|
|
|
|
/* Tag the ID as unused, only in case it is not part of a dependency loop. */
|
2024-02-19 15:54:48 +01:00
|
|
|
id->tag |= tag;
|
|
|
|
|
if (r_num_tagged != nullptr) {
|
|
|
|
|
r_num_tagged[INDEX_ID_NULL]++;
|
|
|
|
|
r_num_tagged[BKE_idtype_idcode_to_index(GS(id->name))]++;
|
|
|
|
|
}
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
|
|
|
|
|
/* This ID is not being processed anymore.
|
|
|
|
|
*
|
2023-05-05 09:25:45 +10:00
|
|
|
* However, we can only tag is as successfully processed if either it was detected as part of a
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
* valid usage hierarchy, or, if detected as unused, if it was not part of a dependency loop.
|
|
|
|
|
*
|
|
|
|
|
* Otherwise, this is an undecided state, it will be resolved at the entry point of this
|
|
|
|
|
* recursive process for the root id (see below in #BKE_lib_query_unused_ids_tag calling code).
|
|
|
|
|
*/
|
|
|
|
|
id_relations->tags &= ~MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS;
|
|
|
|
|
if (has_valid_from_users || !is_part_of_dependency_loop) {
|
|
|
|
|
id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return is_part_of_dependency_loop;
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
2024-02-19 15:54:48 +01:00
|
|
|
void BKE_lib_query_unused_ids_tag(Main *bmain,
|
|
|
|
|
const int tag,
|
|
|
|
|
const bool do_local_ids,
|
|
|
|
|
const bool do_linked_ids,
|
|
|
|
|
const bool do_tag_recursive,
|
|
|
|
|
int *r_num_tagged)
|
2021-02-25 12:37:31 +01:00
|
|
|
{
|
2021-03-01 11:00:22 +11:00
|
|
|
/* First loop, to only check for immediately unused IDs (those with 0 user count).
|
2021-02-25 12:37:31 +01:00
|
|
|
* NOTE: It also takes care of clearing given tag for used IDs. */
|
|
|
|
|
ID *id;
|
2024-02-19 15:54:48 +01:00
|
|
|
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
|
|
|
|
if ((!do_linked_ids && ID_IS_LINKED(id)) || (!do_local_ids && !ID_IS_LINKED(id))) {
|
|
|
|
|
id->tag &= ~tag;
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
else if (id->us == 0) {
|
2024-02-19 15:54:48 +01:00
|
|
|
id->tag |= tag;
|
|
|
|
|
if (r_num_tagged != nullptr) {
|
|
|
|
|
r_num_tagged[INDEX_ID_NULL]++;
|
|
|
|
|
r_num_tagged[BKE_idtype_idcode_to_index(GS(id->name))]++;
|
|
|
|
|
}
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2024-02-19 15:54:48 +01:00
|
|
|
id->tag &= ~tag;
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FOREACH_MAIN_ID_END;
|
|
|
|
|
|
2024-02-19 15:54:48 +01:00
|
|
|
if (!do_tag_recursive) {
|
2021-02-25 12:37:31 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-19 15:54:48 +01:00
|
|
|
BKE_main_relations_create(bmain, 0);
|
|
|
|
|
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
|
|
|
|
if (lib_query_unused_ids_tag_recurse(
|
|
|
|
|
bmain, tag, do_local_ids, do_linked_ids, id, r_num_tagged))
|
|
|
|
|
{
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
/* This root processed ID is part of one or more dependency loops.
|
|
|
|
|
*
|
|
|
|
|
* If it was not tagged, and its matching relations entry is not marked as processed, it
|
|
|
|
|
* means that it's the first encountered entry point of an 'unused archipelago' (i.e. the
|
|
|
|
|
* entry point to a set of IDs with relationships to each other, but no 'valid usage'
|
|
|
|
|
* relations to the current Blender file (like being part of a scene, etc.).
|
|
|
|
|
*
|
|
|
|
|
* So the entry can be tagged as processed, and the ID tagged as unused. */
|
2024-02-19 15:54:48 +01:00
|
|
|
if ((id->tag & tag) == 0) {
|
2023-07-17 10:46:26 +02:00
|
|
|
MainIDRelationsEntry *id_relations = static_cast<MainIDRelationsEntry *>(
|
2024-02-19 15:54:48 +01:00
|
|
|
BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
if ((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) == 0) {
|
|
|
|
|
id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
|
2024-02-19 15:54:48 +01:00
|
|
|
id->tag |= tag;
|
|
|
|
|
if (r_num_tagged != nullptr) {
|
|
|
|
|
r_num_tagged[INDEX_ID_NULL]++;
|
|
|
|
|
r_num_tagged[BKE_idtype_idcode_to_index(GS(id->name))]++;
|
|
|
|
|
}
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
/* Relation entry for the root processed ID should always be marked as processed now. */
|
2023-07-17 10:46:26 +02:00
|
|
|
MainIDRelationsEntry *id_relations = static_cast<MainIDRelationsEntry *>(
|
2024-02-19 15:54:48 +01:00
|
|
|
BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
|
|
|
|
|
if ((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) == 0) {
|
|
|
|
|
BLI_assert((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) != 0);
|
|
|
|
|
}
|
Fix #107573: Purging orphan data deletes used data.
The logic in the initial commit (97dd107070) was broken in some cases,
and would end up tagging as unused IDs that had valid usages. It is
reverted by this commit..
For this new solution to #98029 (deleting unused archipelagos of data),
the logic handling dependency loops detection is reworked to rely on a
new tag in the relations entry of the relevant IDs, instead of
pre-tagging as unused the ID itself.
Further more, when a dependency loop is detected, the IDs in it cannot
be immediately tagged as unused, since it may be that the entry point
of that loop is later detected as actually used. So their relations
entries are not tagged as processed, and only the entry point of the
potential archipelago can be checked in that case, outside of the
recursive processing of dependencies.
The other IDs of the archipelago will then be processed again later, in
a state where at least one ID in the archipelago has a known state for
sure, which then allows for a safe evaluation of the other related data.
This commit should be backported to 3.3LTS.
2023-05-03 16:01:25 +02:00
|
|
|
BLI_assert((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS) == 0);
|
|
|
|
|
#endif
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
FOREACH_MAIN_ID_END;
|
2024-02-19 15:54:48 +01:00
|
|
|
BKE_main_relations_free(bmain);
|
2021-02-25 12:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
2020-02-13 12:56:10 +01:00
|
|
|
static int foreach_libblock_used_linked_data_tag_clear_cb(LibraryIDLinkCallbackData *cb_data)
|
2016-10-19 14:29:43 +02:00
|
|
|
{
|
2023-05-16 18:14:43 +02:00
|
|
|
ID *self_id = cb_data->self_id;
|
2020-02-13 12:56:10 +01:00
|
|
|
ID **id_p = cb_data->id_pointer;
|
|
|
|
|
const int cb_flag = cb_data->cb_flag;
|
2023-07-17 10:46:26 +02:00
|
|
|
bool *is_changed = static_cast<bool *>(cb_data->user_data);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-10-19 14:29:43 +02:00
|
|
|
if (*id_p) {
|
2022-02-03 17:57:40 +01:00
|
|
|
/* The infamous 'from' pointers (Key.from, ...).
|
2019-03-18 11:47:54 +01:00
|
|
|
* those are not actually ID usage, so we ignore them here. */
|
|
|
|
|
if (cb_flag & IDWALK_CB_LOOPBACK) {
|
2016-10-19 14:29:43 +02:00
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-27 12:07:07 +10:00
|
|
|
/* If checked id is used by an assumed used ID,
|
|
|
|
|
* then it is also used and not part of any linked archipelago. */
|
2016-10-19 14:29:43 +02:00
|
|
|
if (!(self_id->tag & LIB_TAG_DOIT) && ((*id_p)->tag & LIB_TAG_DOIT)) {
|
|
|
|
|
(*id_p)->tag &= ~LIB_TAG_DOIT;
|
|
|
|
|
*is_changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-10-19 14:29:43 +02:00
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-11 22:56:47 +01:00
|
|
|
void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
|
2016-10-19 14:29:43 +02:00
|
|
|
{
|
2019-02-14 16:24:49 +01:00
|
|
|
ID *id;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-10-19 14:29:43 +02:00
|
|
|
if (do_init_tag) {
|
2019-04-21 04:40:16 +10:00
|
|
|
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
2019-02-14 16:24:49 +01:00
|
|
|
if (id->lib && (id->tag & LIB_TAG_INDIRECT) != 0) {
|
|
|
|
|
id->tag |= LIB_TAG_DOIT;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
id->tag &= ~LIB_TAG_DOIT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FOREACH_MAIN_ID_END;
|
2016-10-19 14:29:43 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-07 21:52:54 +01:00
|
|
|
for (bool do_loop = true; do_loop;) {
|
2016-10-19 14:29:43 +02:00
|
|
|
do_loop = false;
|
2019-04-21 04:40:16 +10:00
|
|
|
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
2019-03-18 11:32:06 +01:00
|
|
|
/* We only want to check that ID if it is currently known as used... */
|
2019-02-14 16:24:49 +01:00
|
|
|
if ((id->tag & LIB_TAG_DOIT) == 0) {
|
|
|
|
|
BKE_library_foreach_ID_link(
|
|
|
|
|
bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-18 11:32:06 +01:00
|
|
|
FOREACH_MAIN_ID_END;
|
2016-11-11 22:29:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
|
|
|
|
|
{
|
2021-03-04 18:39:07 +01:00
|
|
|
ListBase *lb_array[INDEX_ID_MAX];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-11-11 22:29:54 +01:00
|
|
|
bool do_loop = true;
|
|
|
|
|
while (do_loop) {
|
|
|
|
|
int i = set_listbasepointers(bmain, lb_array);
|
|
|
|
|
do_loop = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-11-11 22:29:54 +01:00
|
|
|
while (i--) {
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (ID *, id, lb_array[i]) {
|
2021-08-26 15:01:14 +02:00
|
|
|
if (!ID_IS_LINKED(id) || id->tag & LIB_TAG_DOIT) {
|
2016-11-11 22:29:54 +01:00
|
|
|
/* Local or non-indirectly-used ID (so far), no need to check it further. */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-01-30 21:41:44 +01:00
|
|
|
BKE_library_foreach_ID_link(
|
|
|
|
|
bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
|
2016-10-19 14:29:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|