Blendread: Remove all instantiation logic from `BLO_library_link_` code.

Instantiation is now fully handled by BKE_blendfile_link_append module.

Note that this also allows removal of the `BLO_LIBLINK_NEEDS_ID_TAG_DOIT`
flag.

Part of T91414: Unify link/append between WM operators and BPY context
manager API, and cleanup usages of `BKE_library_make_local`.
This commit is contained in:
Bastien Montagne 2021-11-30 17:52:58 +01:00
parent 4fe8c62b56
commit 9f290467ca
Notes: blender-bot 2023-02-14 12:01:57 +01:00
Referenced by issue #91414, Unify link/append between WM operators and BPY context manager API, and cleanup usages of `BKE_library_make_local`
3 changed files with 7 additions and 395 deletions

View File

@ -1324,12 +1324,6 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
/* here appending/linking starts */
/* NOTE: This is temporary hot-fix until whole code using link/append features has been moved
* to use new BKE code. */
/* Do not handle instantiation in linking process anymore, we do it here in
* #loose_data_instantiate instead. */
lapp_context->params->flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
mainl = BLO_library_link_begin(&blo_handle, libname, lapp_context->params);
lib = mainl->curlib;
BLI_assert(lib);

View File

@ -212,14 +212,6 @@ typedef enum eBLOLibLinkFlags {
BLO_LIBLINK_USE_PLACEHOLDERS = 1 << 16,
/** Force loaded ID to be tagged as #LIB_TAG_INDIRECT (used in reload context only). */
BLO_LIBLINK_FORCE_INDIRECT = 1 << 17,
/**
* When set, tag ID types that pass the internal check #library_link_idcode_needs_tag_check
*
* Currently this is only used to instantiate objects in the scene.
* Set this from #BLO_library_link_params_init_with_context so callers
* don't need to remember to set this flag.
*/
BLO_LIBLINK_NEEDS_ID_TAG_DOIT = 1 << 18,
/** Set fake user on appended IDs. */
BLO_LIBLINK_APPEND_SET_FAKEUSER = 1 << 19,
/** Append (make local) also indirect dependencies of appended IDs coming from other libraries.
@ -335,14 +327,6 @@ void BLO_sanitize_experimental_features_userpref_blend(struct UserDef *userdef);
struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath);
void BLO_object_instantiate_object_base_instance_init(struct Main *bmain,
struct Collection *collection,
struct Object *ob,
struct ViewLayer *view_layer,
const struct View3D *v3d,
const int flag,
bool set_active);
/* datafiles (generated theme) */
extern const struct bTheme U_theme_default;
extern const struct UserDef U_default;

View File

@ -195,7 +195,6 @@ static void read_libraries(FileData *basefd, ListBase *mainlist);
static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
static bool library_link_idcode_needs_tag_check(const short idcode, const int flag);
typedef struct BHeadN {
struct BHeadN *next, *prev;
@ -4441,290 +4440,6 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
/** \name Library Linking (helper functions)
* \{ */
static bool object_in_any_scene(Main *bmain, Object *ob)
{
LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
if (BKE_scene_object_find(sce, ob)) {
return true;
}
}
return false;
}
static bool object_in_any_collection(Main *bmain, Object *ob)
{
LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
if (BKE_collection_has_object(collection, ob)) {
return true;
}
}
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->master_collection != NULL &&
BKE_collection_has_object(scene->master_collection, ob)) {
return true;
}
}
return false;
}
/**
* Shared operations to perform on the object's base after adding it to the scene.
*/
static void object_base_instance_init(
Object *ob, ViewLayer *view_layer, const View3D *v3d, const int flag, bool set_active)
{
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (v3d != NULL) {
base->local_view_bits |= v3d->local_view_uuid;
}
if (flag & FILE_AUTOSELECT) {
/* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */
BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK));
if (base->flag & BASE_SELECTABLE) {
base->flag |= BASE_SELECTED;
}
}
if (set_active) {
view_layer->basact = base;
}
BKE_scene_object_base_flag_sync_from_base(base);
}
/**
* Exported for link/append to create objects as well.
*/
void BLO_object_instantiate_object_base_instance_init(Main *bmain,
Collection *collection,
Object *ob,
ViewLayer *view_layer,
const View3D *v3d,
const int flag,
bool set_active)
{
/* Auto-select and appending. */
if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) {
/* While in general the object should not be manipulated,
* when the user requests the object to be selected, ensure it's visible and selectable. */
ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT);
}
BKE_collection_object_add(bmain, collection, ob);
object_base_instance_init(ob, view_layer, v3d, flag, set_active);
}
static void add_loose_objects_to_scene(Main *mainvar,
Main *bmain,
Scene *scene,
ViewLayer *view_layer,
const View3D *v3d,
Library *lib,
const int flag)
{
Collection *active_collection = NULL;
const bool do_append = (flag & FILE_LINK) == 0;
BLI_assert(scene);
/* Give all objects which are LIB_TAG_INDIRECT a base,
* or for a collection when *lib has been set. */
LISTBASE_FOREACH (Object *, ob, &mainvar->objects) {
/* NOTE: Even if this is a directly linked object and is tagged for instantiation, it might
* have already been instantiated through one of its owner collections, in which case we do not
* want to re-instantiate it in the active collection here. */
bool do_it = (ob->id.tag & LIB_TAG_DOIT) != 0 && !BKE_scene_object_find(scene, ob);
if (do_it ||
((ob->id.tag & LIB_TAG_INDIRECT) != 0 && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0)) {
if (do_append) {
if (ob->id.us == 0) {
do_it = true;
}
else if ((ob->id.lib == lib) && !object_in_any_collection(bmain, ob)) {
/* When appending, make sure any indirectly loaded object gets a base,
* when they are not part of any collection yet. */
do_it = true;
}
}
if (do_it) {
/* Find or add collection as needed. */
if (active_collection == NULL) {
if (flag & FILE_ACTIVE_COLLECTION) {
LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
active_collection = lc->collection;
}
else {
active_collection = BKE_collection_add(bmain, scene->master_collection, NULL);
}
}
CLAMP_MIN(ob->id.us, 0);
ob->mode = OB_MODE_OBJECT;
/* Do NOT make base active here! screws up GUI stuff,
* if you want it do it at the editor level. */
const bool set_active = false;
BLO_object_instantiate_object_base_instance_init(
bmain, active_collection, ob, view_layer, v3d, flag, set_active);
ob->id.tag &= ~LIB_TAG_INDIRECT;
ob->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
ob->id.tag |= LIB_TAG_EXTERN;
}
}
}
}
static void add_loose_object_data_to_scene(Main *mainvar,
Main *bmain,
Scene *scene,
ViewLayer *view_layer,
const View3D *v3d,
const int flag)
{
if ((flag & BLO_LIBLINK_OBDATA_INSTANCE) == 0) {
return;
}
Collection *active_collection = scene->master_collection;
if (flag & FILE_ACTIVE_COLLECTION) {
LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
active_collection = lc->collection;
}
/* Do not re-instantiate obdata IDs that are already instantiated by an object. */
LISTBASE_FOREACH (Object *, ob, &mainvar->objects) {
if ((ob->id.tag & LIB_TAG_PRE_EXISTING) == 0 && ob->data != NULL) {
ID *obdata = ob->data;
BLI_assert(ID_REAL_USERS(obdata) > 0);
if ((obdata->tag & LIB_TAG_PRE_EXISTING) == 0) {
obdata->tag &= ~LIB_TAG_DOIT;
}
}
}
/* Loop over all ID types, instancing object-data for ID types that have support for it. */
ListBase *lbarray[INDEX_ID_MAX];
int i = set_listbasepointers(mainvar, lbarray);
while (i--) {
const short idcode = BKE_idtype_idcode_from_index(i);
if (!OB_DATA_SUPPORT_ID(idcode)) {
continue;
}
LISTBASE_FOREACH (ID *, id, lbarray[i]) {
if (id->tag & LIB_TAG_DOIT) {
const int type = BKE_object_obdata_to_type(id);
BLI_assert(type != -1);
Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
ob->data = id;
id_us_plus(id);
BKE_object_materials_test(bmain, ob, ob->data);
/* Do NOT make base active here! screws up GUI stuff,
* if you want it do it at the editor level. */
bool set_active = false;
BLO_object_instantiate_object_base_instance_init(
bmain, active_collection, ob, view_layer, v3d, flag, set_active);
copy_v3_v3(ob->loc, scene->cursor.location);
}
}
}
}
static void add_collections_to_scene(Main *mainvar,
Main *bmain,
Scene *scene,
ViewLayer *view_layer,
const View3D *v3d,
Library *lib,
const int flag)
{
Collection *active_collection = scene->master_collection;
if (flag & FILE_ACTIVE_COLLECTION) {
LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
active_collection = lc->collection;
}
/* Give all objects which are tagged a base. */
LISTBASE_FOREACH (Collection *, collection, &mainvar->collections) {
if ((flag & BLO_LIBLINK_COLLECTION_INSTANCE) && (collection->id.tag & LIB_TAG_DOIT)) {
/* Any indirect collection should not have been tagged. */
BLI_assert((collection->id.tag & LIB_TAG_INDIRECT) == 0);
/* BKE_object_add(...) messes with the selection. */
Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
ob->type = OB_EMPTY;
ob->empty_drawsize = U.collection_instance_empty_size;
const bool set_selected = (flag & FILE_AUTOSELECT) != 0;
/* TODO: why is it OK to make this active here but not in other situations?
* See other callers of #object_base_instance_init */
const bool set_active = set_selected;
BLO_object_instantiate_object_base_instance_init(
bmain, active_collection, ob, view_layer, v3d, flag, set_active);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
/* Assign the collection. */
ob->instance_collection = collection;
id_us_plus(&collection->id);
ob->transflag |= OB_DUPLICOLLECTION;
copy_v3_v3(ob->loc, scene->cursor.location);
}
/* We do not want to force instantiation of indirectly linked collections,
* not even when appending. Users can now easily instantiate collections (and their objects)
* as needed by themselves. See T67032. */
else if ((collection->id.tag & LIB_TAG_INDIRECT) == 0) {
bool do_add_collection = (collection->id.tag & LIB_TAG_DOIT) != 0;
if (!do_add_collection) {
/* We need to check that objects in that collections are already instantiated in a scene.
* Otherwise, it's better to add the collection to the scene's active collection, than to
* instantiate its objects in active scene's collection directly. See T61141.
* Note that we only check object directly into that collection,
* not recursively into its children.
*/
LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
Object *ob = coll_ob->ob;
if ((ob->id.tag & (LIB_TAG_PRE_EXISTING | LIB_TAG_DOIT | LIB_TAG_INDIRECT)) == 0 &&
(ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == false)) {
do_add_collection = true;
break;
}
}
}
if (do_add_collection) {
/* Add collection as child of active collection. */
BKE_collection_child_add(bmain, active_collection, collection);
if (flag & FILE_AUTOSELECT) {
LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
Object *ob = coll_ob->ob;
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base) {
base->flag |= BASE_SELECTED;
BKE_scene_object_base_flag_sync_from_base(base);
}
}
}
/* Those are kept for safety and consistency, but should not be needed anymore? */
collection->id.tag &= ~LIB_TAG_INDIRECT;
collection->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
collection->id.tag |= LIB_TAG_EXTERN;
}
}
}
}
/* returns true if the item was found
* but it may already have already been appended/linked */
static ID *link_named_part(
@ -4774,14 +4489,6 @@ static ID *link_named_part(
/* if we found the id but the id is NULL, this is really bad */
BLI_assert(!((bhead != NULL) && (id == NULL)));
/* Tag as loose object (or data associated with objects)
* needing to be instantiated in #LibraryLink_Params.scene. */
if ((id != NULL) && (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT)) {
if (library_link_idcode_needs_tag_check(idcode, flag)) {
id->tag |= LIB_TAG_DOIT;
}
}
return id;
}
@ -4806,41 +4513,10 @@ ID *BLO_library_link_named_part(Main *mainl,
/* common routine to append/link something from a library */
/**
* Checks if the \a idcode needs to be tagged with #LIB_TAG_DOIT when linking/appending.
*/
static bool library_link_idcode_needs_tag_check(const short idcode, const int flag)
{
if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
/* Always true because of #add_loose_objects_to_scene & #add_collections_to_scene. */
if (ELEM(idcode, ID_OB, ID_GR)) {
return true;
}
if (flag & BLO_LIBLINK_OBDATA_INSTANCE) {
if (OB_DATA_SUPPORT_ID(idcode)) {
return true;
}
}
}
return false;
}
/**
* Clears #LIB_TAG_DOIT based on the result of #library_link_idcode_needs_tag_check.
*/
static void library_link_clear_tag(Main *mainvar, const int flag)
{
for (int i = 0; i < INDEX_ID_MAX; i++) {
const short idcode = BKE_idtype_idcode_from_index(i);
BLI_assert(idcode != -1);
if (library_link_idcode_needs_tag_check(idcode, flag)) {
BKE_main_id_tag_idcode(mainvar, idcode, LIB_TAG_DOIT, false);
}
}
}
static Main *library_link_begin(
Main *mainvar, FileData **fd, const char *filepath, const int flag, const int id_tag_extra)
static Main *library_link_begin(Main *mainvar,
FileData **fd,
const char *filepath,
const int id_tag_extra)
{
Main *mainl;
@ -4853,11 +4529,6 @@ static Main *library_link_begin(
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
/* Clear for objects and collections instantiating tag. */
library_link_clear_tag(mainvar, flag);
}
/* make mains */
blo_split_main((*fd)->mainlist, mainvar);
@ -4896,9 +4567,6 @@ void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params
{
BLO_library_link_params_init(params, bmain, flag, id_tag_extra);
if (scene != NULL) {
/* Tagging is needed for instancing. */
params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
params->context.scene = scene;
params->context.view_layer = view_layer;
params->context.v3d = v3d;
@ -4919,7 +4587,7 @@ Main *BLO_library_link_begin(BlendHandle **bh,
const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
return library_link_begin(params->bmain, &fd, filepath, params->flag, params->id_tag_extra);
return library_link_begin(params->bmain, &fd, filepath, params->id_tag_extra);
}
static void split_main_newid(Main *mainptr, Main *main_newid)
@ -4946,19 +4614,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
}
}
/**
* \param scene: The scene in which to instantiate objects/collections
* (if NULL, no instantiation is done).
* \param v3d: The active 3D viewport.
* (only to define active layers for instantiated objects & collections, can be NULL).
*/
static void library_link_end(Main *mainl,
FileData **fd,
Main *bmain,
const int flag,
Scene *scene,
ViewLayer *view_layer,
const View3D *v3d)
static void library_link_end(Main *mainl, FileData **fd, const int flag)
{
Main *mainvar;
Library *curlib;
@ -5043,22 +4699,6 @@ static void library_link_end(Main *mainl,
/* Make all relative paths, relative to the open blend file. */
fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar);
/* Give a base to loose objects and collections.
* Only directly linked objects & collections are instantiated by
* #BLO_library_link_named_part & co,
* here we handle indirect ones and other possible edge-cases. */
if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
/* Should always be true. */
if (scene != NULL) {
add_collections_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
add_loose_objects_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
add_loose_object_data_to_scene(mainvar, bmain, scene, view_layer, v3d, flag);
}
/* Clear objects and collections instantiating tag. */
library_link_clear_tag(mainvar, flag);
}
/* patch to prevent switch_endian happens twice */
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
blo_filedata_free(*fd);
@ -5078,13 +4718,7 @@ static void library_link_end(Main *mainl,
void BLO_library_link_end(Main *mainl, BlendHandle **bh, const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
library_link_end(mainl,
&fd,
params->bmain,
params->flag,
params->context.scene,
params->context.view_layer,
params->context.v3d);
library_link_end(mainl, &fd, params->flag);
*bh = (BlendHandle *)fd;
}