LibOverride: Add operator to convert a proxy object into an override.

In the end the process is surpringly simple, we only need to manually
convert the proxy itself into an override (which is trivial), and then
run common code with the default 'make override' operation.

Fix T81059: Add operator to convert proxies to library overrides.
This commit is contained in:
Bastien Montagne 2020-09-23 10:47:27 +02:00
parent 6fde0050c4
commit c3a0618fbf
Notes: blender-bot 2023-02-14 06:49:57 +01:00
Referenced by issue #81049, Add operator to convert proxies to library overrides
7 changed files with 149 additions and 0 deletions

View File

@ -2191,6 +2191,8 @@ class VIEW3D_MT_object_relations(Menu):
layout.operator("object.make_override_library", text="Make Library Override...")
layout.operator("object.convert_proxy_to_override")
layout.operator("object.make_dupli_face")
layout.separator()

View File

@ -49,6 +49,7 @@ struct IDOverrideLibraryPropertyOperation;
struct Main;
struct PointerRNA;
struct PropertyRNA;
struct Object;
struct Scene;
struct ViewLayer;
@ -77,6 +78,10 @@ bool BKE_lib_override_library_create(struct Main *bmain,
struct ViewLayer *view_layer,
struct ID *id_root,
struct ID *id_reference);
bool BKE_lib_override_library_proxy_convert(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Object *ob_proxy);
bool BKE_lib_override_library_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,

View File

@ -668,6 +668,42 @@ bool BKE_lib_override_library_create(
return success;
}
/**
* Converts a given proxy object into a library override.
*
* \note This is actually a thin wrapper around \a BKE_lib_override_library_create, only extra work
* is to actually convert the proxy itself into an override first.
*
* \return true if override was successfully created.
*/
bool BKE_lib_override_library_proxy_convert(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
Object *ob_proxy)
{
/* proxy_group, if defined, is the empty instanciating the collection from which the proxy is
* coming. */
Object *ob_proxy_group = ob_proxy->proxy_group;
const bool is_override_instancing_object = ob_proxy_group != NULL;
ID *id_root = is_override_instancing_object ? &ob_proxy_group->instance_collection->id :
&ob_proxy->proxy->id;
ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id;
/* We manually convert the proxy object into a library override, further override handling will
* then be handled by BKE_lib_override_library_create() just as for a regular override creation.
*/
ob_proxy->proxy->id.tag |= LIB_TAG_DOIT;
ob_proxy->proxy->id.newid = &ob_proxy->id;
BKE_lib_override_library_init(&ob_proxy->id, &ob_proxy->proxy->id);
ob_proxy->proxy->proxy_from = NULL;
ob_proxy->proxy = ob_proxy->proxy_group = NULL;
DEG_id_tag_update(&ob_proxy->id, ID_RECALC_COPY_ON_WRITE);
return BKE_lib_override_library_create(bmain, scene, view_layer, id_root, id_reference);
}
/**
* Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked
* data, from an existing override hierarchy.

View File

@ -63,6 +63,7 @@ void OBJECT_OT_track_set(struct wmOperatorType *ot);
void OBJECT_OT_track_clear(struct wmOperatorType *ot);
void OBJECT_OT_make_local(struct wmOperatorType *ot);
void OBJECT_OT_make_override_library(struct wmOperatorType *ot);
void OBJECT_OT_convert_proxy_to_override(struct wmOperatorType *ot);
void OBJECT_OT_make_single_user(struct wmOperatorType *ot);
void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);

View File

@ -81,6 +81,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_track_clear);
WM_operatortype_append(OBJECT_OT_make_local);
WM_operatortype_append(OBJECT_OT_make_override_library);
WM_operatortype_append(OBJECT_OT_convert_proxy_to_override);
WM_operatortype_append(OBJECT_OT_make_single_user);
WM_operatortype_append(OBJECT_OT_make_links_scene);
WM_operatortype_append(OBJECT_OT_make_links_data);

View File

@ -2490,6 +2490,54 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot)
ot->prop = prop;
}
static bool convert_proxy_to_override_poll(bContext *C)
{
Object *obact = CTX_data_active_object(C);
return obact != NULL && obact->proxy != NULL;
}
static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
Object *ob_proxy = CTX_data_active_object(C);
Object *ob_proxy_group = ob_proxy->proxy_group;
const bool is_override_instancing_object = ob_proxy_group != NULL;
const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, view_layer, ob_proxy);
/* Remove the instance empty from this scene, the items now have an overridden collection
* instead. */
if (success && is_override_instancing_object) {
ED_object_base_free_and_unlink(bmain, scene, ob_proxy_group);
}
DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_WINDOW, NULL);
return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void OBJECT_OT_convert_proxy_to_override(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Convert Proxy To Override";
ot->description = "Convert a proxy to a local library override";
ot->idname = "OBJECT_OT_convert_proxy_to_override";
/* api callbacks */
ot->exec = convert_proxy_to_override_exec;
ot->poll = convert_proxy_to_override_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
/* ------------------------------------------------------------------- */

View File

@ -737,6 +737,31 @@ static void id_local_fn(bContext *C,
}
}
static void object_proxy_to_override_convert_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep),
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_proxy = tselem->id;
BLI_assert(GS(id_proxy->name) == ID_OB);
Object *ob_proxy = (Object *)id_proxy;
Scene *scene = CTX_data_scene(C);
if (ob_proxy->proxy == NULL) {
return;
}
BKE_lib_override_library_proxy_convert(
CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
typedef struct OutlinerLibOverrideData {
bool do_hierarchy;
} OutlinerLibOverrideData;
@ -1404,6 +1429,7 @@ enum {
OL_OP_RENAME,
OL_OP_OBJECT_MODE_ENTER,
OL_OP_OBJECT_MODE_EXIT,
OL_OP_PROXY_TO_OVERRIDE_CONVERT,
};
static const EnumPropertyItem prop_object_op_types[] = {
@ -1418,6 +1444,11 @@ static const EnumPropertyItem prop_object_op_types[] = {
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
{OL_OP_OBJECT_MODE_ENTER, "OBJECT_MODE_ENTER", 0, "Enter Mode", ""},
{OL_OP_OBJECT_MODE_EXIT, "OBJECT_MODE_EXIT", 0, "Exit Mode", ""},
{OL_OP_PROXY_TO_OVERRIDE_CONVERT,
"OBJECT_PROXY_TO_OVERRIDE",
0,
"Convert Proxy to Override",
"Convert a Proxy object to a full library override, inclduing all its dependencies"},
{0, NULL, 0, NULL, NULL},
};
@ -1487,6 +1518,15 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
str = "Rename Object";
}
else if (event == OL_OP_PROXY_TO_OVERRIDE_CONVERT) {
outliner_do_object_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
object_proxy_to_override_convert_fn);
str = "Convert Proxy to Override";
}
else {
BLI_assert(0);
return OPERATOR_CANCELLED;
@ -1654,6 +1694,7 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY,
OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY,
@ -1694,6 +1735,11 @@ static const EnumPropertyItem prop_id_op_types[] = {
0,
"Add Library Override Hierarchy",
"Add a local override of this linked data-block, and its hierarchy of dependencies"},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT,
"OVERRIDE_LIBRARY_PROXY_CONVERT",
0,
"Convert Proxy to Override",
"Convert a Proxy object to a full library override, inclduing all its dependencies"},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
"OVERRIDE_LIBRARY_RESET",
0,
@ -1904,6 +1950,16 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
ED_undo_push(C, "Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT: {
outliner_do_object_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
object_proxy_to_override_convert_fn);
ED_undo_push(C, "Convert Proxy to Override");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: {
outliner_do_libdata_operation(C,
op->reports,