Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / object / object_add.c
index 4ed1e85fb48e2403d0042c6f6a5d943b9499ab95..c824537a21adfa510c813b0286d9c661be5bf17d 100644 (file)
@@ -45,6 +45,7 @@
 #include "DNA_object_fluidsim.h"
 #include "DNA_object_force.h"
 #include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_vfont_types.h"
 #include "DNA_actuator_types.h"
 #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_effect.h"
@@ -74,6 +75,7 @@
 #include "BKE_group.h"
 #include "BKE_lamp.h"
 #include "BKE_lattice.h"
+#include "BKE_layer.h"
 #include "BKE_library.h"
 #include "BKE_library_query.h"
 #include "BKE_library_remap.h"
@@ -92,6 +94,9 @@
 #include "BKE_speaker.h"
 #include "BKE_texture.h"
 
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
 #include "RNA_access.h"
 #include "RNA_define.h"
 #include "RNA_enum_types.h"
 
 #include "UI_resources.h"
 
-#include "GPU_material.h"
+#include "GPU_lamp.h"
 
 #include "object_intern.h"
 
@@ -147,6 +152,16 @@ static EnumPropertyItem field_type_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
+static EnumPropertyItem lightprobe_type_items[] = {
+       {LIGHTPROBE_TYPE_CUBE, "SPHERE", ICON_MESH_UVSPHERE, "Reflection Cubemap",
+     "Reflection probe with spherical or cubic attenuation"},
+       {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_MESH_PLANE, "Reflection Plane",
+     "Planar reflection probe"},
+       {LIGHTPROBE_TYPE_GRID, "GRID", ICON_MESH_GRID, "Irradiance Volume",
+     "Irradiance probe to capture diffuse indirect lighting"},
+       {0, NULL, 0, NULL, NULL}
+};
+
 /************************** Exported *****************************/
 
 void ED_object_location_from_view(bContext *C, float loc[3])
@@ -406,10 +421,11 @@ Object *ED_object_add_type(
         bContext *C,
         int type, const char *name,
         const float loc[3], const float rot[3],
-        bool enter_editmode, unsigned int layer)
+        bool enter_editmode, unsigned int UNUSED(layer))
 {
        Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
+       SceneLayer *sl = CTX_data_scene_layer(C);
        Object *ob;
 
        /* for as long scene has editmode... */
@@ -417,13 +433,12 @@ Object *ED_object_add_type(
                ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);  /* freedata, and undo */
 
        /* deselects all, sets scene->basact */
-       ob = BKE_object_add(bmain, scene, type, name);
-       BASACT->lay = ob->lay = layer;
+       ob = BKE_object_add(bmain, scene, sl, type, name);
        /* editor level activate, notifiers */
-       ED_base_object_activate(C, BASACT);
+       ED_object_base_activate(C, sl->basact);
 
        /* more editor stuff */
-       ED_object_base_init_transform(C, BASACT, loc, rot);
+       ED_object_base_init_transform(C, sl->basact, loc, rot);
 
        /* Ignore collisions by default for non-mesh objects */
        if (type != OB_MESH) {
@@ -431,8 +446,8 @@ Object *ED_object_add_type(
                ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_OCCLUDER | OB_DYNAMIC | OB_NAVMESH); /* copied from rna_object.c */
        }
 
-       DAG_id_type_tag(bmain, ID_OB);
-       DAG_relations_tag_update(bmain);
+       DEG_id_type_tag(bmain, ID_OB);
+       DEG_relations_tag_update(bmain);
        if (ob->data) {
                ED_render_id_flush_update(bmain, ob->data);
        }
@@ -442,6 +457,9 @@ Object *ED_object_add_type(
 
        WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
 
+       /* TODO(sergey): Use proper flag for tagging here. */
+       DEG_id_tag_update(&scene->id, 0);
+
        return ob;
 }
 
@@ -493,6 +511,79 @@ void OBJECT_OT_add(wmOperatorType *ot)
        ED_object_add_generic_props(ot, true);
 }
 
+/********************** Add Probe Operator **********************/
+
+/* for object add operator */
+static int lightprobe_add_exec(bContext *C, wmOperator *op)
+{
+       Object *ob;
+       LightProbe *probe;
+       int type;
+       bool enter_editmode;
+       unsigned int layer;
+       float loc[3], rot[3];
+       float radius;
+
+       WM_operator_view3d_unit_defaults(C, op);
+       if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
+               return OPERATOR_CANCELLED;
+
+       type = RNA_enum_get(op->ptr, "type");
+       radius = RNA_float_get(op->ptr, "radius");
+
+       const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Light Probe");
+       ob = ED_object_add_type(C, OB_LIGHTPROBE, name, loc, rot, false, layer);
+       BKE_object_obdata_size_init(ob, radius);
+
+       probe = (LightProbe *)ob->data;
+       probe->type = type;
+
+       switch (type) {
+               case LIGHTPROBE_TYPE_GRID:
+                       probe->distinf = 0.3f;
+                       probe->falloff = 1.0f;
+                       probe->clipsta = 0.01f;
+                       break;
+               case LIGHTPROBE_TYPE_PLANAR:
+                       probe->distinf = 0.1f;
+                       probe->falloff = 0.5f;
+                       probe->clipsta = 0.001f;
+                       ob->empty_drawsize = 0.5f;
+                       break;
+               case LIGHTPROBE_TYPE_CUBE:
+                       probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID;
+                       break;
+               default:
+                       BLI_assert(!"Lightprobe type not configured.");
+                       break;
+       }
+
+       DEG_relations_tag_update(CTX_data_main(C));
+
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_lightprobe_add(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Add Light Probe";
+       ot->description = "Add a light probe object";
+       ot->idname = "OBJECT_OT_lightprobe_add";
+
+       /* api callbacks */
+       ot->exec = lightprobe_add_exec;
+       ot->poll = ED_operator_objectmode;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* properties */
+       ot->prop = RNA_def_enum(ot->srna, "type", lightprobe_type_items, 0, "Type", "");
+
+       ED_object_add_unit_props(ot);
+       ED_object_add_generic_props(ot, true);
+}
+
 /********************* Add Effector Operator ********************/
 
 /* for object add operator */
@@ -536,7 +627,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
 
        ob->pd = object_add_collision_fields(type);
 
-       DAG_relations_tag_update(CTX_data_main(C));
+       DEG_relations_tag_update(CTX_data_main(C));
 
        return OPERATOR_FINISHED;
 }
@@ -641,7 +732,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
                newob = true;
        }
        else {
-               DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+               DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
        }
 
        ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
@@ -745,7 +836,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
                newob = true;
        }
        else {
-               DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+               DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
        }
 
        if (obedit == NULL) {
@@ -831,7 +922,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
 {
        Scene *scene = CTX_data_scene(C);
 
-       Base *base = NULL;
+       BaseLegacy *base = NULL;
        Image *ima = NULL;
        Object *ob = NULL;
 
@@ -1003,7 +1094,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
                id_us_plus(&group->id);
 
                /* works without this except if you try render right after, see: 22027 */
-               DAG_relations_tag_update(bmain);
+               DEG_relations_tag_update(bmain);
 
                WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
 
@@ -1110,22 +1201,20 @@ static void object_delete_check_glsl_update(Object *ob)
 
 /* remove base from a specific scene */
 /* note: now unlinks constraints as well */
-void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base)
+void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
 {
-       if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
-           ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
+       if (BKE_library_ID_is_indirectly_used(bmain, ob) &&
+           ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0)
        {
                /* We cannot delete indirectly used object... */
                printf("WARNING, undeletable object '%s', should have been catched before reaching this function!",
-                      base->object->id.name + 2);
+                      ob->id.name + 2);
                return;
        }
 
-       BKE_scene_base_unlink(scene, base);
-       object_delete_check_glsl_update(base->object);
-       BKE_libblock_free_us(bmain, base->object);
-       MEM_freeN(base);
-       DAG_id_type_tag(bmain, ID_OB);
+       object_delete_check_glsl_update(ob);
+       BKE_collections_object_remove(bmain, scene, ob, true);
+       DEG_id_type_tag(bmain, ID_OB);
 }
 
 static int object_delete_exec(bContext *C, wmOperator *op)
@@ -1140,18 +1229,18 @@ static int object_delete_exec(bContext *C, wmOperator *op)
        if (CTX_data_edit_object(C)) 
                return OPERATOR_CANCELLED;
 
-       CTX_DATA_BEGIN (C, Base *, base, selected_bases)
+       CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
        {
-               const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, base->object);
-               if (base->object->id.tag & LIB_TAG_INDIRECT) {
+               const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, ob);
+               if (ob->id.tag & LIB_TAG_INDIRECT) {
                        /* Can this case ever happen? */
-                       BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+                       BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2);
                        continue;
                }
-               else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) {
+               else if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) {
                        BKE_reportf(op->reports, RPT_WARNING,
                                "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
-                               base->object->id.name + 2, scene->id.name + 2);
+                               ob->id.name + 2, scene->id.name + 2);
                        continue;
                }
 
@@ -1159,9 +1248,9 @@ static int object_delete_exec(bContext *C, wmOperator *op)
                 * custom scene/object/base handling, and use generic lib remap/query for that.
                 * But this is for later (aka 2.8, once layers & co are settled and working).
                 */
-               if (use_global && base->object->id.lib == NULL) {
+               if (use_global && ob->id.lib == NULL) {
                        /* We want to nuke the object, let's nuke it the easy way (not for linked data though)... */
-                       BKE_libblock_delete(bmain, &base->object->id);
+                       BKE_libblock_delete(bmain, &ob->id);
                        changed = true;
                        continue;
                }
@@ -1172,38 +1261,28 @@ static int object_delete_exec(bContext *C, wmOperator *op)
                for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
                        for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
                                if (gpl->parent != NULL) {
-                                       Object *ob = gpl->parent;
-                                       Object *curob = base->object;
-                                       if (ob == curob) {
+                                       if (gpl->parent == ob) {
                                                gpl->parent = NULL;
                                        }
                                }
                        }
                }
 
-               /* deselect object -- it could be used in other scenes */
-               base->object->flag &= ~SELECT;
-
                /* remove from current scene only */
-               ED_base_object_free_and_unlink(bmain, scene, base);
+               ED_base_object_free_and_unlink(bmain, scene, ob);
                changed = true;
 
                if (use_global) {
                        Scene *scene_iter;
-                       Base *base_other;
-
                        for (scene_iter = bmain->scene.first; scene_iter; scene_iter = scene_iter->id.next) {
                                if (scene_iter != scene && !ID_IS_LINKED_DATABLOCK(scene_iter)) {
-                                       base_other = BKE_scene_base_find(scene_iter, base->object);
-                                       if (base_other) {
-                                               if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) {
-                                                       BKE_reportf(op->reports, RPT_WARNING,
-                                                                   "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
-                                                                   base->object->id.name + 2, scene_iter->id.name + 2);
-                                                       break;
-                                               }
-                                               ED_base_object_free_and_unlink(bmain, scene_iter, base_other);
+                                       if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) {
+                                               BKE_reportf(op->reports, RPT_WARNING,
+                                                           "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+                                                           ob->id.name + 2, scene_iter->id.name + 2);
+                                               break;
                                        }
+                                       ED_base_object_free_and_unlink(bmain, scene_iter, ob);
                                }
                        }
                }
@@ -1217,12 +1296,12 @@ static int object_delete_exec(bContext *C, wmOperator *op)
        /* delete has to handle all open scenes */
        BKE_main_id_tag_listbase(&bmain->scene, LIB_TAG_DOIT, true);
        for (win = wm->windows.first; win; win = win->next) {
-               scene = win->screen->scene;
-               
+               scene = WM_window_get_active_scene(win);
+
                if (scene->id.tag & LIB_TAG_DOIT) {
                        scene->id.tag &= ~LIB_TAG_DOIT;
                        
-                       DAG_relations_tag_update(bmain);
+                       DEG_relations_tag_update(bmain);
 
                        WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
                        WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
@@ -1344,6 +1423,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                                        const bool use_hierarchy)
 {
        Main *bmain = CTX_data_main(C);
+       SceneLayer *sl = CTX_data_scene_layer(C);
        ListBase *lb;
        DupliObject *dob;
        GHash *dupli_gh = NULL, *parent_gh = NULL;
@@ -1375,12 +1455,10 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                 */
                if (ob->mat == NULL) ob->totcol = 0;
 
-               basen = MEM_dupallocN(base);
-               basen->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP);
-               ob->flag = basen->flag;
-               basen->lay = base->lay;
-               BLI_addhead(&scene->base, basen);   /* addhead: othwise eternal loop */
-               basen->object = ob;
+               BKE_collection_object_add_from(scene, dob->ob, ob);
+               basen = BKE_scene_layer_base_find(sl, ob);
+
+               BKE_scene_object_base_flag_sync_from_base(basen);
 
                /* make sure apply works */
                BKE_animdata_free(&ob->id, true);
@@ -1395,7 +1473,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                BKE_constraints_free(&ob->constraints);
                ob->curve_cache = NULL;
                ob->transflag &= ~OB_DUPLI;
-               ob->lay = base->lay;
 
                copy_m4_m4(ob->obmat, dob->mat);
                BKE_object_apply_mat4(ob, ob->obmat, false, false);
@@ -1417,7 +1494,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                set_sca_new_poins_ob(ob);
                BKE_id_clear_newpoin(&dob->ob->id);
 
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
        }
 
        if (use_hierarchy) {
@@ -1469,7 +1546,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                                BKE_object_apply_mat4(ob_dst, dob->mat, false, true);
 
                                /* to set ob_dst->orig and in case theres any other discrepicies */
-                               DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
+                               DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
                        }
                }
        }
@@ -1485,7 +1562,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
 
                        /* similer to the code above, see comments */
                        BKE_object_apply_mat4(ob_dst, dob->mat, false, true);
-                       DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
+                       DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
                }
        }
 
@@ -1494,7 +1571,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                        if (object->proxy_group == base->object) {
                                object->proxy = NULL;
                                object->proxy_from = NULL;
-                               DAG_id_tag_update(&object->id, OB_RECALC_OB);
+                               DEG_id_tag_update(&object->id, OB_RECALC_OB);
                        }
                }
        }
@@ -1528,7 +1605,7 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op)
        }
        CTX_DATA_END;
 
-       DAG_relations_tag_update(bmain);
+       DEG_relations_tag_update(bmain);
        WM_event_add_notifier(C, NC_SCENE, scene);
        WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
 
@@ -1601,7 +1678,7 @@ static int convert_poll(bContext *C)
 }
 
 /* Helper for convert_exec */
-static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object *ob)
+static Base *duplibase_for_convert(Main *bmain, Scene *scene, SceneLayer *sl, Base *base, Object *ob)
 {
        Object *obn;
        Base *basen;
@@ -1611,17 +1688,12 @@ static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object
        }
 
        obn = BKE_object_copy(bmain, ob);
-       DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
-       basen = MEM_mallocN(sizeof(Base), "duplibase");
-       *basen = *base;
-       BLI_addhead(&scene->base, basen);   /* addhead: otherwise eternal loop */
-       basen->object = obn;
-       basen->flag |= SELECT;
-       obn->flag |= SELECT;
-       base->flag &= ~SELECT;
-       ob->flag &= ~SELECT;
+       DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+       BKE_collection_object_add_from(scene, ob, obn);
 
+       basen = BKE_scene_layer_base_find(sl, obn);
+       ED_object_base_select(basen, BA_SELECT);
+       ED_object_base_select(basen, BA_DESELECT);
        return basen;
 }
 
@@ -1629,6 +1701,7 @@ static int convert_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
+       SceneLayer *sl = CTX_data_scene_layer(C);
        Base *basen = NULL, *basact = NULL;
        Object *ob, *ob1, *newob, *obact = CTX_data_active_object(C);
        DerivedMesh *dm;
@@ -1643,7 +1716,7 @@ static int convert_exec(bContext *C, wmOperator *op)
        /* don't forget multiple users! */
 
        {
-               Base *base;
+               BaseLegacy *base;
 
                for (base = scene->base.first; base; base = base->next) {
                        ob = base->object;
@@ -1674,7 +1747,7 @@ static int convert_exec(bContext *C, wmOperator *op)
         * on other objects data masks too, see: T50950. */
        {
                for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
-                       Base *base = link->ptr.data;
+                       BaseLegacy *base = link->ptr.data;
                        ob = base->object;
 
                        /* The way object type conversion works currently (enforcing conversion of *all* objetcs using converted
@@ -1688,7 +1761,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                                            "Converting some linked object/object data, enforcing 'Keep Original' option to True");
                        }
 
-                       DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
+                       DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
                }
 
                uint64_t customdata_mask_prev = scene->customdata_mask;
@@ -1698,7 +1771,7 @@ static int convert_exec(bContext *C, wmOperator *op)
        }
 
        for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
-               Base *base = link->ptr.data;
+               BaseLegacy *base = link->ptr.data;
                ob = base->object;
 
                if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) {
@@ -1720,7 +1793,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                        ob->flag |= OB_DONE;
 
                        if (keep_original) {
-                               basen = duplibase_for_convert(bmain, scene, base, NULL);
+                               basen = duplibase_for_convert(bmain, scene, sl, base, NULL);
                                newob = basen->object;
 
                                /* decrement original mesh's usage count  */
@@ -1745,7 +1818,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                        ob->flag |= OB_DONE;
 
                        if (keep_original) {
-                               basen = duplibase_for_convert(bmain, scene, base, NULL);
+                               basen = duplibase_for_convert(bmain, scene, sl, base, NULL);
                                newob = basen->object;
 
                                /* decrement original mesh's usage count  */
@@ -1757,7 +1830,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                        }
                        else {
                                newob = ob;
-                               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);
                        }
 
                        /* make new mesh data from the original copy */
@@ -1776,7 +1849,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                        ob->flag |= OB_DONE;
 
                        if (keep_original) {
-                               basen = duplibase_for_convert(bmain, scene, base, NULL);
+                               basen = duplibase_for_convert(bmain, scene, sl, base, NULL);
                                newob = basen->object;
 
                                /* decrement original curve's usage count  */
@@ -1823,7 +1896,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                                        for (ob1 = bmain->object.first; ob1; ob1 = ob1->id.next) {
                                                if (ob1->data == ob->data) {
                                                        ob1->type = OB_CURVE;
-                                                       DAG_id_tag_update(&ob1->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+                                                       DEG_id_tag_update(&ob1->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                                                }
                                        }
                                }
@@ -1847,7 +1920,7 @@ static int convert_exec(bContext *C, wmOperator *op)
 
                        if (target == OB_MESH) {
                                if (keep_original) {
-                                       basen = duplibase_for_convert(bmain, scene, base, NULL);
+                                       basen = duplibase_for_convert(bmain, scene, sl, base, NULL);
                                        newob = basen->object;
 
                                        /* decrement original curve's usage count  */
@@ -1882,7 +1955,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                        if (!(baseob->flag & OB_DONE)) {
                                baseob->flag |= OB_DONE;
 
-                               basen = duplibase_for_convert(bmain, scene, base, baseob);
+                               basen = duplibase_for_convert(bmain, scene, sl, base, baseob);
                                newob = basen->object;
 
                                mb = newob->data;
@@ -1925,7 +1998,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                }
 
                if (!keep_original && (ob->flag & OB_DONE)) {
-                       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+                       DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
                        ((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */
                }
        }
@@ -1933,27 +2006,24 @@ static int convert_exec(bContext *C, wmOperator *op)
 
        if (!keep_original) {
                if (mballConverted) {
-                       Base *base, *base_next;
-
-                       for (base = scene->base.first; base; base = base_next) {
-                               base_next = base->next;
-
-                               ob = base->object;
+                       FOREACH_SCENE_OBJECT(scene, ob_mball)
+                       {
                                if (ob->type == OB_MBALL) {
                                        if (ob->flag & OB_DONE) {
                                                Object *ob_basis = NULL;
-                                               if (BKE_mball_is_basis(ob) ||
-                                                   ((ob_basis = BKE_mball_basis_find(scene, ob)) && (ob_basis->flag & OB_DONE)))
+                                               if (BKE_mball_is_basis(ob_mball) ||
+                                                   ((ob_basis = BKE_mball_basis_find(scene, ob_mball)) && (ob_basis->flag & OB_DONE)))
                                                {
-                                                       ED_base_object_free_and_unlink(bmain, scene, base);
+                                                       ED_base_object_free_and_unlink(bmain, scene, ob_mball);
                                                }
                                        }
                                }
                        }
+                       FOREACH_SCENE_OBJECT_END
                }
 
                /* delete object should renew depsgraph */
-               DAG_relations_tag_update(bmain);
+               DEG_relations_tag_update(bmain);
        }
 
 // XXX ED_object_editmode_enter(C, 0);
@@ -1961,15 +2031,15 @@ static int convert_exec(bContext *C, wmOperator *op)
 
        if (basact) {
                /* active base was changed */
-               ED_base_object_activate(C, basact);
-               BASACT = basact;
+               ED_object_base_activate(C, basact);
+               BASACT_NEW = basact;
        }
-       else if (BASACT->object->flag & OB_DONE) {
-               WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT->object);
-               WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT->object);
+       else if (BASACT_NEW->object->flag & OB_DONE) {
+               WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT_NEW->object);
+               WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT_NEW->object);
        }
 
-       DAG_relations_tag_update(bmain);
+       DEG_relations_tag_update(bmain);
        WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
        WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
 
@@ -2008,39 +2078,36 @@ void OBJECT_OT_convert(wmOperatorType *ot)
 /* used below, assumes id.new is correct */
 /* leaves selection of base/object unaltered */
 /* Does set ID->newid pointers. */
-static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base, int dupflag)
+static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, SceneLayer *sl, Object *ob, int dupflag)
 {
 #define ID_NEW_REMAP_US(a)     if (      (a)->id.newid) { (a) = (void *)(a)->id.newid;       (a)->id.us++; }
 #define ID_NEW_REMAP_US2(a)    if (((ID *)a)->newid)    { (a) = ((ID  *)a)->newid;     ((ID *)a)->us++;    }
 
        Base *basen = NULL;
        Material ***matarar;
-       Object *ob, *obn;
+       Object *obn;
        ID *id;
        int a, didit;
 
-       ob = base->object;
        if (ob->mode & OB_MODE_POSE) {
                ; /* nothing? */
        }
        else {
                obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
-               DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+               DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 
-               basen = MEM_mallocN(sizeof(Base), "duplibase");
-               *basen = *base;
-               BLI_addhead(&scene->base, basen);   /* addhead: prevent eternal loop */
-               basen->object = obn;
+               BKE_collection_object_add_from(scene, ob, obn);
+               basen = BKE_scene_layer_base_find(sl, obn);
 
                /* 1) duplis should end up in same group as the original
                 * 2) Rigid Body sim participants MUST always be part of a group...
                 */
                // XXX: is 2) really a good measure here?
-               if ((basen->flag & OB_FROMGROUP) || ob->rigidbody_object || ob->rigidbody_constraint) {
+               if ((ob->flag & OB_FROMGROUP) != 0 || ob->rigidbody_object || ob->rigidbody_constraint) {
                        Group *group;
                        for (group = bmain->group.first; group; group = group->id.next) {
                                if (BKE_group_object_exists(group, ob))
-                                       BKE_group_object_add(group, obn, scene, basen);
+                                       BKE_group_object_add(group, obn);
                        }
                }
 
@@ -2149,7 +2216,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
                                }
                                break;
                        case OB_ARMATURE:
-                               DAG_id_tag_update(&obn->id, OB_RECALC_DATA);
+                               DEG_id_tag_update(&obn->id, OB_RECALC_DATA);
                                if (obn->pose)
                                        BKE_pose_tag_recalc(bmain, obn->pose);
                                if (dupflag & USER_DUP_ARM) {
@@ -2248,14 +2315,14 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
  * note: don't call this within a loop since clear_* funcs loop over the entire database.
  * note: caller must do DAG_relations_tag_update(bmain);
  *       this is not done automatic since we may duplicate many objects in a batch */
-Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag)
+Base *ED_object_add_duplicate(Main *bmain, Scene *scene, SceneLayer *sl, Base *base, int dupflag)
 {
        Base *basen;
        Object *ob;
 
        clear_sca_new_poins();  /* BGE logic */
 
-       basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
+       basen = object_add_duplicate_internal(bmain, scene, sl, base->object, dupflag);
        if (basen == NULL) {
                return NULL;
        }
@@ -2282,6 +2349,7 @@ static int duplicate_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
+       SceneLayer *sl = CTX_data_scene_layer(C);
        const bool linked = RNA_boolean_get(op->ptr, "linked");
        int dupflag = (linked) ? 0 : U.dupflag;
 
@@ -2289,22 +2357,23 @@ static int duplicate_exec(bContext *C, wmOperator *op)
 
        CTX_DATA_BEGIN (C, Base *, base, selected_bases)
        {
-               Base *basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
+               Base *basen = object_add_duplicate_internal(bmain, scene, sl, base->object, dupflag);
 
                /* note that this is safe to do with this context iterator,
                 * the list is made in advance */
-               ED_base_object_select(base, BA_DESELECT);
+               ED_object_base_select(base, BA_DESELECT);
+               ED_object_base_select(basen, BA_SELECT);
 
                if (basen == NULL) {
                        continue;
                }
 
                /* new object becomes active */
-               if (BASACT == base)
-                       ED_base_object_activate(C, basen);
+               if (BASACT_NEW == base)
+                       ED_object_base_activate(C, basen);
 
                if (basen->object->data) {
-                       DAG_id_tag_update(basen->object->data, 0);
+                       DEG_id_tag_update(basen->object->data, 0);
                }
        }
        CTX_DATA_END;
@@ -2313,7 +2382,9 @@ static int duplicate_exec(bContext *C, wmOperator *op)
 
        BKE_main_id_clear_newpoins(bmain);
 
-       DAG_relations_tag_update(bmain);
+       DEG_relations_tag_update(bmain);
+       /* TODO(sergey): Use proper flag for tagging here. */
+       DEG_id_tag_update(&CTX_data_scene(C)->id, 0);
 
        WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
 
@@ -2349,9 +2420,9 @@ static int add_named_exec(bContext *C, wmOperator *op)
        wmWindow *win = CTX_wm_window(C);
        const wmEvent *event = win ? win->eventstate : NULL;
        Main *bmain = CTX_data_main(C);
-       View3D *v3d = CTX_wm_view3d(C);  /* may be NULL */
        Scene *scene = CTX_data_scene(C);
-       Base *basen, *base;
+       SceneLayer *sl = CTX_data_scene_layer(C);
+       Base *basen;
        Object *ob;
        const bool linked = RNA_boolean_get(op->ptr, "linked");
        int dupflag = (linked) ? 0 : U.dupflag;
@@ -2366,22 +2437,17 @@ static int add_named_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
 
-       base = MEM_callocN(sizeof(Base), "duplibase");
-       base->object = ob;
-       base->flag = ob->flag;
-
        /* prepare dupli */
        clear_sca_new_poins();  /* BGE logic */
 
-       basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
+       basen = object_add_duplicate_internal(bmain, scene, sl, ob, dupflag);
+       BKE_scene_object_base_flag_sync_from_object(basen);
 
        if (basen == NULL) {
-               MEM_freeN(base);
                BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
                return OPERATOR_CANCELLED;
        }
 
-       basen->lay = basen->object->lay = BKE_screen_view3d_layer_active(v3d, scene);
        basen->object->restrictflag &= ~OB_RESTRICT_VIEW;
 
        if (event) {
@@ -2392,16 +2458,14 @@ static int add_named_exec(bContext *C, wmOperator *op)
                ED_view3d_cursor3d_position(C, basen->object->loc, mval);
        }
        
-       ED_base_object_select(basen, BA_SELECT);
-       ED_base_object_activate(C, basen);
+       ED_object_base_select(basen, BA_SELECT);
+       ED_object_base_activate(C, basen);
 
        copy_object_set_idnew(C);
 
        BKE_main_id_clear_newpoins(bmain);
 
-       DAG_relations_tag_update(bmain);
-
-       MEM_freeN(base);
+       DEG_relations_tag_update(bmain);
 
        WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_OB_ACTIVE, scene);