diff options
-rw-r--r-- | source/blender/editors/object/object_relations.c | 44 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_tools.cc | 95 |
2 files changed, 136 insertions, 3 deletions
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 3ecf86d14ed..70081b4b5f2 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2273,6 +2273,10 @@ static int make_override_library_exec(bContext *C, wmOperator *op) ID *id_root = NULL; bool is_override_instancing_object = false; + GSet *user_overrides_objects_uids = BLI_gset_new( + BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__); + bool user_overrides_from_selected_objects = false; + if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && ID_IS_LINKED(obact->instance_collection)) { if (!ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)) { @@ -2285,6 +2289,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op) id_root = &obact->instance_collection->id; is_override_instancing_object = true; + user_overrides_from_selected_objects = false; } else if (!make_override_library_object_overridable_check(bmain, obact)) { const int i = RNA_property_enum_get(op->ptr, op->type->prop); @@ -2309,16 +2314,53 @@ static int make_override_library_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } id_root = &collection->id; + user_overrides_from_selected_objects = true; } /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ else { id_root = &obact->id; + user_overrides_from_selected_objects = true; + } + + if (user_overrides_from_selected_objects) { + /* Only selected objects can be 'user overrides'. */ + FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) { + BLI_gset_add(user_overrides_objects_uids, POINTER_FROM_UINT(ob_iter->id.session_uuid)); + } + FOREACH_SELECTED_OBJECT_END; + } + else { + /* Only armatures inside the root collection (and their children) can be 'user overrides'. */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN ((Collection *)id_root, ob_iter) { + if (ob_iter->type == OB_ARMATURE) { + BLI_gset_add(user_overrides_objects_uids, POINTER_FROM_UINT(ob_iter->id.session_uuid)); + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + ID *id_root_override; const bool success = BKE_lib_override_library_create( - bmain, scene, view_layer, NULL, id_root, id_root, &obact->id, NULL); + bmain, scene, view_layer, NULL, id_root, id_root, &obact->id, &id_root_override); + + /* Define liboverrides from selected/validated objects as user defined. */ + ID *id_hierarchy_root_override = id_root_override->override_library->hierarchy_root; + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter) || + id_iter->override_library->hierarchy_root != id_hierarchy_root_override) { + continue; + } + if (BLI_gset_haskey(user_overrides_objects_uids, + POINTER_FROM_UINT(id_iter->override_library->reference->session_uuid))) { + id_iter->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED; + } + } + FOREACH_MAIN_ID_END; + + BLI_gset_free(user_overrides_objects_uids, NULL); /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index 55196d042ae..8c5e3cd2d15 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -31,6 +31,7 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" +#include "BLI_set.hh" #include "BLI_utildefines.h" #include "BKE_anim_data.h" @@ -87,6 +88,8 @@ static CLG_LogRef LOG = {"ed.outliner.tools"}; using namespace blender::ed::outliner; +using blender::Set; + /* -------------------------------------------------------------------- */ /** \name ID/Library/Data Set/Un-link Utilities * \{ */ @@ -755,8 +758,50 @@ struct OutlinerLibOverrideData { * instead of re-applying relevant existing ID pointer property override operations. Helps * solving broken overrides while not losing *all* of your overrides. */ bool do_resync_hierarchy_enforce; + + /** The override hierarchy root, when known/created. */ + ID *id_hierarchy_root_override; + + /** A hash of the selected tree elements' ID 'uuid'. Used to clear 'system override' flags on + * their newly-created liboverrides in post-process step of override hierarchy creation. */ + Set<uint> selected_id_uid; }; +/* Store 'UUID' of IDs of selected elements in the Outliner tree, before generating the override + * hierarchy. */ +static void id_override_library_create_hierarchy_pre_process_fn(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *user_data) +{ + BLI_assert(TSE_IS_REAL_ID(tselem)); + + OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); + const bool do_hierarchy = data->do_hierarchy; + ID *id_root_reference = tselem->id; + + BLI_assert(do_hierarchy); + UNUSED_VARS_NDEBUG(do_hierarchy); + + data->selected_id_uid.add(id_root_reference->session_uuid); + + if (GS(id_root_reference->name) == ID_GR && (tselem->flag & TSE_CLOSED) != 0) { + /* If selected element is a (closed) collection, check all of its objects recursively, and also + * consider the armature ones as 'selected' (i.e. to not become system overrides). */ + Collection *root_collection = reinterpret_cast<Collection *>(id_root_reference); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (root_collection, object_iter) { + if (id_root_reference->lib == object_iter->id.lib && object_iter->type == OB_ARMATURE) { + printf("Foooo\n"); + data->selected_id_uid.add(object_iter->id.session_uuid); + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } +} + static void id_override_library_create_fn(bContext *C, ReportList *reports, Scene *scene, @@ -775,7 +820,7 @@ static void id_override_library_create_fn(bContext *C, bool is_override_instancing_object = false; if (tsep != nullptr && tsep->type == TSE_SOME_ID && tsep->id != nullptr && GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id)) { - Object *ob = (Object *)tsep->id; + Object *ob = reinterpret_cast<Object *>(tsep->id); if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root_reference) { BLI_assert(GS(id_root_reference->name) == ID_GR); /* Empty instantiating the collection we override, we need to pass it to BKE overriding code @@ -888,6 +933,7 @@ static void id_override_library_create_fn(bContext *C, return; } + ID *id_root_override = nullptr; success = BKE_lib_override_library_create(bmain, CTX_data_scene(C), CTX_data_view_layer(C), @@ -895,7 +941,22 @@ static void id_override_library_create_fn(bContext *C, id_root_reference, id_hierarchy_root_reference, id_instance_hint, - nullptr); + &id_root_override); + + BLI_assert(id_root_override != nullptr); + BLI_assert(!ID_IS_LINKED(id_root_override)); + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override)); + if (ID_IS_LINKED(id_hierarchy_root_reference)) { + BLI_assert( + id_root_override->override_library->hierarchy_root->override_library->reference == + id_hierarchy_root_reference); + data->id_hierarchy_root_override = id_root_override->override_library->hierarchy_root; + } + else { + BLI_assert(id_root_override->override_library->hierarchy_root == + id_hierarchy_root_reference); + data->id_hierarchy_root_override = id_root_override->override_library->hierarchy_root; + } } else if (ID_IS_OVERRIDABLE_LIBRARY(id_root_reference)) { success = BKE_lib_override_library_create_from_id(bmain, id_root_reference, true) != nullptr; @@ -919,6 +980,27 @@ static void id_override_library_create_fn(bContext *C, } } +/* Clear system override flag from newly created overrides which linked reference were previously + * selected in the Outliner tree. */ +static void id_override_library_create_hierarchy_post_process(bContext *C, + OutlinerLibOverrideData *data) +{ + Main *bmain = CTX_data_main(C); + ID *id_hierarchy_root_override = data->id_hierarchy_root_override; + + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter) || + id_iter->override_library->hierarchy_root != id_hierarchy_root_override) { + continue; + } + if (data->selected_id_uid.contains(id_iter->override_library->reference->session_uuid)) { + id_iter->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED; + } + } + FOREACH_MAIN_ID_END; +} + static void id_override_library_reset_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), @@ -2106,8 +2188,17 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) scene, space_outliner, &space_outliner->tree, + id_override_library_create_hierarchy_pre_process_fn, + &override_data); + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, id_override_library_create_fn, &override_data); + id_override_library_create_hierarchy_post_process(C, &override_data); + ED_undo_push(C, "Overridden Data Hierarchy"); break; } |