diff options
Diffstat (limited to 'source/blender/editors/object/object_relations.c')
-rw-r--r-- | source/blender/editors/object/object_relations.c | 900 |
1 files changed, 459 insertions, 441 deletions
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 8abbb535981..f2e996237cf 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -63,21 +63,23 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_camera.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_constraint.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_fcurve.h" #include "BKE_idprop.h" #include "BKE_lamp.h" #include "BKE_lattice.h" +#include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" +#include "BKE_lightprobe.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" @@ -86,12 +88,14 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_report.h" -#include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_speaker.h" #include "BKE_texture.h" #include "BKE_editmesh.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "WM_api.h" #include "WM_types.h" @@ -123,6 +127,8 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ViewLayer *view_layer = CTX_data_view_layer(C); Object *obedit = CTX_data_edit_object(C); BMVert *eve; BMIter iter; @@ -142,7 +148,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) EDBM_mesh_load(bmain, obedit); EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true); - DAG_id_tag_update(obedit->data, 0); + DEG_id_tag_update(obedit->data, 0); em = me->edit_btmesh; @@ -151,7 +157,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) /* derivedMesh might be needed for solving parenting, * so re-create it here */ - makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX, false); + makeDerivedMesh(depsgraph, scene, obedit, em, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX, false); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { @@ -230,7 +236,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob != obedit) { - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); par = obedit->parent; if (BKE_object_parent_loop_check(par, ob)) { @@ -239,7 +245,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) else { Object workob; - ob->parent = BASACT->object; + ob->parent = BASACT(view_layer)->object; if (v3) { ob->partype = PARVERT3; ob->par1 = v1 - 1; @@ -247,7 +253,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) ob->par3 = v3 - 1; /* inverse parent matrix */ - BKE_object_workob_calc_parent(scene, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); } else { @@ -255,7 +261,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) ob->par1 = v1 - 1; /* inverse parent matrix */ - BKE_object_workob_calc_parent(scene, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); } } @@ -263,7 +269,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT, NULL); @@ -322,7 +328,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event) } else { /* error.. cannot continue */ - BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or group"); + BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or collection"); return OPERATOR_CANCELLED; } @@ -332,44 +338,42 @@ static int make_proxy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Object *ob, *gob = ED_object_active_context(C); - GroupObject *go; Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); if (gob->dup_group != NULL) { - go = BLI_findlink(&gob->dup_group->gobject, RNA_enum_get(op->ptr, "object")); - ob = go->ob; + const ListBase dup_group_objects = BKE_collection_object_cache_get(gob->dup_group); + Base *base = BLI_findlink(&dup_group_objects, RNA_enum_get(op->ptr, "object")); + ob = base->object; } else { ob = gob; - gob = NULL; } if (ob) { Object *newob; - Base *newbase, *oldbase = BASACT; char name[MAX_ID_NAME + 4]; BLI_snprintf(name, sizeof(name), "%s_proxy", ((ID *)(gob ? gob : ob))->name + 2); /* Add new object for the proxy */ - newob = BKE_object_add(bmain, scene, OB_EMPTY, name); + newob = BKE_object_add_from(bmain, scene, view_layer, OB_EMPTY, name, gob ? gob : ob); /* set layers OK */ - newbase = BASACT; /* BKE_object_add sets active... */ - newbase->lay = oldbase->lay; - newob->lay = newbase->lay; - - /* remove base, leave user count of object, it gets linked in BKE_object_make_proxy */ - if (gob == NULL) { - BKE_scene_base_unlink(scene, oldbase); - MEM_freeN(oldbase); - } - BKE_object_make_proxy(newob, ob, gob); + /* Set back pointer immediately so dependency graph knows that this is + * is a proxy and will act accordingly. Otherwise correctness of graph + * will depend on order of bases. + * + * TODO(sergey): We really need to get rid of this bi-directional links + * in proxies with something like static overrides. + */ + newob->proxy->proxy_from = newob; + /* depsgraph flushes are needed for the new data */ - DAG_relations_tag_update(bmain); - DAG_id_tag_update(&newob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&newob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob); } else { @@ -381,24 +385,25 @@ static int make_proxy_exec(bContext *C, wmOperator *op) } /* Generic itemf's for operators that take library args */ -static const EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *proxy_collection_object_itemf(bContext *C, PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), bool *r_free) { EnumPropertyItem item_tmp = {0}, *item = NULL; int totitem = 0; int i = 0; Object *ob = ED_object_active_context(C); - GroupObject *go; if (!ob || !ob->dup_group) return DummyRNA_DEFAULT_items; /* find the object to affect */ - for (go = ob->dup_group->gobject.first; go; go = go->next) { - item_tmp.identifier = item_tmp.name = go->ob->id.name + 2; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(ob->dup_group, object) + { + item_tmp.identifier = item_tmp.name = object->id.name + 2; item_tmp.value = i++; RNA_enum_item_add(&item, &totitem, &item_tmp); } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -426,8 +431,8 @@ void OBJECT_OT_proxy_make(wmOperatorType *ot) /* properties */ /* XXX, relies on hard coded ID at the moment */ prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object", - "Name of lib-linked/grouped object to make a proxy for"); - RNA_def_enum_funcs(prop, proxy_group_object_itemf); + "Name of lib-linked/collection object to make a proxy for"); + RNA_def_enum_funcs(prop, proxy_collection_object_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } @@ -524,7 +529,7 @@ void ED_object_parent_clear(Object *ob, const int type) /* Always clear parentinv matrix for sake of consistency, see T41950. */ unit_m4(ob->parentinv); - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } /* note, poll should check for editable scene */ @@ -539,7 +544,7 @@ static int parent_clear_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); return OPERATOR_FINISHED; @@ -607,13 +612,15 @@ EnumPropertyItem prop_make_parent_types[] = { {0, NULL, 0, NULL, NULL} }; -bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par, +bool ED_object_parent_set(ReportList *reports, const bContext *C, Scene *scene, Object *ob, Object *par, int partype, const bool xmirror, const bool keep_transform, const int vert_par[3]) { + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); bPoseChannel *pchan = NULL; const bool pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); - DAG_id_tag_update(&par->id, OB_RECALC_OB); + DEG_id_tag_update(&par->id, OB_RECALC_OB); /* preconditions */ if (partype == PAR_FOLLOW || partype == PAR_PATH_CONST) { @@ -624,7 +631,7 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object if ((cu->flag & CU_PATH) == 0) { cu->flag |= CU_PATH | CU_FOLLOW; - BKE_displist_make_curveTypes(scene, par, 0); /* force creation of path data */ + BKE_displist_make_curveTypes(depsgraph, scene, par, 0); /* force creation of path data */ } else { cu->flag |= CU_FOLLOW; @@ -710,7 +717,7 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object ((CurveModifierData *)md)->object = par; } if (par->curve_cache && par->curve_cache->path == NULL) { - DAG_id_tag_update(&par->id, OB_RECALC_DATA); + DEG_id_tag_update(&par->id, OB_RECALC_DATA); } } break; @@ -766,34 +773,36 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object data = con->data; data->tar = par; - BKE_constraint_target_matrix_get(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); + 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); } else if (pararm && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) { - if (partype == PAR_ARMATURE_NAME) - ED_object_vgroup_calc_from_armature(reports, scene, ob, par, ARM_GROUPS_NAME, false); - else if (partype == PAR_ARMATURE_ENVELOPE) - ED_object_vgroup_calc_from_armature(reports, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror); + 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, scene, ob, par, ARM_GROUPS_AUTO, xmirror); + 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(scene, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); } else { /* calculate inverse parent matrix */ - BKE_object_workob_calc_parent(scene, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); } - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); } } @@ -864,7 +873,7 @@ static int parent_set_exec(bContext *C, wmOperator *op) parent_set_vert_find(tree, ob, vert_par, is_tri); } - if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) { + if (!ED_object_parent_set(op->reports, C, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) { ok = false; break; } @@ -879,7 +888,7 @@ static int parent_set_exec(bContext *C, wmOperator *op) if (!ok) return OPERATOR_CANCELLED; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); @@ -963,7 +972,7 @@ static void parent_set_ui(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* Main auto-draw call. */ - uiDefAutoButsRNA(layout, &ptr, parent_set_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, parent_set_draw_check_prop, UI_BUT_LABEL_ALIGN_NONE, false); } void OBJECT_OT_parent_set(wmOperatorType *ot) @@ -996,7 +1005,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Object *par = ED_object_active_context(C); - DAG_id_tag_update(&par->id, OB_RECALC_OB); + DEG_id_tag_update(&par->id, OB_RECALC_OB); /* context iterator */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) @@ -1011,7 +1020,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op) memset(ob->loc, 0, 3 * sizeof(float)); /* set recalc flags */ - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); /* set parenting type for object - object only... */ ob->parent = par; @@ -1021,7 +1030,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; @@ -1047,6 +1056,7 @@ void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot) static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op)) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) @@ -1054,9 +1064,9 @@ static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op)) if (ob->parent) { if (ob->partype & PARSLOW) { ob->partype -= PARSLOW; - BKE_object_where_is_calc(scene, ob); + BKE_object_where_is_calc(depsgraph, scene, ob); ob->partype |= PARSLOW; - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } } } @@ -1094,7 +1104,7 @@ static int object_slow_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) if (ob->parent) ob->partype |= PARSLOW; - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } CTX_DATA_END; @@ -1148,7 +1158,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) /* remove track-object for old track */ ob->track = NULL; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* also remove all tracking constraints */ for (con = ob->constraints.last; con; con = pcon) { @@ -1162,7 +1172,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; @@ -1222,7 +1232,7 @@ static int track_set_exec(bContext *C, wmOperator *op) data = con->data; data->tar = obact; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { @@ -1245,7 +1255,7 @@ static int track_set_exec(bContext *C, wmOperator *op) data = con->data; data->tar = obact; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { @@ -1269,7 +1279,7 @@ static int track_set_exec(bContext *C, wmOperator *op) data = con->data; data->tar = obact; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { @@ -1283,7 +1293,7 @@ static int track_set_exec(bContext *C, wmOperator *op) } } - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; @@ -1309,119 +1319,6 @@ void OBJECT_OT_track_set(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", ""); } -/************************** Move to Layer Operator *****************************/ - -static unsigned int move_to_layer_init(bContext *C, wmOperator *op) -{ - int values[20], a; - unsigned int lay = 0; - - if (!RNA_struct_property_is_set(op->ptr, "layers")) { - /* note: layers are set in bases, library objects work for this */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - lay |= base->lay; - } - CTX_DATA_END; - - for (a = 0; a < 20; a++) - values[a] = (lay & (1 << a)) != 0; - - RNA_boolean_set_array(op->ptr, "layers", values); - } - else { - RNA_boolean_get_array(op->ptr, "layers", values); - - for (a = 0; a < 20; a++) - if (values[a]) - lay |= (1 << a); - } - - return lay; -} - -static int move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - View3D *v3d = CTX_wm_view3d(C); - if (v3d && v3d->localvd) { - return WM_operator_confirm_message(C, op, "Move out of Local View"); - } - else { - move_to_layer_init(C, op); - return WM_operator_props_popup(C, op, event); - } -} - -static int move_to_layer_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - unsigned int lay, local; - /* bool is_lamp = false; */ /* UNUSED */ - - lay = move_to_layer_init(C, op); - lay &= 0xFFFFFF; - - if (lay == 0) return OPERATOR_CANCELLED; - - if (v3d && v3d->localvd) { - /* now we can move out of localview. */ - /* note: layers are set in bases, library objects work for this */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - lay = base->lay & ~v3d->lay; - base->lay = lay; - base->object->lay = lay; - base->object->flag &= ~SELECT; - base->flag &= ~SELECT; - /* if (base->object->type == OB_LAMP) is_lamp = true; */ - } - CTX_DATA_END; - } - else { - /* normal non localview operation */ - /* note: layers are set in bases, library objects work for this */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - /* upper byte is used for local view */ - local = base->lay & 0xFF000000; - base->lay = lay + local; - base->object->lay = base->lay; - /* if (base->object->type == OB_LAMP) is_lamp = true; */ - } - CTX_DATA_END; - } - - /* warning, active object may be hidden now */ - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); - - DAG_relations_tag_update(bmain); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_move_to_layer(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Move to Layer"; - ot->description = "Move the object to different layers"; - ot->idname = "OBJECT_OT_move_to_layer"; - - /* api callbacks */ - ot->invoke = move_to_layer_invoke; - ot->exec = move_to_layer_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", ""); -} - /************************** Link to Scene Operator *****************************/ #if 0 @@ -1444,23 +1341,10 @@ static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr)) } #endif -Base *ED_object_scene_link(Scene *scene, Object *ob) -{ - Base *base; - - if (BKE_scene_base_find(scene, ob)) { - return NULL; - } - - base = BKE_scene_base_add(scene, ob); - id_us_plus(&ob->id); - - return base; -} - static int make_links_scene_exec(bContext *C, wmOperator *op) { - Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene")); + Main *bmain = CTX_data_main(C); + Scene *scene_to = BLI_findlink(&bmain->scene, RNA_enum_get(op->ptr, "scene")); if (scene_to == NULL) { BKE_report(op->reports, RPT_ERROR, "Could not find scene"); @@ -1477,9 +1361,10 @@ static int make_links_scene_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + Collection *collection_to = BKE_collection_master(scene_to); CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - ED_object_scene_link(scene_to, base->object); + BKE_collection_object_add(bmain, collection_to, base->object); } CTX_DATA_END; @@ -1495,7 +1380,7 @@ enum { MAKE_LINKS_MATERIALS = 2, MAKE_LINKS_ANIMDATA = 3, MAKE_LINKS_GROUP = 4, - MAKE_LINKS_DUPLIGROUP = 5, + MAKE_LINKS_DUPLICOLLECTION = 5, MAKE_LINKS_MODIFIERS = 6, MAKE_LINKS_FONTS = 7, }; @@ -1516,7 +1401,7 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst break; case MAKE_LINKS_ANIMDATA: case MAKE_LINKS_GROUP: - case MAKE_LINKS_DUPLIGROUP: + case MAKE_LINKS_DUPLICOLLECTION: return true; case MAKE_LINKS_MODIFIERS: if (!ELEM(OB_EMPTY, ob_src->type, ob_dst->type)) { @@ -1534,23 +1419,23 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst static int make_links_data_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + Main *bmain = CTX_data_main(C); const int type = RNA_enum_get(op->ptr, "type"); Object *ob_src; ID *obdata_id; int a; - /* group */ - LinkNode *ob_groups = NULL; + /* collection */ + LinkNode *ob_collections = NULL; bool is_cycle = false; bool is_lib = false; ob_src = ED_object_active_context(C); - /* avoid searching all groups in source object each time */ + /* avoid searching all collections in source object each time */ if (type == MAKE_LINKS_GROUP) { - ob_groups = BKE_object_groups(bmain, ob_src); + ob_collections = BKE_object_groups(bmain, ob_src); } CTX_DATA_BEGIN (C, Base *, base_dst, selected_editable_bases) @@ -1572,7 +1457,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) /* if amount of material indices changed: */ test_object_materials(bmain, ob_dst, ob_dst->data); - DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); break; case MAKE_LINKS_MATERIALS: /* new approach, using functions from kernel */ @@ -1580,30 +1465,30 @@ static int make_links_data_exec(bContext *C, wmOperator *op) Material *ma = give_current_material(ob_src, a + 1); assign_material(bmain, ob_dst, ma, a + 1, BKE_MAT_ASSIGN_USERPREF); /* also works with ma==NULL */ } - DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); break; case MAKE_LINKS_ANIMDATA: - BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, false); + BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, false, true); if (ob_dst->data && ob_src->data) { if (ID_IS_LINKED(obdata_id)) { is_lib = true; break; } - BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, false); + BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, false, true); } - DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; case MAKE_LINKS_GROUP: { - LinkNode *group_node; + LinkNode *collection_node; - /* first clear groups */ - BKE_object_groups_clear(bmain, scene, base_dst, ob_dst); + /* first clear collections */ + BKE_object_groups_clear(bmain, ob_dst); - /* now add in the groups from the link nodes */ - for (group_node = ob_groups; group_node; group_node = group_node->next) { - if (ob_dst->dup_group != group_node->link) { - BKE_group_object_add(group_node->link, ob_dst, scene, base_dst); + /* now add in the collections from the link nodes */ + for (collection_node = ob_collections; collection_node; collection_node = collection_node->next) { + if (ob_dst->dup_group != collection_node->link) { + BKE_collection_object_add(bmain, collection_node->link, ob_dst); } else { is_cycle = true; @@ -1611,16 +1496,16 @@ static int make_links_data_exec(bContext *C, wmOperator *op) } break; } - case MAKE_LINKS_DUPLIGROUP: + case MAKE_LINKS_DUPLICOLLECTION: ob_dst->dup_group = ob_src->dup_group; if (ob_dst->dup_group) { id_us_plus(&ob_dst->dup_group->id); - ob_dst->transflag |= OB_DUPLIGROUP; + ob_dst->transflag |= OB_DUPLICOLLECTION; } break; case MAKE_LINKS_MODIFIERS: - BKE_object_link_modifiers(ob_dst, ob_src); - DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + BKE_object_link_modifiers(scene, ob_dst, ob_src); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; case MAKE_LINKS_FONTS: { @@ -1649,7 +1534,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) cu_dst->vfontbi = cu_src->vfontbi; id_us_plus((ID *)cu_dst->vfontbi); - DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; } } @@ -1659,12 +1544,12 @@ static int make_links_data_exec(bContext *C, wmOperator *op) CTX_DATA_END; if (type == MAKE_LINKS_GROUP) { - if (ob_groups) { - BLI_linklist_free(ob_groups, NULL); + if (ob_collections) { + BLI_linklist_free(ob_collections, NULL); } if (is_cycle) { - BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected"); + BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected"); } } @@ -1672,7 +1557,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_WARNING, "Skipped editing library object data"); } - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, CTX_wm_view3d(C)); WM_event_add_notifier(C, NC_OBJECT, NULL); @@ -1712,7 +1597,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) {MAKE_LINKS_MATERIALS, "MATERIAL", 0, "Materials", ""}, {MAKE_LINKS_ANIMDATA, "ANIMATION", 0, "Animation Data", ""}, {MAKE_LINKS_GROUP, "GROUPS", 0, "Group", ""}, - {MAKE_LINKS_DUPLIGROUP, "DUPLIGROUP", 0, "DupliGroup", ""}, + {MAKE_LINKS_DUPLICOLLECTION, "DUPLICOLLECTION", 0, "DupliGroup", ""}, {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Modifiers", ""}, {MAKE_LINKS_FONTS, "FONTS", 0, "Fonts", ""}, {0, NULL, 0, NULL, NULL}}; @@ -1736,101 +1621,120 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) /**************************** Make Single User ********************************/ -/* Warning, sets ID->newid pointers of objects and groups, but does not clear them. */ -static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups) +static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob) { - Base *base; - Object *ob, *obn; - Group *group, *groupn; - GroupObject *go; + /* base gets copy of object */ + Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); - clear_sca_new_poins(); /* BGE logic */ + /* remap gpencil parenting */ - /* duplicate (must set newid) */ - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; + if (scene->gpd) { + bGPdata *gpd = scene->gpd; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->parent == ob) { + gpl->parent = obn; + } + } + } + + id_us_plus(&obn->id); + id_us_min(&ob->id); + return obn; +} - if ((base->flag & flag) == flag) { +static void libblock_relink_collection(Collection *collection) +{ + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + BKE_libblock_relink_to_newid(&cob->ob->id); + } + + for (CollectionChild *child = collection->children.first; child; child = child->next) { + libblock_relink_collection(child->collection); + } +} + +static void single_object_users_collection(Main *bmain, Scene *scene, Collection *collection, const int flag, const bool copy_collections) +{ + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Object *ob = cob->ob; + /* an object may be in more than one collection */ + if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) { if (!ID_IS_LINKED(ob) && ob->id.us > 1) { - /* base gets copy of object */ - base->object = obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); + cob->ob = single_object_users_object(bmain, scene, cob->ob); + } + } + } - if (copy_groups) { - if (ob->flag & OB_FROMGROUP) { - obn->flag |= OB_FROMGROUP; - } - } - else { - /* copy already clears */ - } - /* remap gpencil parenting */ + for (CollectionChild *child = collection->children.first; child; child = child->next) { + single_object_users_collection(bmain, scene, child->collection, flag, copy_collections); + } +} - if (scene->gpd) { - bGPdata *gpd = scene->gpd; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->parent == ob) { - gpl->parent = obn; - } - } - } +/* Warning, sets ID->newid pointers of objects and collections, but does not clear them. */ +static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_collections) +{ + Collection *collection, *collectionn; - base->flag = obn->flag; + /* duplicate all the objects of the scene */ + Collection *master_collection = BKE_collection_master(scene); + single_object_users_collection(bmain, scene, master_collection, flag, copy_collections); - id_us_min(&ob->id); - } + /* loop over ViewLayers and assign the pointers accordingly */ + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + ID_NEW_REMAP(base->object); } } - /* duplicate groups that consist entirely of duplicated objects */ - for (group = bmain->group.first; group; group = group->id.next) { - if (copy_groups && group->gobject.first) { + /* duplicate collections that consist entirely of duplicated objects */ + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + if (copy_collections) { bool all_duplicated = true; + bool any_duplicated = false; - for (go = group->gobject.first; go; go = go->next) { - if (!(go->ob && (go->ob->id.newid))) { + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + any_duplicated = true; + if (cob->ob->id.newid == NULL) { all_duplicated = false; break; } } - if (all_duplicated) { - groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group)); + if (any_duplicated && all_duplicated) { + // TODO: test if this works, with child collections .. + collectionn = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection)); - for (go = groupn->gobject.first; go; go = go->next) { - go->ob = (Object *)go->ob->id.newid; + for (CollectionObject *cob = collectionn->gobject.first; cob; cob = cob->next) { + cob->ob = (Object *)cob->ob->id.newid; } } } } - /* group pointers in scene */ + /* collection pointers in scene */ BKE_scene_groups_relink(scene); ID_NEW_REMAP(scene->camera); if (v3d) ID_NEW_REMAP(v3d->camera); - /* object and group pointers */ - for (base = FIRSTBASE; base; base = base->next) { - BKE_libblock_relink_to_newid(&base->object->id); - } - - set_sca_new_poins(); + /* object and collection pointers */ + libblock_relink_collection(master_collection); } /* not an especially efficient function, only added so the single user * button can be functional.*/ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob) { - Base *base; - const bool copy_groups = false; - - for (base = FIRSTBASE; base; base = base->next) { - if (base->object == ob) base->flag |= OB_DONE; - else base->flag &= ~OB_DONE; + FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter) + { + ob_iter->flag &= ~OB_DONE; } + FOREACH_SCENE_OBJECT_END; - single_object_users(bmain, scene, NULL, OB_DONE, copy_groups); + /* tag only the one object */ + ob->flag |= OB_DONE; + single_object_users(bmain, scene, NULL, OB_DONE, false); BKE_main_id_clear_newpoins(bmain); } @@ -1855,34 +1759,26 @@ static void new_id_matar(Main *bmain, Material **matar, const int totcol) } } -static void single_obdata_users(Main *bmain, Scene *scene, const int flag) +static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag) { - Object *ob; Lamp *la; Curve *cu; /* Camera *cam; */ - Base *base; Mesh *me; Lattice *lat; ID *id; - int a; - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; - if (!ID_IS_LINKED(ob) && (base->flag & flag) == flag) { + FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob) + { + if (!ID_IS_LINKED(ob)) { id = ob->data; if (id && id->us > 1 && !ID_IS_LINKED(id)) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); switch (ob->type) { case OB_LAMP: ob->data = la = ID_NEW_SET(ob->data, BKE_lamp_copy(bmain, ob->data)); - for (a = 0; a < MAX_MTEX; a++) { - if (la->mtex[a]) { - ID_NEW_REMAP(la->mtex[a]->object); - } - } break; case OB_CAMERA: ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data)); @@ -1911,16 +1807,22 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) BKE_animdata_copy_id_action(bmain, (ID *)lat->key, false); break; case OB_ARMATURE: - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data)); BKE_pose_rebuild(ob, ob->data); break; case OB_SPEAKER: ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data)); break; + case OB_LIGHTPROBE: + ob->data = ID_NEW_SET(ob->data, BKE_lightprobe_copy(bmain, ob->data)); + break; default: - if (G.debug & G_DEBUG) - printf("ERROR %s: can't copy %s\n", __func__, id->name); + printf("ERROR %s: can't copy %s\n", __func__, id->name); + BLI_assert(!"This should never happen."); + + /* We need to end the FOREACH_OBJECT_FLAG_BEGIN iterator to prevent memory leak. */ + BKE_scene_objects_iterator_end(&iter_macro); return; } @@ -1935,6 +1837,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) } } } + FOREACH_OBJECT_FLAG_END; me = bmain->mesh.first; while (me) { @@ -1943,31 +1846,26 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) } } -static void single_object_action_users(Main *bmain, Scene *scene, const int flag) +static void single_object_action_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag) { - Object *ob; - Base *base; - - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; - if (!ID_IS_LINKED(ob) && (flag == 0 || (base->flag & SELECT)) ) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob) + { + if (!ID_IS_LINKED(ob)) { + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); BKE_animdata_copy_id_action(bmain, &ob->id, false); } } + FOREACH_OBJECT_FLAG_END; } -static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bool do_textures) +static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag) { - Object *ob; - Base *base; Material *ma, *man; - Tex *tex; - int a, b; + int a; - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; - if (!ID_IS_LINKED(ob) && (flag == 0 || (base->flag & SELECT)) ) { + FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob) + { + if (!ID_IS_LINKED(ob)) { for (a = 1; a <= ob->totcol; a++) { ma = give_current_material(ob, a); if (ma) { @@ -1979,84 +1877,12 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo man->id.us = 0; assign_material(bmain, ob, man, a, BKE_MAT_ASSIGN_USERPREF); - - if (do_textures) { - for (b = 0; b < MAX_MTEX; b++) { - if (ma->mtex[b] && (tex = ma->mtex[b]->tex)) { - if (tex->id.us > 1) { - id_us_min(&tex->id); - tex = BKE_texture_copy(bmain, tex); - BKE_animdata_copy_id_action(bmain, &tex->id, false); - man->mtex[b]->tex = tex; - } - } - } - } } } } } } -} - -static void do_single_tex_user(Main *bmain, Tex **from) -{ - Tex *tex, *texn; - - tex = *from; - if (tex == NULL) return; - - if (tex->id.newid) { - *from = (Tex *)tex->id.newid; - id_us_plus(tex->id.newid); - id_us_min(&tex->id); - } - else if (tex->id.us > 1) { - texn = ID_NEW_SET(tex, BKE_texture_copy(bmain, tex)); - BKE_animdata_copy_id_action(bmain, &texn->id, false); - tex->id.newid = (ID *)texn; - id_us_min(&tex->id); - *from = texn; - } -} - -static void single_tex_users_expand(Main *bmain) -{ - /* only when 'parent' blocks are LIB_TAG_NEW */ - Material *ma; - Lamp *la; - World *wo; - int b; - - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->id.tag & LIB_TAG_NEW) { - for (b = 0; b < MAX_MTEX; b++) { - if (ma->mtex[b] && ma->mtex[b]->tex) { - do_single_tex_user(bmain, &(ma->mtex[b]->tex)); - } - } - } - } - - for (la = bmain->lamp.first; la; la = la->id.next) { - if (la->id.tag & LIB_TAG_NEW) { - for (b = 0; b < MAX_MTEX; b++) { - if (la->mtex[b] && la->mtex[b]->tex) { - do_single_tex_user(bmain, &(la->mtex[b]->tex)); - } - } - } - } - - for (wo = bmain->world.first; wo; wo = wo->id.next) { - if (wo->id.tag & LIB_TAG_NEW) { - for (b = 0; b < MAX_MTEX; b++) { - if (wo->mtex[b] && wo->mtex[b]->tex) { - do_single_tex_user(bmain, &(wo->mtex[b]->tex)); - } - } - } - } + FOREACH_OBJECT_FLAG_END; } static void single_mat_users_expand(Main *bmain) @@ -2066,8 +1892,6 @@ static void single_mat_users_expand(Main *bmain) Mesh *me; Curve *cu; MetaBall *mb; - Material *ma; - int a; for (ob = bmain->object.first; ob; ob = ob->id.next) if (ob->id.tag & LIB_TAG_NEW) @@ -2084,25 +1908,17 @@ static void single_mat_users_expand(Main *bmain) for (mb = bmain->mball.first; mb; mb = mb->id.next) if (mb->id.tag & LIB_TAG_NEW) new_id_matar(bmain, mb->mat, mb->totcol); - - /* material imats */ - for (ma = bmain->mat.first; ma; ma = ma->id.next) - if (ma->id.tag & LIB_TAG_NEW) - for (a = 0; a < MAX_MTEX; a++) - if (ma->mtex[a]) - ID_NEW_REMAP(ma->mtex[a]->object); } /* used for copying scenes */ -void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_groups) +void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_collections) { - single_object_users(bmain, scene, NULL, 0, copy_groups); + single_object_users(bmain, scene, NULL, 0, copy_collections); if (full) { - single_obdata_users(bmain, scene, 0); - single_object_action_users(bmain, scene, 0); + single_obdata_users(bmain, scene, NULL, 0); + single_object_action_users(bmain, scene, NULL, 0); single_mat_users_expand(bmain); - single_tex_users_expand(bmain); } /* Relink nodetrees' pointers that have been duplicated. */ @@ -2121,12 +1937,13 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo { IDP_RelinkProperty(scene->id.properties); - for (Base *base = scene->base.first; base; base = base->next) { - Object *ob = base->object; + FOREACH_SCENE_OBJECT_BEGIN(scene, ob) + { if (!ID_IS_LINKED(ob)) { IDP_RelinkProperty(ob->id.properties); } } + FOREACH_SCENE_OBJECT_END; if (scene->nodetree) { IDP_RelinkProperty(scene->nodetree->id.properties); @@ -2148,7 +1965,7 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo } } BKE_main_id_clear_newpoins(bmain); - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } /******************************* Make Local ***********************************/ @@ -2215,7 +2032,7 @@ static void tag_localizable_objects(bContext *C, const int mode) * Instance indirectly referenced zero user objects, * otherwise they're lost on reload, see T40595. */ -static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene) +static bool make_local_all__instance_indirect_unused(Main *bmain, ViewLayer *view_layer, Collection *collection) { Object *ob; bool changed = false; @@ -2226,10 +2043,11 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene) id_us_plus(&ob->id); - base = BKE_scene_base_add(scene, ob); - base->flag |= SELECT; - base->object->flag = base->flag; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + BKE_collection_object_add(bmain, collection, ob); + base = BKE_view_layer_base_find(view_layer, ob); + base->flag |= BASE_SELECTED; + BKE_scene_object_base_flag_sync_from_base(base); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); changed = true; } @@ -2287,33 +2105,28 @@ static void make_local_material_tag(Material *ma) make_local_animdata_tag(BKE_animdata_from_id(&ma->id)); /* About nodetrees: root one is made local together with material, others we keep linked for now... */ - - for (int a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a] && ma->mtex[a]->tex) { - ma->mtex[a]->tex->id.tag &= ~LIB_TAG_PRE_EXISTING; - } - } } } static int make_local_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); ParticleSystem *psys; Material *ma, ***matarar; - Lamp *la; const int mode = RNA_enum_get(op->ptr, "type"); int a; /* Note: we (ab)use LIB_TAG_PRE_EXISTING to cherry pick which ID to make local... */ if (mode == MAKE_LOCAL_ALL) { + ViewLayer *view_layer = CTX_data_view_layer(C); + Collection *collection = CTX_data_collection(C); + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - /* de-select so the user can differentiate newly instanced from existing objects */ - BKE_scene_base_deselect_all(scene); + /* De-select so the user can differentiate newly instanced from existing objects. */ + BKE_view_layer_base_deselect_all(view_layer); - if (make_local_all__instance_indirect_unused(bmain, scene)) { + if (make_local_all__instance_indirect_unused(bmain, view_layer, collection)) { BKE_report(op->reports, RPT_INFO, "Orphan library objects added to the current scene to avoid loss"); } } @@ -2350,16 +2163,6 @@ static int make_local_exec(bContext *C, wmOperator *op) } } } - - if (ob->type == OB_LAMP) { - BLI_assert(ob->data != NULL); - la = ob->data; - for (a = 0; a < MAX_MTEX; a++) { - if (la->mtex[a] && la->mtex[a]->tex) { - la->id.tag &= ~LIB_TAG_PRE_EXISTING; - } - } - } } if (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL) && ob->data != NULL) { @@ -2404,6 +2207,220 @@ void OBJECT_OT_make_local(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); } + +static void make_override_static_tag_object(Object *obact, Object *ob) +{ + 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; + } + } + } + } + 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); + } +} + +/* Set the object to override. */ +static int make_override_static_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Scene *scene = CTX_data_scene(C); + Object *obact = ED_object_active_context(C); + + /* Sanity checks. */ + if (!scene || ID_IS_LINKED(scene) || !obact) { + return OPERATOR_CANCELLED; + } + + /* Get object to work on - use a menu if we need to... */ + if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { + /* Gives menu with list of objects in group. */ + WM_enum_search_invoke(C, op, event); + return OPERATOR_CANCELLED; + } + else if (ID_IS_LINKED(obact)) { + uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); + uiLayout *layout = UI_popup_menu_layout(pup); + + /* Create operator menu item with relevant properties filled in. */ + PointerRNA opptr_dummy; + uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL, + WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy); + + /* Present the menu and be done... */ + UI_popup_menu_end(C, pup); + + /* 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 static override for a referenced object or collection"); + return OPERATOR_CANCELLED; + } + +} + +static int make_override_static_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Object *obact = CTX_data_active_object(C); + + bool success = false; + + if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { + const ListBase dup_collection_objects = BKE_collection_object_cache_get(obact->dup_group); + Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object")); + Object *obcollection = obact; + obact = base->object; + Collection *collection = obcollection->dup_group; + + /* First, we make a static override of the linked collection itself. */ + collection->id.tag |= LIB_TAG_DOIT; + + /* Then, we make static 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; + } + } + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + success = BKE_override_static_create_from_tag(bmain); + + /* Intantiate 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; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(new_collection, new_ob) + { + if (new_ob != NULL && new_ob->id.override_static != NULL) { + if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) { + BKE_collection_object_add_from(bmain, scene, obcollection, new_ob); + DEG_id_tag_update_ex(bmain, &new_ob->id, DEG_TAG_TRANSFORM | DEG_TAG_BASE_FLAGS_UPDATE); + } + /* parent to 'collection' empty */ + if (new_ob->parent == NULL) { + new_ob->parent = obcollection; + } + if (new_ob == (Object *)obact->id.newid) { + BKE_view_layer_base_select(view_layer, base); + } + else { + /* Disable auto-override tags for non-active objects, will help with performaces... */ + new_ob->id.override_static->flag &= ~STATICOVERRIDE_AUTO; + } + /* We still want to store all objects' current override status (i.e. change of parent). */ + BKE_override_static_operations_create(&new_ob->id, true); + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + /* obcollection is no more duplicollection-ing, it merely parents whole collection of overriding instantiated objects. */ + obcollection->dup_group = NULL; + + /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */ + + DEG_id_tag_update(&scene->id, 0); + + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false); + } + /* 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->object.first; ob != NULL; ob = ob->id.next) { + make_override_static_tag_object(obact, ob); + } + + success = BKE_override_static_create_from_tag(bmain); + + /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */ + + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false); + } + /* TODO: probably more cases where we want to do automated smart things in the future! */ + else { + success = (BKE_override_static_create_from_id(bmain, &obact->id) != NULL); + } + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +static int make_override_static_poll(bContext *C) +{ + Object *obact = CTX_data_active_object(C); + + /* Object must be directly linked to be overridable. */ + return (ED_operator_objectmode(C) && obact != NULL && + ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) || + (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)))); +} + +void OBJECT_OT_make_override_static(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Make Static Override"; + ot->description = "Make local override of this library linked data-block"; + ot->idname = "OBJECT_OT_make_override_static"; + + /* api callbacks */ + ot->invoke = make_override_static_invoke; + ot->exec = make_override_static_exec; + ot->poll = make_override_static_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop; + prop = RNA_def_enum(ot->srna, "object", 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); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; +} + enum { MAKE_SINGLE_USER_ALL = 1, MAKE_SINGLE_USER_SELECTED = 2, @@ -2413,32 +2430,35 @@ static int make_single_user_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); View3D *v3d = CTX_wm_view3d(C); /* ok if this is NULL */ const int flag = (RNA_enum_get(op->ptr, "type") == MAKE_SINGLE_USER_SELECTED) ? SELECT : 0; - const bool copy_groups = false; + const bool copy_collections = false; bool update_deps = false; if (RNA_boolean_get(op->ptr, "object")) { - single_object_users(bmain, scene, v3d, flag, copy_groups); + if (flag == SELECT) { + BKE_view_layer_selected_objects_tag(view_layer, OB_DONE); + single_object_users(bmain, scene, v3d, OB_DONE, copy_collections); + } + else { + single_object_users(bmain, scene, v3d, 0, copy_collections); + } /* needed since object relationships may have changed */ update_deps = true; } if (RNA_boolean_get(op->ptr, "obdata")) { - single_obdata_users(bmain, scene, flag); + single_obdata_users(bmain, scene, view_layer, flag); } if (RNA_boolean_get(op->ptr, "material")) { - single_mat_users(bmain, scene, flag, RNA_boolean_get(op->ptr, "texture")); + single_mat_users(bmain, scene, view_layer, flag); } -#if 0 /* can't do this separate from materials */ - if (RNA_boolean_get(op->ptr, "texture")) - single_mat_users(scene, flag, true); -#endif if (RNA_boolean_get(op->ptr, "animation")) { - single_object_action_users(bmain, scene, flag); + single_object_action_users(bmain, scene, view_layer, flag); } BKE_main_id_clear_newpoins(bmain); @@ -2446,7 +2466,7 @@ static int make_single_user_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_WINDOW, NULL); if (update_deps) { - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } return OPERATOR_FINISHED; @@ -2478,8 +2498,6 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot) RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects"); RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data"); RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each data-block"); - RNA_def_boolean(ot->srna, "texture", 0, "Textures", - "Make textures local to each material (needs 'Materials' to be set too)"); RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object"); } @@ -2497,7 +2515,7 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent assign_material(CTX_data_main(C), base->object, ma, 1, BKE_MAT_ASSIGN_USERPREF); - DAG_id_tag_update(&base->object->id, OB_RECALC_OB); + DEG_id_tag_update(&base->object->id, OB_RECALC_OB); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, base->object); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); |