Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / object / object_add.c
index 519f591..9ce7f55 100644 (file)
@@ -45,9 +45,9 @@
 #include "DNA_object_fluidsim_types.h"
 #include "DNA_object_force_types.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 "DNA_gpencil_types.h"
 
 #include "BLI_utildefines.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"
 #include "BKE_font.h"
-#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"
 #include "BKE_material.h"
 #include "BKE_mball.h"
 #include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
 #include "BKE_nla.h"
 #include "BKE_object.h"
 #include "BKE_particle.h"
 #include "BKE_report.h"
-#include "BKE_sca.h"
 #include "BKE_scene.h"
 #include "BKE_screen.h"
 #include "BKE_speaker.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 "object_intern.h"
 
 /* this is an exact copy of the define in rna_lamp.c
@@ -146,6 +147,16 @@ static const EnumPropertyItem field_type_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
+static EnumPropertyItem lightprobe_type_items[] = {
+       {LIGHTPROBE_TYPE_CUBE, "CUBEMAP", ICON_LIGHTPROBE_CUBEMAP, "Reflection Cubemap",
+     "Reflection probe with spherical or cubic attenuation"},
+       {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_LIGHTPROBE_PLANAR, "Reflection Plane",
+     "Planar reflection probe"},
+       {LIGHTPROBE_TYPE_GRID, "GRID", ICON_LIGHTPROBE_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])
@@ -154,7 +165,7 @@ void ED_object_location_from_view(bContext *C, float loc[3])
        Scene *scene = CTX_data_scene(C);
        const float *cursor;
 
-       cursor = ED_view3d_cursor3d_get(scene, v3d);
+       cursor = ED_view3d_cursor3d_get(scene, v3d)->location;
 
        copy_v3_v3(loc, cursor);
 }
@@ -207,6 +218,7 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3],
 {
        Object *ob = base->object;
        Scene *scene = CTX_data_scene(C);
+       Depsgraph *depsgraph = CTX_data_depsgraph(C);
 
        if (!scene) return;
 
@@ -216,7 +228,7 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3],
        if (rot)
                copy_v3_v3(ob->rot, rot);
 
-       BKE_object_where_is_calc(scene, ob);
+       BKE_object_where_is_calc(depsgraph, scene, ob);
 }
 
 /* Uses context to figure out transform for primitive.
@@ -294,7 +306,7 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
 
 void ED_object_add_mesh_props(wmOperatorType *ot)
 {
-       RNA_def_boolean(ot->srna, "calc_uvs", false, "Generate UVs", "Generate a default UV map");
+       RNA_def_boolean(ot->srna, "calc_uvs", true, "Generate UVs", "Generate a default UV map");
 }
 
 bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view_align_axis,
@@ -404,10 +416,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);
+       ViewLayer *view_layer = CTX_data_view_layer(C);
        Object *ob;
 
        /* for as long scene has editmode... */
@@ -416,24 +429,20 @@ Object *ED_object_add_type(
        }
 
        /* deselects all, sets scene->basact */
-       ob = BKE_object_add(bmain, scene, type, name);
-       BASACT->lay = ob->lay = layer;
+       ob = BKE_object_add(bmain, scene, view_layer, type, name);
        /* editor level activate, notifiers */
-       ED_base_object_activate(C, BASACT);
+       ED_object_base_activate(C, view_layer->basact);
 
        /* more editor stuff */
-       ED_object_base_init_transform(C, BASACT, loc, rot);
-
-       /* Ignore collisions by default for non-mesh objects */
-       if (type != OB_MESH) {
-               ob->body_type = OB_BODY_TYPE_NO_COLLISION;
-               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 */
-       }
+       ED_object_base_init_transform(C, view_layer->basact, loc, rot);
 
-       DAG_id_type_tag(bmain, ID_OB);
-       DAG_relations_tag_update(bmain);
-       if (ob->data) {
-               ED_render_id_flush_update(bmain, ob->data);
+       /* TODO(sergey): This is weird to manually tag objects for update, better to
+        * use DEG_id_tag_update here perhaps.
+        */
+       DEG_id_type_tag(bmain, ID_OB);
+       DEG_relations_tag_update(bmain);
+       if (ob->data != NULL) {
+               DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE);
        }
 
        if (enter_editmode)
@@ -441,6 +450,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;
 }
 
@@ -492,6 +504,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 */
@@ -535,7 +620,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;
 }
@@ -640,7 +725,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);
@@ -744,7 +829,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) {
@@ -932,7 +1017,7 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op)
        la = (Lamp *)ob->data;
        la->type = type;
 
-       if (BKE_scene_use_new_shading_nodes(scene)) {
+       if (BKE_scene_uses_cycles(scene)) {
                ED_node_shader_default(C, &la->id);
                la->use_nodes = true;
        }
@@ -963,12 +1048,12 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot)
        ED_object_add_generic_props(ot, false);
 }
 
-/********************* Add Group Instance Operator ********************/
+/********************* Add Collection Instance Operator ********************/
 
-static int group_instance_add_exec(bContext *C, wmOperator *op)
+static int collection_instance_add_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
-       Group *group;
+       Collection *collection;
        unsigned int layer;
        float loc[3], rot[3];
 
@@ -976,7 +1061,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
                char name[MAX_ID_NAME - 2];
 
                RNA_string_get(op->ptr, "name", name);
-               group = (Group *)BKE_libblock_find_name(bmain, ID_GR, name);
+               collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
 
                if (0 == RNA_struct_property_is_set(op->ptr, "location")) {
                        const wmEvent *event = CTX_wm_window(C)->eventstate;
@@ -989,20 +1074,29 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
                }
        }
        else
-               group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group"));
+               collection = BLI_findlink(&CTX_data_main(C)->collection, RNA_enum_get(op->ptr, "collection"));
 
        if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
                return OPERATOR_CANCELLED;
 
-       if (group) {
+       if (collection) {
                Scene *scene = CTX_data_scene(C);
-               Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer);
-               ob->dup_group = group;
-               ob->transflag |= OB_DUPLIGROUP;
-               id_us_plus(&group->id);
+               ViewLayer *view_layer = CTX_data_view_layer(C);
+
+               /* Avoid dependency cycles. */
+               LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
+               while (BKE_collection_find_cycle(active_lc->collection, collection)) {
+                       active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
+               }
+
+               Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, loc, rot, false, layer);
+               ob->dup_group = collection;
+               ob->transflag |= OB_DUPLICOLLECTION;
+               id_us_plus(&collection->id);
 
                /* works without this except if you try render right after, see: 22027 */
-               DAG_relations_tag_update(bmain);
+               DEG_relations_tag_update(bmain);
+               DEG_id_tag_update(&collection->id, 0);
 
                WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
 
@@ -1013,27 +1107,27 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
 }
 
 /* only used as menu */
-void OBJECT_OT_group_instance_add(wmOperatorType *ot)
+void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
 {
        PropertyRNA *prop;
 
        /* identifiers */
-       ot->name = "Add Group Instance";
-       ot->description = "Add a dupligroup instance";
-       ot->idname = "OBJECT_OT_group_instance_add";
+       ot->name = "Add Collection Instance";
+       ot->description = "Add a collection instance";
+       ot->idname = "OBJECT_OT_collection_instance_add";
 
        /* api callbacks */
        ot->invoke = WM_enum_search_invoke;
-       ot->exec = group_instance_add_exec;
+       ot->exec = collection_instance_add_exec;
        ot->poll = ED_operator_objectmode;
 
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
        /* properties */
-       RNA_def_string(ot->srna, "name", "Group", MAX_ID_NAME - 2, "Name", "Group name to add");
-       prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "");
-       RNA_def_enum_funcs(prop, RNA_group_itemf);
+       RNA_def_string(ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Collection name to add");
+       prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "");
+       RNA_def_enum_funcs(prop, RNA_collection_itemf);
        RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
        ot->prop = prop;
        ED_object_add_generic_props(ot, false);
@@ -1096,35 +1190,22 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot)
 
 /**************************** Delete Object *************************/
 
-static void object_delete_check_glsl_update(Object *ob)
-{
-       /* some objects could affect on GLSL shading, make sure GLSL settings
-        * are being tagged to be updated when object is removing from scene
-        */
-       if (ob->type == OB_LAMP) {
-               if (ob->gpulamp.first)
-                       GPU_lamp_free(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_object_base_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);
+       DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_BASE_FLAGS_UPDATE);
+
+       BKE_scene_collections_object_remove(bmain, scene, ob, true);
 }
 
 static int object_delete_exec(bContext *C, wmOperator *op)
@@ -1139,18 +1220,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;
                }
 
@@ -1158,9 +1239,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;
                }
@@ -1171,38 +1252,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_object_base_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(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_object_base_free_and_unlink(bmain, scene_iter, ob);
                                }
                        }
                }
@@ -1216,12 +1287,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);
@@ -1262,15 +1333,13 @@ static void copy_object_set_idnew(bContext *C)
        }
        CTX_DATA_END;
 
-       set_sca_new_poins();
-
        BKE_main_id_clear_newpoins(bmain);
 }
 
 /********************* Make Duplicates Real ************************/
 
 /**
- * \note regarding hashing dupli-objects when using OB_DUPLIGROUP, skip the first member of #DupliObject.persistent_id
+ * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, skip the first member of #DupliObject.persistent_id
  * since its a unique index and we only want to know if the group objects are from the same dupli-group instance.
  */
 static unsigned int dupliobject_group_hash(const void *ptr)
@@ -1285,7 +1354,7 @@ static unsigned int dupliobject_group_hash(const void *ptr)
 }
 
 /**
- * \note regarding hashing dupli-objects when NOT using OB_DUPLIGROUP, include the first member of #DupliObject.persistent_id
+ * \note regarding hashing dupli-objects when NOT using OB_DUPLICOLLECTION, include the first member of #DupliObject.persistent_id
  * since its the index of the vertex/face the object is instantiated on and we want to identify objects on the same vertex/face.
  */
 static unsigned int dupliobject_hash(const void *ptr)
@@ -1343,6 +1412,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                                        const bool use_hierarchy)
 {
        Main *bmain = CTX_data_main(C);
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       Depsgraph *depsgraph = CTX_data_depsgraph(C);
        ListBase *lb_duplis;
        DupliObject *dob;
        GHash *dupli_gh, *parent_gh = NULL;
@@ -1351,11 +1422,11 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                return;
        }
 
-       lb_duplis = object_duplilist(bmain, bmain->eval_ctx, scene, base->object);
+       lb_duplis = object_duplilist(depsgraph, scene, base->object);
 
        dupli_gh = BLI_ghash_ptr_new(__func__);
        if (use_hierarchy) {
-               if (base->object->transflag & OB_DUPLIGROUP) {
+               if (base->object->transflag & OB_DUPLICOLLECTION) {
                        parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__);
                }
                else {
@@ -1375,12 +1446,11 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                        ob_dst->totcol = 0;
                }
 
-               base_dst = MEM_dupallocN(base);
-               base_dst->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP);
-               ob_dst->flag = base_dst->flag;
-               base_dst->lay = base->lay;
-               BLI_addhead(&scene->base, base_dst);   /* addhead: othwise eternal loop */
-               base_dst->object = ob_dst;
+               BKE_collection_object_add_from(bmain, scene, base->object, ob_dst);
+               base_dst = BKE_view_layer_base_find(view_layer, ob_dst);
+               BLI_assert(base_dst != NULL);
+
+               BKE_scene_object_base_flag_sync_from_base(base_dst);
 
                /* make sure apply works */
                BKE_animdata_free(&ob_dst->id, true);
@@ -1395,7 +1465,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                BKE_constraints_free(&ob_dst->constraints);
                ob_dst->curve_cache = NULL;
                ob_dst->transflag &= ~OB_DUPLI;
-               ob_dst->lay = base->lay;
 
                copy_m4_m4(ob_dst->obmat, dob->mat);
                BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false);
@@ -1417,9 +1486,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
 
                /* Remap new object to itself, and clear again newid pointer of orig object. */
                BKE_libblock_relink_to_newid(&ob_dst->id);
-               set_sca_new_poins_ob(ob_dst);
 
-               DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+               DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
 
                if (use_hierarchy) {
                        /* original parents */
@@ -1432,7 +1500,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
                                 * they won't be read, this is simply for a hash lookup. */
                                DupliObject dob_key;
                                dob_key.ob = ob_src_par;
-                               if (base->object->transflag & OB_DUPLIGROUP) {
+                               if (base->object->transflag & OB_DUPLICOLLECTION) {
                                        memcpy(&dob_key.persistent_id[1],
                                               &dob->persistent_id[1],
                                               sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1));
@@ -1473,16 +1541,16 @@ 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);
                }
        }
 
-       if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) {
+       if (base->object->transflag & OB_DUPLICOLLECTION && base->object->dup_group) {
                for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
                        if (ob->proxy_group == base->object) {
                                ob->proxy = NULL;
                                ob->proxy_from = NULL;
-                               DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+                               DEG_id_tag_update(&ob->id, OB_RECALC_OB);
                        }
                }
        }
@@ -1518,7 +1586,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);
 
@@ -1552,46 +1620,43 @@ static const EnumPropertyItem convert_target_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
-static void convert_ensure_curve_cache(Main *bmain, Scene *scene, Object *ob)
+static void convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob)
 {
        if (ob->curve_cache == NULL) {
                /* Force creation. This is normally not needed but on operator
                 * redo we might end up with an object which isn't evaluated yet.
                 */
                if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
-                       BKE_displist_make_curveTypes(scene, ob, false);
+                       BKE_displist_make_curveTypes(depsgraph, scene, ob, false);
                }
                else if (ob->type == OB_MBALL) {
-                       BKE_displist_make_mball(bmain, bmain->eval_ctx, scene, ob);
+                       BKE_displist_make_mball(depsgraph, scene, ob);
                }
        }
 }
 
-static void curvetomesh(Main *bmain, Scene *scene, Object *ob)
+static void curvetomesh(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
 {
-       convert_ensure_curve_cache(bmain, scene, ob);
+       convert_ensure_curve_cache(depsgraph, scene, ob);
        BKE_mesh_from_nurbs(bmain, ob); /* also does users */
 
        if (ob->type == OB_MESH) {
                BKE_object_free_modifiers(ob, 0);
-
-               /* Game engine defaults for mesh objects */
-               ob->body_type = OB_BODY_TYPE_STATIC;
-               ob->gameflag = OB_PROP | OB_COLLISION;
        }
 }
 
 static int convert_poll(bContext *C)
 {
-       Object *obact = CTX_data_active_object(C);
        Scene *scene = CTX_data_scene(C);
+       Base *base_act = CTX_data_active_base(C);
+       Object *obact = base_act ? base_act->object : NULL;
 
-       return (!ID_IS_LINKED(scene) && obact && scene->obedit != obact &&
-               (obact->flag & SELECT) && !ID_IS_LINKED(obact));
+       return (!ID_IS_LINKED(scene) && obact && (BKE_object_is_in_editmode(obact) == false) &&
+               (base_act->flag & BASE_SELECTED) && !ID_IS_LINKED(obact));
 }
 
 /* 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, ViewLayer *view_layer, Base *base, Object *ob)
 {
        Object *obn;
        Base *basen;
@@ -1601,26 +1666,23 @@ 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(bmain, scene, ob, obn);
 
+       basen = BKE_view_layer_base_find(view_layer, obn);
+       ED_object_base_select(basen, BA_SELECT);
+       ED_object_base_select(basen, BA_DESELECT);
        return basen;
 }
 
 static int convert_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
+       Depsgraph *depsgraph = CTX_data_depsgraph(C);
        Scene *scene = CTX_data_scene(C);
+       ViewLayer *view_layer = CTX_data_view_layer(C);
        Base *basen = NULL, *basact = NULL;
-       Object *ob, *ob1, *newob, *obact = CTX_data_active_object(C);
+       Object *ob1, *newob, *obact = CTX_data_active_object(C);
        DerivedMesh *dm;
        Curve *cu;
        Nurb *nu;
@@ -1633,10 +1695,8 @@ static int convert_exec(bContext *C, wmOperator *op)
        /* don't forget multiple users! */
 
        {
-               Base *base;
-
-               for (base = scene->base.first; base; base = base->next) {
-                       ob = base->object;
+               FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
+               {
                        ob->flag &= ~OB_DONE;
 
                        /* flag data thats not been edited (only needed for !keep_original) */
@@ -1648,13 +1708,14 @@ static int convert_exec(bContext *C, wmOperator *op)
                        if (ob->type == OB_MBALL && target == OB_MESH) {
                                if (BKE_mball_is_basis(ob) == false) {
                                        Object *ob_basis;
-                                       ob_basis = BKE_mball_basis_find(bmain, bmain->eval_ctx, scene, ob);
+                                       ob_basis = BKE_mball_basis_find(scene, ob);
                                        if (ob_basis) {
                                                ob_basis->flag &= ~OB_DONE;
                                        }
                                }
                        }
                }
+               FOREACH_SCENE_OBJECT_END;
        }
 
        ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases");
@@ -1665,7 +1726,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;
-                       ob = base->object;
+                       Object *ob = base->object;
 
                        /* The way object type conversion works currently (enforcing conversion of *all* objetcs using converted
                         * obdata, even some un-selected/hidden/inother scene ones, sounds totally bad to me.
@@ -1678,18 +1739,18 @@ 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;
                scene->customdata_mask |= CD_MASK_MESH;
-               BKE_scene_update_tagged(bmain->eval_ctx, bmain, scene);
+               BKE_scene_graph_update_tagged(depsgraph, bmain);
                scene->customdata_mask = customdata_mask_prev;
        }
 
        for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
                Base *base = link->ptr.data;
-               ob = base->object;
+               Object *ob = base->object;
 
                if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) {
                        if (ob->type != target) {
@@ -1710,7 +1771,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, view_layer, base, NULL);
                                newob = basen->object;
 
                                /* decrement original mesh's usage count  */
@@ -1724,7 +1785,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                                newob = ob;
                        }
 
-                       BKE_mesh_to_curve(bmain, scene, newob);
+                       BKE_mesh_to_curve(bmain, depsgraph, scene, newob);
 
                        if (newob->type == OB_CURVE) {
                                BKE_object_free_modifiers(newob, 0);   /* after derivedmesh calls! */
@@ -1735,7 +1796,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, view_layer, base, NULL);
                                newob = basen->object;
 
                                /* decrement original mesh's usage count  */
@@ -1747,14 +1808,14 @@ 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 */
                        /* note: get the mesh from the original, not from the copy in some
                         * cases this doesnt give correct results (when MDEF is used for eg)
                         */
-                       dm = mesh_get_derived_final(scene, newob, CD_MASK_MESH);
+                       dm = mesh_get_derived_final(depsgraph, scene, newob, CD_MASK_MESH);
 
                        DM_to_mesh(dm, newob->data, newob, CD_MASK_MESH, true);
 
@@ -1766,7 +1827,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, view_layer, base, NULL);
                                newob = basen->object;
 
                                /* decrement original curve's usage count  */
@@ -1813,7 +1874,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);
                                                }
                                        }
                                }
@@ -1826,7 +1887,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                        BKE_curve_curve_dimension_update(cu);
 
                        if (target == OB_MESH) {
-                               curvetomesh(bmain, scene, newob);
+                               curvetomesh(bmain, depsgraph, scene, newob);
 
                                /* meshes doesn't use displist */
                                BKE_object_free_curve_cache(newob);
@@ -1837,7 +1898,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, view_layer, base, NULL);
                                        newob = basen->object;
 
                                        /* decrement original curve's usage count  */
@@ -1850,7 +1911,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                                        newob = ob;
                                }
 
-                               curvetomesh(bmain, scene, newob);
+                               curvetomesh(bmain, depsgraph, scene, newob);
 
                                /* meshes doesn't use displist */
                                BKE_object_free_curve_cache(newob);
@@ -1859,10 +1920,10 @@ static int convert_exec(bContext *C, wmOperator *op)
                else if (ob->type == OB_MBALL && target == OB_MESH) {
                        Object *baseob;
 
-                       base->flag &= ~SELECT;
-                       ob->flag &= ~SELECT;
+                       base->flag &= ~BASE_SELECTED;
+                       ob->base_flag &= ~BASE_SELECTED;
 
-                       baseob = BKE_mball_basis_find(bmain, bmain->eval_ctx, scene, ob);
+                       baseob = BKE_mball_basis_find(scene, ob);
 
                        if (ob != baseob) {
                                /* if motherball is converting it would be marked as done later */
@@ -1872,7 +1933,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, view_layer, base, baseob);
                                newob = basen->object;
 
                                mb = newob->data;
@@ -1888,7 +1949,7 @@ static int convert_exec(bContext *C, wmOperator *op)
                                        for (a = 0; a < newob->totcol; a++) id_us_plus((ID *)me->mat[a]);
                                }
 
-                               convert_ensure_curve_cache(bmain, scene, baseob);
+                               convert_ensure_curve_cache(depsgraph, scene, baseob);
                                BKE_mesh_from_metaball(&baseob->curve_cache->disp, newob->data);
 
                                if (obact->type == OB_MBALL) {
@@ -1915,7 +1976,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 */
                }
        }
@@ -1923,27 +1984,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;
-                               if (ob->type == OB_MBALL) {
-                                       if (ob->flag & OB_DONE) {
+                       FOREACH_SCENE_OBJECT_BEGIN(scene, ob_mball)
+                       {
+                               if (ob_mball->type == OB_MBALL) {
+                                       if (ob_mball->flag & OB_DONE) {
                                                Object *ob_basis = NULL;
-                                               if (BKE_mball_is_basis(ob) ||
-                                                   ((ob_basis = BKE_mball_basis_find(bmain, bmain->eval_ctx, 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_object_base_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);
@@ -1951,15 +2009,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(view_layer) = 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(view_layer)->object->flag & OB_DONE) {
+               WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT(view_layer)->object);
+               WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT(view_layer)->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);
 
@@ -1998,39 +2056,43 @@ 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, ViewLayer *view_layer, 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;
+       Base *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);
 
-               basen = MEM_mallocN(sizeof(Base), "duplibase");
-               *basen = *base;
-               BLI_addhead(&scene->base, basen);   /* addhead: prevent eternal loop */
-               basen->object = obn;
+               base = BKE_view_layer_base_find(view_layer, ob);
+               if ((base != NULL) && (base->flag & BASE_VISIBLED)) {
+                       BKE_collection_object_add_from(bmain, scene, ob, obn);
+               }
+               else {
+                       LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
+                       BKE_collection_object_add(bmain, layer_collection->collection, obn);
+               }
+               basen = BKE_view_layer_base_find(view_layer, obn);
 
-               /* 1) duplis should end up in same group as the original
-                * 2) Rigid Body sim participants MUST always be part of a group...
+               /* 1) duplis should end up in same collection as the original
+                * 2) Rigid Body sim participants MUST always be part of a collection...
                 */
                // XXX: is 2) really a good measure here?
-               if ((basen->flag & OB_FROMGROUP) || 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);
+               if (ob->rigidbody_object || ob->rigidbody_constraint) {
+                       Collection *collection;
+                       for (collection = bmain->collection.first; collection; collection = collection->id.next) {
+                               if (BKE_collection_has_object(collection, ob))
+                                       BKE_collection_object_add(bmain, collection, obn);
                        }
                }
 
@@ -2139,7 +2201,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) {
@@ -2194,25 +2256,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
                        }
 
                        if (dupflag & USER_DUP_ACT) {
-                               bActuator *act;
-
                                BKE_animdata_copy_id_action((ID *)obn->data, true);
                                if (key) {
                                        BKE_animdata_copy_id_action((ID *)key, true);
                                }
-
-                               /* Update the duplicated action in the action actuators */
-                               /* XXX TODO this code is all wrong! actact->act is user-refcounted (see readfile.c),
-                                * and what about other ID pointers of other BGE logic bricks,
-                                * and since this is object-level, why is it only ran if obdata was duplicated??? -mont29 */
-                               for (act = obn->actuators.first; act; act = act->next) {
-                                       if (act->type == ACT_ACTION) {
-                                               bActionActuator *actact = (bActionActuator *) act->data;
-                                               if (ob->adt && actact->act == ob->adt->action) {
-                                                       actact->act = obn->adt->action;
-                                               }
-                                       }
-                               }
                        }
 
                        if (dupflag & USER_DUP_MAT) {
@@ -2243,14 +2290,12 @@ 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, ViewLayer *view_layer, 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, view_layer, base->object, dupflag);
        if (basen == NULL) {
                return NULL;
        }
@@ -2259,12 +2304,11 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag
 
        /* link own references to the newly duplicated data [#26816] */
        BKE_libblock_relink_to_newid(&ob->id);
-       set_sca_new_poins_ob(ob);
 
        /* DAG_relations_tag_update(bmain); */ /* caller must do */
 
-       if (ob->data) {
-               ED_render_id_flush_update(bmain, ob->data);
+       if (ob->data != NULL) {
+               DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE);
        }
 
        BKE_main_id_clear_newpoins(bmain);
@@ -2277,29 +2321,29 @@ static int duplicate_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);
        const bool linked = RNA_boolean_get(op->ptr, "linked");
        int dupflag = (linked) ? 0 : U.dupflag;
 
-       clear_sca_new_poins();  /* BGE logic */
-
        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, view_layer, 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(view_layer) == 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;
@@ -2308,7 +2352,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(&scene->id, 0);
 
        WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
 
@@ -2344,9 +2390,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;
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       Base *basen;
        Object *ob;
        const bool linked = RNA_boolean_get(op->ptr, "linked");
        int dupflag = (linked) ? 0 : U.dupflag;
@@ -2361,22 +2407,15 @@ 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, view_layer, ob, dupflag);
 
        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);
+       BKE_scene_object_base_flag_sync_from_object(basen);
        basen->object->restrictflag &= ~OB_RESTRICT_VIEW;
 
        if (event) {
@@ -2387,16 +2426,15 @@ 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);
+       /* TODO(sergey): Only update relations for the current scene. */
+       DEG_relations_tag_update(bmain);
 
        WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
        WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -2438,10 +2476,9 @@ static int join_poll(bContext *C)
 
 static int join_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene = CTX_data_scene(C);
        Object *ob = CTX_data_active_object(C);
 
-       if (scene->obedit) {
+       if (ob->mode & OB_MODE_EDIT) {
                BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode");
                return OPERATOR_CANCELLED;
        }
@@ -2492,10 +2529,9 @@ static int join_shapes_poll(bContext *C)
 
 static int join_shapes_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene = CTX_data_scene(C);
        Object *ob = CTX_data_active_object(C);
 
-       if (scene->obedit) {
+       if (ob->mode & OB_MODE_EDIT) {
                BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode");
                return OPERATOR_CANCELLED;
        }