Blender V4.3
library.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <optional>
12
13/* all types are needed here, in order to do memory operations */
14#include "DNA_ID.h"
15
16#include "BLI_utildefines.h"
17
18#include "BLI_blenlib.h"
19#include "BLI_ghash.h"
20#include "BLI_set.hh"
21
22#include "BLT_translation.hh"
23
24#include "BKE_bpath.hh"
25#include "BKE_idtype.hh"
26#include "BKE_lib_query.hh"
27#include "BKE_library.hh"
28#include "BKE_main.hh"
29#include "BKE_main_namemap.hh"
30#include "BKE_packedFile.hh"
31
32struct BlendDataReader;
33
35{
36 if (lib->runtime.name_map) {
37 BKE_main_namemap_destroy(&lib->runtime.name_map);
38 }
39}
40
41static void library_free_data(ID *id)
42{
43 Library *library = (Library *)id;
44 library_runtime_reset(library);
45 if (library->packedfile) {
47 }
48}
49
50static void library_copy_data(Main *bmain,
51 std::optional<Library *> owner_library,
52 ID *id_dst,
53 const ID *id_src,
54 int /*flag*/)
55{
56 /* Libraries are always local IDs. */
57 BLI_assert(!owner_library || *owner_library == nullptr);
58 UNUSED_VARS_NDEBUG(bmain, owner_library);
59
60 const Library *library_src = reinterpret_cast<const Library *>(id_src);
61
62 /* Libraries are copyable now, but there should still be only one library ID for each linked
63 * blendfile (based on absolute filepath). */
64 BLI_assert(!bmain || BLI_findstring(&bmain->libraries,
65 library_src->runtime.filepath_abs,
66 offsetof(Library, runtime.filepath_abs)) == nullptr);
67
68 Library *library_dst = reinterpret_cast<Library *>(id_dst);
69 if (library_src->packedfile) {
70 library_dst->packedfile = BKE_packedfile_duplicate(library_src->packedfile);
71 }
72 library_dst->runtime.filedata = nullptr;
73 library_dst->runtime.name_map = nullptr;
74}
75
77{
78 Library *lib = (Library *)id;
80}
81
82static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data)
83{
84 Library *lib = (Library *)id;
85
86 /* FIXME: Find if we should respect #BKE_BPATH_FOREACH_PATH_SKIP_PACKED here, and if not, explain
87 * why. */
88 if (lib->packedfile !=
89 nullptr /*&& (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0 */)
90 {
91 return;
92 }
93
94 if (BKE_bpath_foreach_path_fixed_process(bpath_data, lib->filepath, sizeof(lib->filepath))) {
95 BKE_library_filepath_set(bpath_data->bmain, lib, lib->filepath);
96 }
97}
98
99static void library_blend_read_data(BlendDataReader * /*reader*/, ID *id)
100{
101 Library *lib = (Library *)id;
102 memset(&lib->runtime, 0, sizeof(lib->runtime));
103}
104
106 /*id_code*/ ID_LI,
107 /*id_filter*/ FILTER_ID_LI,
108 /*dependencies_id_types*/ FILTER_ID_LI,
109 /*main_listbase_index*/ INDEX_ID_LI,
110 /*struct_size*/ sizeof(Library),
111 /*name*/ "Library",
112 /*name_plural*/ N_("libraries"),
113 /*translation_context*/ BLT_I18NCONTEXT_ID_LIBRARY,
115 /*asset_type_info*/ nullptr,
116
117 /*init_data*/ nullptr,
118 /*copy_data*/ library_copy_data,
119 /*free_data*/ library_free_data,
120 /*make_local*/ nullptr,
121 /*foreach_id*/ library_foreach_id,
122 /*foreach_cache*/ nullptr,
123 /*foreach_path*/ library_foreach_path,
124 /*owner_pointer_get*/ nullptr,
125
126 /*blend_write*/ nullptr,
127 /*blend_read_data*/ library_blend_read_data,
128 /*blend_read_after_liblink*/ nullptr,
129
130 /*blend_read_undo_preserve*/ nullptr,
131
132 /*lib_override_apply_post*/ nullptr,
133};
134
135void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
136{
137 /* in some cases this is used to update the absolute path from the
138 * relative */
139 if (lib->filepath != filepath) {
140 STRNCPY(lib->filepath, filepath);
141 }
142
143 STRNCPY(lib->runtime.filepath_abs, filepath);
144
145 /* Not essential but set `filepath_abs` is an absolute copy of value which
146 * is more useful if its kept in sync. */
147 if (BLI_path_is_rel(lib->runtime.filepath_abs)) {
148 /* NOTE(@ideasman42): the file may be unsaved, in this case, setting the
149 * `filepath_abs` on an indirectly linked path is not allowed from the
150 * outliner, and its not really supported but allow from here for now
151 * since making local could cause this to be directly linked.
152 */
153 /* Never make paths relative to parent lib - reading code (blenloader) always set *all*
154 * `lib->filepath` relative to current main, not to their parent for indirectly linked ones. */
155 const char *blendfile_path = BKE_main_blendfile_path(bmain);
156 BLI_path_abs(lib->runtime.filepath_abs, blendfile_path);
157 }
158}
159
161 blender::Set<Library *> &directly_used_libs,
162 Library *lib)
163{
164 BLI_assert(!directly_used_libs.contains(lib));
165
166 Library *best_parent_lib = nullptr;
167 bool do_break = false;
168 ListBase *lb;
169 ID *id_iter;
170 FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
171 FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id_iter) {
172 if (!ID_IS_LINKED(id_iter) || id_iter->lib != lib) {
173 continue;
174 }
175 MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
177 for (MainIDRelationsEntryItem *item = entry->from_ids; item; item = item->next) {
178 ID *from_id = item->id_pointer.from;
179 if (!ID_IS_LINKED(from_id)) {
181 continue;
182 }
183 Library *from_id_lib = from_id->lib;
184 if (from_id_lib == lib) {
185 continue;
186 }
187 if (directly_used_libs.contains(from_id_lib)) {
188 /* Found the first best possible candidate, no need to search further. */
189 BLI_assert(best_parent_lib == nullptr || best_parent_lib->runtime.temp_index > 0);
190 best_parent_lib = from_id_lib;
191 do_break = true;
192 break;
193 }
194 if (!from_id_lib->runtime.parent) {
195 rebuild_hierarchy_best_parent_find(bmain, directly_used_libs, from_id_lib);
196 }
197 if (!best_parent_lib ||
198 best_parent_lib->runtime.temp_index > from_id_lib->runtime.temp_index)
199 {
200 best_parent_lib = from_id_lib;
201 if (best_parent_lib->runtime.temp_index == 0) {
202 /* Found the first best possible candidate, no need to search further. */
203 BLI_assert(directly_used_libs.contains(best_parent_lib));
204 do_break = true;
205 break;
206 }
207 }
208 }
209 if (do_break) {
210 break;
211 }
212 }
214 if (do_break) {
215 break;
216 }
217 }
219
220 /* NOTE: It may happen that no parent library is found, e.g. if after deleting a directly used
221 * library, its indirect dependency is still around, but none of its linked IDs are used by local
222 * data. */
223 if (best_parent_lib) {
224 lib->runtime.parent = best_parent_lib;
225 lib->runtime.temp_index = best_parent_lib->runtime.temp_index + 1;
226 }
227 else {
228 lib->runtime.parent = nullptr;
229 lib->runtime.temp_index = 0;
230 directly_used_libs.add(lib);
231 }
232}
233
235{
237
238 /* Reset all values, they may have been set to irrelevant values by other processes (like the
239 * liboverride handling e.g., see #lib_override_libraries_index_define). */
240 LISTBASE_FOREACH (Library *, lib_iter, &bmain->libraries) {
241 lib_iter->runtime.temp_index = 0;
242 }
243
244 /* Find all libraries with directly linked IDs (i.e. IDs used by local data). */
245 blender::Set<Library *> directly_used_libs;
246 ID *id_iter;
247 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
248 if (!ID_IS_LINKED(id_iter)) {
249 continue;
250 }
251 id_iter->lib->runtime.temp_index = 0;
252 if (directly_used_libs.contains(id_iter->lib)) {
253 continue;
254 }
255 MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
257 for (MainIDRelationsEntryItem *item = entry->from_ids; item; item = item->next) {
258 if (!ID_IS_LINKED(item->id_pointer.from)) {
259 directly_used_libs.add(id_iter->lib);
260 id_iter->lib->runtime.parent = nullptr;
261 break;
262 }
263 }
264 }
266
267 LISTBASE_FOREACH (Library *, lib_iter, &bmain->libraries) {
268 /* A directly used library. */
269 if (directly_used_libs.contains(lib_iter)) {
270 BLI_assert(lib_iter->runtime.temp_index == 0);
271 continue;
272 }
273
274 /* Assume existing parent is still valid, since it was not cleared in previous loop above.
275 * Just compute 'hierarchy value' in temp index, if needed. */
276 if (lib_iter->runtime.parent) {
277 if (lib_iter->runtime.temp_index > 0) {
278 continue;
279 }
280 blender::Vector<Library *> parent_libraries;
281 for (Library *parent_lib_iter = lib_iter;
282 parent_lib_iter && parent_lib_iter->runtime.temp_index == 0;
283 parent_lib_iter = parent_lib_iter->runtime.parent)
284 {
285 parent_libraries.append(parent_lib_iter);
286 }
287 int parent_temp_index = parent_libraries.last()->runtime.temp_index +
288 int(parent_libraries.size()) - 1;
289 for (Library *parent_lib_iter : parent_libraries) {
290 BLI_assert(parent_lib_iter != parent_libraries.last() ||
291 parent_lib_iter->runtime.temp_index == parent_temp_index);
292 parent_lib_iter->runtime.temp_index = parent_temp_index--;
293 }
294 continue;
295 }
296
297 /* Otherwise, it's an indirectly used library with no known parent, another loop is needed to
298 * ensure all known hierarchy has valid indices when trying to find the best valid parent
299 * library. */
300 }
301
302 /* For all libraries known to be indirect, but without a known parent, find a best valid parent
303 * (i.e. a 'most directly used' library). */
304 LISTBASE_FOREACH (Library *, lib_iter, &bmain->libraries) {
305 /* A directly used library. */
306 if (directly_used_libs.contains(lib_iter)) {
307 BLI_assert(lib_iter->runtime.temp_index == 0);
308 continue;
309 }
310
311 if (lib_iter->runtime.parent) {
312 BLI_assert(lib_iter->runtime.temp_index > 0);
313 }
314 else {
315 BLI_assert(lib_iter->runtime.temp_index == 0);
316 rebuild_hierarchy_best_parent_find(bmain, directly_used_libs, lib_iter);
317 }
318 }
319
321}
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
Definition bpath.cc:123
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition BKE_idtype.hh:41
@ IDTYPE_FLAGS_NO_LIBLINKING
Definition BKE_idtype.hh:32
@ IDTYPE_FLAGS_NEVER_UNUSED
Definition BKE_idtype.hh:64
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_NEVER_SELF
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:500
#define FOREACH_MAIN_LISTBASE_ID_END
Definition BKE_main.hh:469
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
Definition BKE_main.hh:463
#define FOREACH_MAIN_LISTBASE_END
Definition BKE_main.hh:481
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition BKE_main.hh:474
void BKE_main_relations_create(Main *bmain, short flag)
Definition main.cc:544
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:494
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
void BKE_main_relations_free(Main *bmain)
Definition main.cc:580
void BKE_main_namemap_destroy(UniqueName_Map **r_name_map) ATTR_NONNULL()
PackedFile * BKE_packedfile_duplicate(const PackedFile *pf_src)
void BKE_packedfile_free(PackedFile *pf)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define UNUSED_VARS_NDEBUG(...)
#define BLT_I18NCONTEXT_ID_LIBRARY
ID and Library types, which are fundamental for SDNA.
struct Library Library
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
@ INDEX_ID_LI
Definition DNA_ID.h:1248
#define FILTER_ID_LI
Definition DNA_ID.h:1202
@ ID_LI
bool contains(const Key &key) const
Definition BLI_set.hh:291
bool add(const Key &key)
Definition BLI_set.hh:248
int64_t size() const
void append(const T &value)
const T & last(const int64_t n=0) const
#define offsetof(t, d)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
Definition library.cc:135
void BKE_library_main_rebuild_hierarchy(Main *bmain)
Definition library.cc:234
static void library_runtime_reset(Library *lib)
Definition library.cc:34
static void rebuild_hierarchy_best_parent_find(Main *bmain, blender::Set< Library * > &directly_used_libs, Library *lib)
Definition library.cc:160
static void library_blend_read_data(BlendDataReader *, ID *id)
Definition library.cc:99
static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data)
Definition library.cc:82
static void library_foreach_id(ID *id, LibraryForeachIDData *data)
Definition library.cc:76
IDTypeInfo IDType_ID_LI
Definition library.cc:105
static void library_copy_data(Main *bmain, std::optional< Library * > owner_library, ID *id_dst, const ID *id_src, int)
Definition library.cc:50
static void library_free_data(ID *id)
Definition library.cc:41
Definition DNA_ID.h:413
struct Library * lib
Definition DNA_ID.h:419
struct UniqueName_Map * name_map
Definition DNA_ID.h:497
struct Library * parent
Definition DNA_ID.h:512
struct FileData * filedata
Definition DNA_ID.h:499
char filepath_abs[1024]
Definition DNA_ID.h:509
struct PackedFile * packedfile
Definition DNA_ID.h:533
struct Library_Runtime runtime
Definition DNA_ID.h:535
MainIDRelationsEntryItem * from_ids
Definition BKE_main.hh:67
GHash * relations_from_pointers
Definition BKE_main.hh:108
ListBase libraries
Definition BKE_main.hh:211
MainIDRelations * relations
Definition BKE_main.hh:260
#define N_(msgid)
static DynamicLibrary lib