diff options
Diffstat (limited to 'source/blender/editors/object/object_relations.c')
-rw-r--r-- | source/blender/editors/object/object_relations.c | 653 |
1 files changed, 293 insertions, 360 deletions
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index eed3f2ea90c..9520b03f3a6 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -33,6 +33,7 @@ #include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" +#include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" @@ -68,6 +69,7 @@ #include "BKE_gpencil.h" #include "BKE_hair.h" #include "BKE_idprop.h" +#include "BKE_idtype.h" #include "BKE_lattice.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -357,7 +359,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event) WM_enum_search_invoke(C, op, event); return OPERATOR_CANCELLED; } - else if (ID_IS_LINKED(ob)) { + if (ID_IS_LINKED(ob)) { uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); uiLayout *layout = UI_popup_menu_layout(pup); @@ -372,12 +374,10 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* this invoke just calls another instance of this operator... */ return OPERATOR_INTERFACE; } - else { - /* error.. cannot continue */ - BKE_report( - op->reports, RPT_ERROR, "Can only make proxy for a referenced object or collection"); - return OPERATOR_CANCELLED; - } + + /* error.. cannot continue */ + BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or collection"); + return OPERATOR_CANCELLED; } static int make_proxy_exec(bContext *C, wmOperator *op) @@ -706,36 +706,34 @@ bool ED_object_parent_set(ReportList *reports, if (par->type != OB_CURVE) { return 0; } + Curve *cu = par->data; + Curve *cu_eval = parent_eval->data; + if ((cu->flag & CU_PATH) == 0) { + cu->flag |= CU_PATH | CU_FOLLOW; + cu_eval->flag |= CU_PATH | CU_FOLLOW; + /* force creation of path data */ + BKE_displist_make_curveTypes(depsgraph, scene, par, false, false); + } else { - Curve *cu = par->data; - Curve *cu_eval = parent_eval->data; - if ((cu->flag & CU_PATH) == 0) { - cu->flag |= CU_PATH | CU_FOLLOW; - cu_eval->flag |= CU_PATH | CU_FOLLOW; - /* force creation of path data */ - BKE_displist_make_curveTypes(depsgraph, scene, par, false, false); - } - else { - cu->flag |= CU_FOLLOW; - cu_eval->flag |= CU_FOLLOW; - } + cu->flag |= CU_FOLLOW; + cu_eval->flag |= CU_FOLLOW; + } - /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */ - if (partype == PAR_FOLLOW) { - /* get or create F-Curve */ - bAction *act = ED_id_action_ensure(bmain, &cu->id); - FCurve *fcu = ED_action_fcurve_ensure(bmain, act, NULL, NULL, "eval_time", 0); + /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */ + if (partype == PAR_FOLLOW) { + /* get or create F-Curve */ + bAction *act = ED_id_action_ensure(bmain, &cu->id); + FCurve *fcu = ED_action_fcurve_ensure(bmain, act, NULL, NULL, "eval_time", 0); - /* setup dummy 'generator' modifier here to get 1-1 correspondence still working */ - if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) { - add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu); - } + /* setup dummy 'generator' modifier here to get 1-1 correspondence still working */ + if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) { + add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu); } + } - /* fall back on regular parenting now (for follow only) */ - if (partype == PAR_FOLLOW) { - partype = PAR_OBJECT; - } + /* fall back on regular parenting now (for follow only) */ + if (partype == PAR_FOLLOW) { + partype = PAR_OBJECT; } } else if (ELEM(partype, PAR_BONE, PAR_BONE_RELATIVE)) { @@ -753,188 +751,185 @@ bool ED_object_parent_set(ReportList *reports, BKE_report(reports, RPT_ERROR, "Loop in parents"); return false; } - else { - Object workob; - /* apply transformation of previous parenting */ - if (keep_transform) { - /* was removed because of bug [#23577], - * but this can be handy in some cases too [#32616], so make optional */ - BKE_object_apply_mat4(ob, ob->obmat, false, false); - } + Object workob; - /* set the parent (except for follow-path constraint option) */ - if (partype != PAR_PATH_CONST) { - ob->parent = par; - /* Always clear parentinv matrix for sake of consistency, see T41950. */ - unit_m4(ob->parentinv); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } + /* apply transformation of previous parenting */ + if (keep_transform) { + /* was removed because of bug [#23577], + * but this can be handy in some cases too [#32616], so make optional */ + BKE_object_apply_mat4(ob, ob->obmat, false, false); + } - /* handle types */ - if (pchan) { - BLI_strncpy(ob->parsubstr, pchan->name, sizeof(ob->parsubstr)); - } - else { - ob->parsubstr[0] = 0; - } + /* set the parent (except for follow-path constraint option) */ + if (partype != PAR_PATH_CONST) { + ob->parent = par; + /* Always clear parentinv matrix for sake of consistency, see T41950. */ + unit_m4(ob->parentinv); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } - if (partype == PAR_PATH_CONST) { - /* don't do anything here, since this is not technically "parenting" */ - } - else if (ELEM(partype, PAR_CURVE, PAR_LATTICE) || (pararm)) { - /* partype is now set to PAROBJECT so that invisible 'virtual' - * modifiers don't need to be created. - * NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, - * creating the virtual modifiers. - */ - ob->partype = PAROBJECT; /* note, dna define, not operator property */ - /* ob->partype = PARSKEL; */ /* note, dna define, not operator property */ + /* handle types */ + if (pchan) { + BLI_strncpy(ob->parsubstr, pchan->name, sizeof(ob->parsubstr)); + } + else { + ob->parsubstr[0] = 0; + } - /* BUT, to keep the deforms, we need a modifier, - * and then we need to set the object that it uses - * - We need to ensure that the modifier we're adding doesn't already exist, - * so we check this by assuming that the parent is selected too. - */ - /* XXX currently this should only happen for meshes, curves, surfaces, - * and lattices - this stuff isn't available for metas yet */ - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { - ModifierData *md; - - switch (partype) { - case PAR_CURVE: /* curve deform */ - if (BKE_modifiers_is_deformed_by_curve(ob) != par) { - md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Curve); - if (md) { - ((CurveModifierData *)md)->object = par; - } - if (par->runtime.curve_cache && par->runtime.curve_cache->path == NULL) { - DEG_id_tag_update(&par->id, ID_RECALC_GEOMETRY); - } + if (partype == PAR_PATH_CONST) { + /* don't do anything here, since this is not technically "parenting" */ + } + else if (ELEM(partype, PAR_CURVE, PAR_LATTICE) || (pararm)) { + /* partype is now set to PAROBJECT so that invisible 'virtual' + * modifiers don't need to be created. + * NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, + * creating the virtual modifiers. + */ + ob->partype = PAROBJECT; /* note, dna define, not operator property */ + /* ob->partype = PARSKEL; */ /* note, dna define, not operator property */ + + /* BUT, to keep the deforms, we need a modifier, + * and then we need to set the object that it uses + * - We need to ensure that the modifier we're adding doesn't already exist, + * so we check this by assuming that the parent is selected too. + */ + /* XXX currently this should only happen for meshes, curves, surfaces, + * and lattices - this stuff isn't available for metas yet */ + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + ModifierData *md; + + switch (partype) { + case PAR_CURVE: /* curve deform */ + if (BKE_modifiers_is_deformed_by_curve(ob) != par) { + md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Curve); + if (md) { + ((CurveModifierData *)md)->object = par; } - break; - case PAR_LATTICE: /* lattice deform */ - if (BKE_modifiers_is_deformed_by_lattice(ob) != par) { - md = ED_object_modifier_add( - reports, bmain, scene, ob, NULL, eModifierType_Lattice); - if (md) { - ((LatticeModifierData *)md)->object = par; - } + if (par->runtime.curve_cache && par->runtime.curve_cache->path == NULL) { + DEG_id_tag_update(&par->id, ID_RECALC_GEOMETRY); } - break; - default: /* armature deform */ - if (BKE_modifiers_is_deformed_by_armature(ob) != par) { - md = ED_object_modifier_add( - reports, bmain, scene, ob, NULL, eModifierType_Armature); - if (md) { - ((ArmatureModifierData *)md)->object = par; - } + } + break; + case PAR_LATTICE: /* lattice deform */ + if (BKE_modifiers_is_deformed_by_lattice(ob) != par) { + md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Lattice); + if (md) { + ((LatticeModifierData *)md)->object = par; } - break; - } - } - } - else if (partype == PAR_BONE) { - ob->partype = PARBONE; /* note, dna define, not operator property */ - if (pchan->bone) { - pchan->bone->flag &= ~BONE_RELATIVE_PARENTING; - pchan_eval->bone->flag &= ~BONE_RELATIVE_PARENTING; - } - } - else if (partype == PAR_BONE_RELATIVE) { - ob->partype = PARBONE; /* note, dna define, not operator property */ - if (pchan->bone) { - pchan->bone->flag |= BONE_RELATIVE_PARENTING; - pchan_eval->bone->flag |= BONE_RELATIVE_PARENTING; + } + break; + default: /* armature deform */ + if (BKE_modifiers_is_deformed_by_armature(ob) != par) { + md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Armature); + if (md) { + ((ArmatureModifierData *)md)->object = par; + } + } + break; } } - else if (partype == PAR_VERTEX) { - ob->partype = PARVERT1; - ob->par1 = vert_par[0]; - } - else if (partype == PAR_VERTEX_TRI) { - ob->partype = PARVERT3; - copy_v3_v3_int(&ob->par1, vert_par); + } + else if (partype == PAR_BONE) { + ob->partype = PARBONE; /* note, dna define, not operator property */ + if (pchan->bone) { + pchan->bone->flag &= ~BONE_RELATIVE_PARENTING; + pchan_eval->bone->flag &= ~BONE_RELATIVE_PARENTING; } - else { - ob->partype = PAROBJECT; /* note, dna define, not operator property */ + } + else if (partype == PAR_BONE_RELATIVE) { + ob->partype = PARBONE; /* note, dna define, not operator property */ + if (pchan->bone) { + pchan->bone->flag |= BONE_RELATIVE_PARENTING; + pchan_eval->bone->flag |= BONE_RELATIVE_PARENTING; } + } + else if (partype == PAR_VERTEX) { + ob->partype = PARVERT1; + ob->par1 = vert_par[0]; + } + else if (partype == PAR_VERTEX_TRI) { + ob->partype = PARVERT3; + copy_v3_v3_int(&ob->par1, vert_par); + } + else { + ob->partype = PAROBJECT; /* note, dna define, not operator property */ + } - /* constraint */ - if (partype == PAR_PATH_CONST) { - bConstraint *con; - bFollowPathConstraint *data; - float cmat[4][4], vec[3]; + /* constraint */ + if (partype == PAR_PATH_CONST) { + bConstraint *con; + bFollowPathConstraint *data; + float cmat[4][4], vec[3]; - con = BKE_constraint_add_for_object(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); + con = BKE_constraint_add_for_object(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); - data = con->data; - data->tar = par; + data = con->data; + data->tar = par; - BKE_constraint_target_matrix_get( - depsgraph, scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); - sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); + BKE_constraint_target_matrix_get( + depsgraph, scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); + sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); - copy_v3_v3(ob->loc, vec); + copy_v3_v3(ob->loc, vec); + } + else if (pararm && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) { + if (partype == PAR_ARMATURE_NAME) { + ED_object_vgroup_calc_from_armature( + reports, depsgraph, scene, ob, par, ARM_GROUPS_NAME, false); } - else if (pararm && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) { - if (partype == PAR_ARMATURE_NAME) { - ED_object_vgroup_calc_from_armature( - reports, depsgraph, scene, ob, par, ARM_GROUPS_NAME, false); - } - else if (partype == PAR_ARMATURE_ENVELOPE) { - ED_object_vgroup_calc_from_armature( - reports, depsgraph, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror); - } - else if (partype == PAR_ARMATURE_AUTO) { - WM_cursor_wait(1); - ED_object_vgroup_calc_from_armature( - reports, depsgraph, scene, ob, par, ARM_GROUPS_AUTO, xmirror); - WM_cursor_wait(0); - } - /* get corrected inverse */ - ob->partype = PAROBJECT; - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - - invert_m4_m4(ob->parentinv, workob.obmat); + else if (partype == PAR_ARMATURE_ENVELOPE) { + ED_object_vgroup_calc_from_armature( + reports, depsgraph, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror); } - else if (pararm && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) { - if (partype == PAR_ARMATURE) { - ED_gpencil_add_armature(C, reports, ob, par); - } - else if (partype == PAR_ARMATURE_NAME) { - ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME); - } - else if ((partype == PAR_ARMATURE_AUTO) || (partype == PAR_ARMATURE_ENVELOPE)) { - WM_cursor_wait(1); - ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO); - WM_cursor_wait(0); - } - /* get corrected inverse */ - ob->partype = PAROBJECT; - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - - invert_m4_m4(ob->parentinv, workob.obmat); + else if (partype == PAR_ARMATURE_AUTO) { + WM_cursor_wait(1); + ED_object_vgroup_calc_from_armature( + reports, depsgraph, scene, ob, par, ARM_GROUPS_AUTO, xmirror); + WM_cursor_wait(0); } - else if ((ob->type == OB_GPENCIL) && (par->type == OB_LATTICE)) { - /* Add Lattice modifier */ - if (partype == PAR_LATTICE) { - ED_gpencil_add_lattice_modifier(C, reports, ob, par); - } - /* get corrected inverse */ - ob->partype = PAROBJECT; - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + /* get corrected inverse */ + ob->partype = PAROBJECT; + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.obmat); + } + else if (pararm && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) { + if (partype == PAR_ARMATURE) { + ED_gpencil_add_armature(C, reports, ob, par); } - else { - /* calculate inverse parent matrix */ - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + else if (partype == PAR_ARMATURE_NAME) { + ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME); + } + else if ((partype == PAR_ARMATURE_AUTO) || (partype == PAR_ARMATURE_ENVELOPE)) { + WM_cursor_wait(1); + ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO); + WM_cursor_wait(0); + } + /* get corrected inverse */ + ob->partype = PAROBJECT; + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + + invert_m4_m4(ob->parentinv, workob.obmat); + } + else if ((ob->type == OB_GPENCIL) && (par->type == OB_LATTICE)) { + /* Add Lattice modifier */ + if (partype == PAR_LATTICE) { + ED_gpencil_add_lattice_modifier(C, reports, ob, par); } + /* get corrected inverse */ + ob->partype = PAROBJECT; + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + invert_m4_m4(ob->parentinv, workob.obmat); } + else { + /* calculate inverse parent matrix */ + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + invert_m4_m4(ob->parentinv, workob.obmat); + } + + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); } return true; @@ -1122,9 +1117,7 @@ static bool parent_set_poll_property(const bContext *UNUSED(C), if (ELEM(type, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO)) { return true; } - else { - return false; - } + return false; } return true; @@ -1771,7 +1764,10 @@ static Collection *single_object_users_collection(Main *bmain, /* Generate new copies for objects in given collection and all its children, * and optionally also copy collections themselves. */ if (copy_collections && !is_master_collection) { - collection = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection)); + Collection *collection_new; + BKE_id_copy(bmain, &collection->id, (ID **)&collection_new); + id_us_min(&collection_new->id); + collection = ID_NEW_SET(collection, collection_new); } /* We do not remap to new objects here, this is done in separate step. */ @@ -1882,7 +1878,7 @@ static void single_obdata_users( /* Needed to remap texcomesh below. */ me = ob->data = ID_NEW_SET(ob->data, BKE_mesh_copy(bmain, ob->data)); if (me->key) { /* We do not need to set me->key->id.newid here... */ - BKE_animdata_copy_id_action(bmain, (ID *)me->key, false); + BKE_animdata_copy_id_action(bmain, (ID *)me->key); } break; case OB_MBALL: @@ -1895,13 +1891,13 @@ static void single_obdata_users( ID_NEW_REMAP(cu->bevobj); ID_NEW_REMAP(cu->taperobj); if (cu->key) { /* We do not need to set cu->key->id.newid here... */ - BKE_animdata_copy_id_action(bmain, (ID *)cu->key, false); + BKE_animdata_copy_id_action(bmain, (ID *)cu->key); } break; case OB_LATTICE: ob->data = lat = ID_NEW_SET(ob->data, BKE_lattice_copy(bmain, ob->data)); if (lat->key) { /* We do not need to set lat->key->id.newid here... */ - BKE_animdata_copy_id_action(bmain, (ID *)lat->key, false); + BKE_animdata_copy_id_action(bmain, (ID *)lat->key); } break; case OB_ARMATURE: @@ -1941,7 +1937,7 @@ static void single_obdata_users( * AnimData structure, which is not what we want. * (sergey) */ - BKE_animdata_copy_id_action(bmain, (ID *)ob->data, false); + BKE_animdata_copy_id_action(bmain, (ID *)ob->data); id_us_min(id); } @@ -1962,7 +1958,7 @@ static void single_object_action_users( FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) { if (!ID_IS_LINKED(ob)) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - BKE_animdata_copy_id_action(bmain, &ob->id, false); + BKE_animdata_copy_id_action(bmain, &ob->id); } } FOREACH_OBJECT_FLAG_END; @@ -1984,7 +1980,7 @@ static void single_mat_users( if (ma->id.us > 1) { man = BKE_material_copy(bmain, ma); - BKE_animdata_copy_id_action(bmain, &man->id, false); + BKE_animdata_copy_id_action(bmain, &man->id); man->id.us = 0; BKE_object_material_assign(bmain, ob, man, a, BKE_MAT_ASSIGN_USERPREF); @@ -2246,52 +2242,22 @@ void OBJECT_OT_make_local(wmOperatorType *ot) /** \name Make Library Override Operator * \{ */ -static void make_override_library_tag_object(Object *obact, Object *ob) +static bool make_override_library_ovject_overridable_check(Main *bmain, Object *object) { - if (ob == obact) { - return; - } - - if (!ID_IS_LINKED(ob)) { - return; - } - - /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full - * 'automatic', generic handling of all this, - * will probably require adding some override-aware stuff to library_query code... */ - - if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) { - for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) { - if (md->type == eModifierType_Armature) { - ArmatureModifierData *amd = (ArmatureModifierData *)md; - if (amd->object == obact) { - ob->id.tag |= LIB_TAG_DOIT; - break; - } - } + /* An object is actually overrideable only if it is in at least one local collections. + * Unfortunately 'direct link' flag is not enough here. */ + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (!ID_IS_LINKED(collection) && BKE_collection_has_object(collection, object)) { + return true; } } - else if (ob->parent == obact) { - ob->id.tag |= LIB_TAG_DOIT; - } - - if (ob->id.tag & LIB_TAG_DOIT) { - printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name); - } -} - -static void make_override_library_tag_collections(Collection *collection) -{ - collection->id.tag |= LIB_TAG_DOIT; - for (CollectionChild *coll_child = collection->children.first; coll_child != NULL; - coll_child = coll_child->next) { - make_override_library_tag_collections(coll_child->collection); - } + return false; } /* Set the object to override. */ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *obact = ED_object_active_context(C); @@ -2300,14 +2266,9 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve return OPERATOR_CANCELLED; } - /* Get object to work on - use a menu if we need to... */ - if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && - ID_IS_LINKED(obact->instance_collection)) { - /* Gives menu with list of objects in group. */ - WM_enum_search_invoke(C, op, event); - return OPERATOR_CANCELLED; - } - else if (ID_IS_LINKED(obact)) { + if ((!ID_IS_LINKED(obact) && obact->instance_collection != NULL && + ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)) || + make_override_library_ovject_overridable_check(bmain, obact)) { uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); uiLayout *layout = UI_popup_menu_layout(pup); @@ -2322,21 +2283,27 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve /* This invoke just calls another instance of this operator... */ return OPERATOR_INTERFACE; } - else { - /* Error.. cannot continue. */ - BKE_report(op->reports, - RPT_ERROR, - "Can only make library override for a referenced object or collection"); + else if (ID_IS_LINKED(obact)) { + /* Show menu with list of directly linked collections containing the active object. */ + WM_enum_search_invoke(C, op, event); return OPERATOR_CANCELLED; } + + /* Error.. cannot continue. */ + BKE_report(op->reports, + RPT_ERROR, + "Can only make library override for a referenced object or collection"); + return OPERATOR_CANCELLED; } static int make_override_library_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); Object *obact = CTX_data_active_object(C); - - bool success = false; + ID *id_root = NULL; + bool is_override_instancing_object = false; if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && ID_IS_LINKED(obact->instance_collection)) { @@ -2348,115 +2315,50 @@ static int make_override_library_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - - Object *obcollection = obact; - Collection *collection = obcollection->instance_collection; - - const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection); - Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object")); - obact = base->object; - - /* First, we make a library override of the linked collection itself, and all its children. */ - make_override_library_tag_collections(collection); - - /* Then, we make library override of the whole set of objects in the Collection. */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { - ob->id.tag |= LIB_TAG_DOIT; - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - /* Then, we remove (untag) bone shape objects, you shall never want to override those - * (hopefully)... */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { - if (ob->type == OB_ARMATURE && ob->pose != NULL) { - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { - if (pchan->custom != NULL) { - pchan->custom->id.tag &= ~LIB_TAG_DOIT; - } - } - } + id_root = &obact->instance_collection->id; + is_override_instancing_object = true; + } + else if (!make_override_library_ovject_overridable_check(bmain, obact)) { + const int i = RNA_property_enum_get(op->ptr, op->type->prop); + const uint collection_session_uuid = *((uint *)&i); + if (collection_session_uuid == MAIN_ID_SESSION_UUID_UNSET) { + BKE_reportf(op->reports, + RPT_ERROR_INVALID_INPUT, + "Active object '%s' is not overridable", + obact->id.name + 2); + return OPERATOR_CANCELLED; } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - success = BKE_lib_override_library_create_from_tag(bmain); - /* Instantiate our newly overridden objects in scene, if not yet done. */ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Collection *new_collection = (Collection *)collection->id.newid; - - BKE_collection_add_from_object(bmain, scene, obcollection, new_collection); - - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (new_collection, new_ob) { - if (new_ob != NULL && new_ob->id.override_library != NULL) { - if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) { - BKE_collection_object_add_from(bmain, scene, obcollection, new_ob); - base = BKE_view_layer_base_find(view_layer, new_ob); - DEG_id_tag_update_ex(bmain, &new_ob->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); - } - - if (new_ob == (Object *)obact->id.newid) { - /* TODO: is setting active needed? */ - BKE_view_layer_base_select_and_set_active(view_layer, base); - } - else { - /* Disable auto-override tags for non-active objects, will help with performaces... */ - new_ob->id.override_library->flag &= ~OVERRIDE_LIBRARY_AUTO; - } - /* We still want to store all objects' current override status (i.e. change of parent). */ - BKE_lib_override_library_operations_create(bmain, &new_ob->id, true); - } + Collection *collection = BLI_listbase_bytes_find(&bmain->collections, + &collection_session_uuid, + sizeof(collection_session_uuid), + offsetof(ID, session_uuid)); + if (!ID_IS_OVERRIDABLE_LIBRARY(collection)) { + BKE_reportf(op->reports, + RPT_ERROR_INVALID_INPUT, + "Could not find an overridable collection containing object '%s'", + obact->id.name + 2); + return OPERATOR_CANCELLED; } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - /* Remove the instance empty from this scene, the items now have an overridden collection - * instead. */ - ED_object_base_free_and_unlink(bmain, scene, obcollection); - - /* Also, we'd likely want to lock by default things like - * transformations of implicitly overridden objects? */ - - DEG_id_tag_update(&scene->id, 0); - - /* Cleanup. */ - BKE_main_id_clear_newpoins(bmain); - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - } - else if (!ID_IS_OVERRIDABLE_LIBRARY(obact)) { - BKE_reportf(op->reports, - RPT_ERROR_INVALID_INPUT, - "Active object '%s' is not overridable", - obact->id.name + 2); - return OPERATOR_CANCELLED; + id_root = &collection->id; } /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ - else if (obact->type == OB_ARMATURE) { - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - - obact->id.tag |= LIB_TAG_DOIT; - - for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) { - make_override_library_tag_object(obact, ob); - } + else { + id_root = &obact->id; + } - success = BKE_lib_override_library_create_from_tag(bmain); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - /* Also, we'd likely want to lock by default things like - * transformations of implicitly overridden objects? */ + const bool success = BKE_lib_override_library_create( + bmain, scene, view_layer, id_root, &obact->id); - /* Cleanup. */ - BKE_main_id_clear_newpoins(bmain); - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - } - /* TODO: probably more cases where we want to do automated smart things in the future! */ - else { - /* For now, remapp all local usages of linked ID to local override one here. */ - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, true); - success = (BKE_lib_override_library_create_from_id(bmain, &obact->id, true) != NULL); - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + /* 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, obact); } + 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; @@ -2467,10 +2369,40 @@ static bool make_override_library_poll(bContext *C) Object *obact = CTX_data_active_object(C); /* Object must be directly linked to be overridable. */ - return (BKE_lib_override_library_is_enabled() && ED_operator_objectmode(C) && obact != NULL && - ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) || - (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && - ID_IS_LINKED(obact->instance_collection)))); + return (ED_operator_objectmode(C) && obact != NULL && + (ID_IS_LINKED(obact) || (obact->instance_collection != NULL && + ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)))); +} + +static const EnumPropertyItem *make_override_collections_of_linked_object_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem item_tmp = {0}, *item = NULL; + int totitem = 0; + + Object *object = ED_object_active_context(C); + Main *bmain = CTX_data_main(C); + + if (!object || !ID_IS_LINKED(object)) { + return DummyRNA_DEFAULT_items; + } + + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + /* Only check for directly linked collections. */ + if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0) { + continue; + } + if (BKE_collection_has_object_recursive(collection, object)) { + item_tmp.identifier = item_tmp.name = collection->id.name + 2; + item_tmp.value = *((int *)&collection->id.session_uuid); + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } void OBJECT_OT_make_override_library(wmOperatorType *ot) @@ -2491,12 +2423,13 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot) /* properties */ PropertyRNA *prop; prop = RNA_def_enum(ot->srna, - "object", + "collection", DummyRNA_DEFAULT_items, - 0, - "Override Object", - "Name of lib-linked/collection object to make an override from"); - RNA_def_enum_funcs(prop, proxy_collection_object_itemf); + MAIN_ID_SESSION_UUID_UNSET, + "Override Collection", + "Name of directly linked collection containing the selected object, to make " + "an override from"); + RNA_def_enum_funcs(prop, make_override_collections_of_linked_object_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } |