Merge branch 'master' into blender2.8
authorBastien Montagne <montagne29@wanadoo.fr>
Tue, 12 Jun 2018 13:41:32 +0000 (15:41 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Tue, 12 Jun 2018 13:41:32 +0000 (15:41 +0200)
Conflicts:
source/blender/blenkernel/BKE_group.h
source/blender/blenkernel/BKE_object.h
source/blender/blenkernel/intern/group.c
source/blender/blenkernel/intern/library_remap.c
source/blender/blenkernel/intern/object.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/object/object_group.c
source/blender/editors/object/object_relations.c
source/blender/editors/physics/rigidbody_constraint.c
source/blender/editors/physics/rigidbody_object.c
source/blender/makesrna/intern/rna_group.c

1  2 
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/displist.c
source/blender/blenkernel/intern/font.c
source/blender/blenkernel/intern/object_dupli.c
source/blender/editors/curve/editfont.c
source/blender/editors/object/object_add.c

index 01da9857864d6275364fcff5e1fc09fd2cfb435d,d89e7a126449016ccb9d5a71a96382a2f70a370c..504999b0b108494408a4b26c69551a1bedb098fe
@@@ -53,6 -53,7 +53,6 @@@
  
  #include "BKE_animsys.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_displist.h"
  #include "BKE_font.h"
  #include "BKE_global.h"
@@@ -128,8 -129,6 +128,8 @@@ void BKE_curve_free(Curve *cu
  {
        BKE_animdata_free((ID *)cu, false);
  
 +      BKE_curve_batch_cache_free(cu);
 +
        BKE_nurbList_free(&cu->nurb);
        BKE_curve_editfont_free(cu);
  
@@@ -210,9 -209,8 +210,9 @@@ void BKE_curve_copy_data(Main *bmain, C
        cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
        cu_dst->tb = MEM_dupallocN(cu_src->tb);
        cu_dst->bb = MEM_dupallocN(cu_src->bb);
 +      cu_dst->batch_cache = NULL;
  
 -      if (cu_src->key) {
 +      if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
                BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag, false);
        }
  
  Curve *BKE_curve_copy(Main *bmain, const Curve *cu)
  {
        Curve *cu_copy;
 -      BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, 0, false);
 +      BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, LIB_ID_COPY_SHAPEKEY, false);
        return cu_copy;
  }
  
@@@ -1624,7 -1622,7 +1624,7 @@@ float *BKE_curve_surf_make_orco(Object 
  /* NOTE: This routine is tied to the order of vertex
   * built by displist and as passed to the renderer.
   */
 -float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
 +float *BKE_curve_make_orco(Depsgraph *depsgraph, Scene *scene, Object *ob, int *r_numVerts)
  {
        Curve *cu = ob->data;
        DispList *dl;
        float *fp, *coord_array;
        ListBase disp = {NULL, NULL};
  
 -      BKE_displist_make_curveTypes_forOrco(scene, ob, &disp);
 +      BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
  
        numVerts = 0;
        for (dl = disp.first; dl; dl = dl->next) {
  
  /* ***************** BEVEL ****************** */
  
 -void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
 -                          const bool for_render, const bool use_render_resolution)
 +void BKE_curve_bevel_make(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *disp,
 +        const bool for_render, const bool use_render_resolution)
  {
        DispList *dl, *dlnew;
        Curve *bevcu, *cu;
                        facy = cu->bevobj->size[1];
  
                        if (for_render) {
 -                              BKE_displist_make_curveTypes_forRender(scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution);
 +                              BKE_displist_make_curveTypes_forRender(depsgraph, scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution);
                                dl = bevdisp.first;
                        }
                        else if (cu->bevobj->curve_cache) {
@@@ -4962,7 -4959,7 +4962,7 @@@ bool BKE_curve_minmax(Curve *cu, bool u
         */
        if (is_font) {
                nurb_lb = &temp_nurb_lb;
-               BKE_vfont_to_curve_ex(G.main, NULL, cu, FO_EDIT, nurb_lb,
+               BKE_vfont_to_curve_ex(NULL, cu, FO_EDIT, nurb_lb,
                                      NULL, NULL, NULL, NULL);
                use_radius = false;
        }
@@@ -5188,7 -5185,7 +5188,7 @@@ int BKE_curve_material_index_validate(C
        }
  
        if (!is_valid) {
 -              DAG_id_tag_update(&cu->id, OB_RECALC_DATA);
 +              DEG_id_tag_update(&cu->id, OB_RECALC_DATA);
                return true;
        }
        else {
@@@ -5255,28 -5252,11 +5255,28 @@@ void BKE_curve_rect_from_textbox(const 
  
  /* **** Depsgraph evaluation **** */
  
 -void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
 +void BKE_curve_eval_geometry(Depsgraph *depsgraph,
                               Curve *curve)
  {
 -      DEG_debug_print_eval(__func__, curve->id.name, curve);
 +      DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve);
        if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
                BKE_curve_texspace_calc(curve);
        }
  }
 +
 +/* Draw Engine */
 +void (*BKE_curve_batch_cache_dirty_cb)(Curve *cu, int mode) = NULL;
 +void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
 +
 +void BKE_curve_batch_cache_dirty(Curve *cu, int mode)
 +{
 +      if (cu->batch_cache) {
 +              BKE_curve_batch_cache_dirty_cb(cu, mode);
 +      }
 +}
 +void BKE_curve_batch_cache_free(Curve *cu)
 +{
 +      if (cu->batch_cache) {
 +              BKE_curve_batch_cache_free_cb(cu);
 +      }
 +}
index 5e812d4e5d0250f2666bfa2d8c1fb1b1940ebfb2,dea1a3718ddc72f20d780c34d5d4d22140bd85f5..ad055a727a9187ff8c16dc0d4afabc92155d535d
@@@ -37,7 -37,6 +37,7 @@@
  #include "MEM_guardedalloc.h"
  
  #include "DNA_curve_types.h"
 +#include "DNA_mesh_types.h"
  #include "DNA_scene_types.h"
  #include "DNA_object_types.h"
  #include "DNA_vfont_types.h"
  #include "BLI_utildefines.h"
  
  #include "BKE_global.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_displist.h"
  #include "BKE_cdderivedmesh.h"
  #include "BKE_object.h"
 +#include "BKE_library.h"
  #include "BKE_main.h"
  #include "BKE_mball.h"
  #include "BKE_mball_tessellate.h"
 +#include "BKE_mesh.h"
  #include "BKE_curve.h"
  #include "BKE_key.h"
  #include "BKE_anim.h"
@@@ -66,9 -64,6 +66,9 @@@
  
  #include "BLI_sys_types.h" // for intptr_t support
  
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_query.h"
 +
  static void boundbox_displist_object(Object *ob);
  
  void BKE_displist_elem_free(DispList *dl)
@@@ -685,7 -680,7 +685,7 @@@ static void curve_to_filledpoly(Curve *
   * - first point left, last point right
   * - based on subdivided points in original curve, not on points in taper curve (still)
   */
 -static float displist_calc_taper(Scene *scene, Object *taperobj, float fac)
 +static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, float fac)
  {
        DispList *dl;
  
  
        dl = taperobj->curve_cache ? taperobj->curve_cache->disp.first : NULL;
        if (dl == NULL) {
 -              BKE_displist_make_curveTypes(scene, taperobj, 0);
 +              BKE_displist_make_curveTypes(depsgraph, scene, taperobj, 0);
                dl = taperobj->curve_cache->disp.first;
        }
        if (dl) {
        return 1.0;
  }
  
 -float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot)
 +float BKE_displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, int cur, int tot)
  {
        float fac = ((float)cur) / (float)(tot - 1);
  
 -      return displist_calc_taper(scene, taperobj, fac);
 +      return displist_calc_taper(depsgraph, scene, taperobj, fac);
  }
  
 -void BKE_displist_make_mball(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob)
 +void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
  {
        if (!ob || ob->type != OB_MBALL)
                return;
  
 -      if (ob == BKE_mball_basis_find(bmain, eval_ctx, scene, ob)) {
 +      if (ob == BKE_mball_basis_find(scene, ob)) {
                if (ob->curve_cache) {
                        BKE_displist_free(&(ob->curve_cache->disp));
                }
                        ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
                }
  
 -              BKE_mball_polygonize(bmain, eval_ctx, scene, ob, &ob->curve_cache->disp);
 +              BKE_mball_polygonize(depsgraph, scene, ob, &ob->curve_cache->disp);
                BKE_mball_texspace_calc(ob);
  
                object_deform_mball(ob, &ob->curve_cache->disp);
        }
  }
  
 -void BKE_displist_make_mball_forRender(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
 +void BKE_displist_make_mball_forRender(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
  {
 -      BKE_mball_polygonize(bmain, eval_ctx, scene, ob, dispbase);
 +      BKE_mball_polygonize(depsgraph, scene, ob, dispbase);
        BKE_mball_texspace_calc(ob);
  
        object_deform_mball(ob, dispbase);
@@@ -805,9 -800,8 +805,9 @@@ static ModifierData *curve_get_tessella
        return pretessellatePoint;
  }
  
 -static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
 -                                     const bool for_render, const bool use_render_resolution)
 +static void curve_calc_modifiers_pre(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
 +        const bool for_render, const bool use_render_resolution)
  {
        VirtualModifierData virtualModifierData;
        ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        else
                required_mode = eModifierMode_Realtime;
  
 +      const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
 +
        pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
  
        if (editmode)
                                deformedVerts = BKE_curve_nurbs_vertexCos_get(nurb, &numVerts);
                        }
  
 -                      mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, app_flag);
 +                      modifier_deformVerts_DM_deprecated(md, &mectx, NULL, deformedVerts, numVerts);
  
                        if (md == pretessellatePoint)
                                break;
@@@ -918,10 -910,9 +918,10 @@@ static void displist_apply_allverts(Lis
        }
  }
  
 -static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
 -                                      ListBase *dispbase, DerivedMesh **r_dm_final,
 -                                      const bool for_render, const bool use_render_resolution)
 +static void curve_calc_modifiers_post(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
 +        ListBase *dispbase, DerivedMesh **r_dm_final,
 +        const bool for_render, const bool use_render_resolution)
  {
        VirtualModifierData virtualModifierData;
        ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        Curve *cu = ob->data;
        int required_mode = 0, totvert = 0;
        const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
 -      DerivedMesh *dm = NULL, *ndm;
 +      Mesh *modified = NULL, *mesh_applied;
        float (*vertCos)[3] = NULL;
        int useCache = !for_render;
        ModifierApplyFlag app_flag = 0;
        else
                required_mode = eModifierMode_Realtime;
  
 +      const ModifierEvalContext mectx_deform = {depsgraph, ob,
 +                                                editmode ? app_flag | MOD_APPLY_USECACHE : app_flag};
 +      const ModifierEvalContext mectx_apply = {depsgraph, ob,
 +                                               useCache ? app_flag | MOD_APPLY_USECACHE : app_flag};
 +
        pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
  
        if (editmode)
  
        for (; md; md = md->next) {
                const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 -              ModifierApplyFlag appf = app_flag;
 -
                md->scene = scene;
  
                if (!modifier_isEnabled(scene, md, required_mode))
                        continue;
  
                if (mti->type == eModifierTypeType_OnlyDeform ||
 -                  (mti->type == eModifierTypeType_DeformOrConstruct && !dm))
 +                  (mti->type == eModifierTypeType_DeformOrConstruct && !modified))
                {
 -                      if (editmode)
 -                              appf |= MOD_APPLY_USECACHE;
 -                      if (dm) {
 +                      if (modified) {
                                if (!vertCos) {
 -                                      totvert = dm->getNumVerts(dm);
 -                                      vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "dfmv");
 -                                      dm->getVertCos(dm, vertCos);
 +                                      vertCos = BKE_mesh_vertexCos_get(modified, &totvert);
                                }
  
 -                              mti->deformVerts(md, ob, dm, vertCos, totvert, appf);
 +                              modifier_deformVerts(md, &mectx_deform, modified, vertCos, totvert);
                        }
                        else {
                                if (!vertCos) {
                                        vertCos = displist_get_allverts(dispbase, &totvert);
                                }
  
 -                              mti->deformVerts(md, ob, NULL, vertCos, totvert, appf);
 +                              modifier_deformVerts(md, &mectx_deform, NULL, vertCos, totvert);
                        }
                }
                else {
                                break;
                        }
  
 -                      if (dm) {
 +                      if (modified) {
                                if (vertCos) {
 -                                      DerivedMesh *tdm = CDDM_copy(dm);
 -                                      dm->release(dm);
 -                                      dm = tdm;
 -
 -                                      CDDM_apply_vert_coords(dm, vertCos);
 +                                      Mesh *temp_mesh;
 +                                      BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
 +                                                     LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
 +                                                     LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
 +                                                     false);
 +                                      BKE_id_free(NULL, modified);
 +                                      modified = temp_mesh;
 +
 +                                      BKE_mesh_apply_vert_coords(modified, vertCos);
                                }
                        }
                        else {
                                        curve_to_filledpoly(cu, nurb, dispbase);
                                }
  
 -                              dm = CDDM_from_curve_displist(ob, dispbase);
 +                              modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
                        }
  
                        if (vertCos) {
                                vertCos = NULL;
                        }
  
 -                      if (useCache)
 -                              appf |= MOD_APPLY_USECACHE;
 -
 -                      ndm = modwrap_applyModifier(md, ob, dm, appf);
 +                      mesh_applied = modifier_applyModifier(md, &mectx_apply, modified);
  
 -                      if (ndm) {
 +                      if (mesh_applied) {
                                /* Modifier returned a new derived mesh */
  
 -                              if (dm && dm != ndm) /* Modifier  */
 -                                      dm->release(dm);
 -                              dm = ndm;
 +                              if (modified && modified != mesh_applied) /* Modifier  */
 +                                      BKE_id_free(NULL, modified);
 +                              modified = mesh_applied;
                        }
                }
        }
  
        if (vertCos) {
 -              if (dm) {
 -                      DerivedMesh *tdm = CDDM_copy(dm);
 -                      dm->release(dm);
 -                      dm = tdm;
 +              if (modified) {
 +                      Mesh *temp_mesh;
 +                      BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
 +                                     LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
 +                                     LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
 +                                     false);
 +                      BKE_id_free(NULL, modified);
 +                      modified = temp_mesh;
 +
 +                      BKE_mesh_apply_vert_coords(modified, vertCos);
 +                      BKE_mesh_calc_normals_mapping_simple(modified);
  
 -                      CDDM_apply_vert_coords(dm, vertCos);
 -                      CDDM_calc_normals_mapping(dm);
                        MEM_freeN(vertCos);
                }
                else {
        }
  
        if (r_dm_final) {
 -              if (dm) {
 +              if (modified) {
                        /* see: mesh_calc_modifiers */
 -                      if (dm->getNumTessFaces(dm) == 0) {
 -                              dm->recalcTessellation(dm);
 +                      if (modified->totface == 0) {
 +                              BKE_mesh_tessface_calc(modified);
                        }
                        /* Even if tessellation is not needed, some modifiers might have modified CD layers
                         * (like mloopcol or mloopuv), hence we have to update those. */
 -                      else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
 -                              DM_update_tessface_data(dm);
 +                      else if (modified->runtime.cd_dirty_vert & CD_MASK_TESSLOOPNORMAL) {
 +                              BKE_mesh_tessface_calc(modified);
                        }
  
 -                      if (dm->type == DM_TYPE_CDDM) {
 -                              CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true);
 -                      }
 +                      /* XXX2.8(Sybren): make sure the face normals are recalculated as well */
 +                      BKE_mesh_ensure_normals(modified);
 +
 +                      (*r_dm_final) = CDDM_from_mesh_ex(modified, CD_DUPLICATE, CD_MASK_MESH);
 +                      BKE_id_free(NULL, modified);
                }
 -              (*r_dm_final) = dm;
 +              else {
 +                      (*r_dm_final) = NULL;
 +              }
 +
        }
  }
  
@@@ -1111,15 -1092,13 +1111,15 @@@ static void displist_surf_indices(DispL
        }
  }
  
 -static DerivedMesh *create_orco_dm(Scene *scene, Object *ob)
 +/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
 +#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
 +static DerivedMesh *create_orco_dm(Depsgraph *depsgraph, Scene *scene, Object *ob)
  {
        DerivedMesh *dm;
        ListBase disp = {NULL, NULL};
  
        /* OrcoDM should be created from underformed disp lists */
 -      BKE_displist_make_curveTypes_forOrco(scene, ob, &disp);
 +      BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
        dm = CDDM_from_curve_displist(ob, &disp);
  
        BKE_displist_free(&disp);
@@@ -1156,13 -1135,9 +1156,13 @@@ static void add_orco_dm(Object *ob, Der
        else
                DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco);
  }
 +#endif
  
 -static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
 -                              const bool for_render, const bool use_render_resolution)
 +/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
 +#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
 +static void curve_calc_orcodm(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final,
 +        const bool for_render, const bool use_render_resolution)
  {
        /* this function represents logic of mesh's orcodm calculation
         * for displist-based objects
        else
                required_mode = eModifierMode_Realtime;
  
 +      const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
 +
        pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
  
        if (editmode)
         * This means we can create ORCO DM in advance and assume it's
         * never NULL.
         */
 -      orcodm = create_orco_dm(scene, ob);
 +      orcodm = create_orco_dm(depsgraph, scene, ob);
  
        for (; md; md = md->next) {
                const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
                if (mti->type != eModifierTypeType_Constructive)
                        continue;
  
 -              ndm = modwrap_applyModifier(md, ob, orcodm, app_flag);
 +              ndm = modwrap_applyModifier(md, &mectx, orcodm);
  
                if (ndm) {
                        /* if the modifier returned a new dm, release the old one */
  
        orcodm->release(orcodm);
  }
 +#endif
  
 -void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
 -                            DerivedMesh **r_dm_final,
 -                            const bool for_render, const bool for_orco, const bool use_render_resolution)
 +void BKE_displist_make_surf(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
 +        DerivedMesh **r_dm_final,
 +        const bool for_render, const bool for_orco, const bool use_render_resolution)
  {
        ListBase nubase = {NULL, NULL};
        Nurb *nu;
        }
  
        if (!for_orco)
 -              curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution);
 +              curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
  
        for (nu = nubase.first; nu; nu = nu->next) {
                if ((for_render || nu->hide == 0) && BKE_nurb_check_valid_uv(nu)) {
  
        if (!for_orco) {
                BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
 -              curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final,
 +              curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_dm_final,
                                          for_render, use_render_resolution);
        }
  
@@@ -1544,10 -1515,9 +1544,10 @@@ static void calc_bevfac_mapping(Curve *
        }
  }
  
 -static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispbase,
 -                                      DerivedMesh **r_dm_final,
 -                                      const bool for_render, const bool for_orco, const bool use_render_resolution)
 +static void do_makeDispListCurveTypes(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
 +        DerivedMesh **r_dm_final,
 +        const bool for_render, const bool for_orco, const bool use_render_resolution)
  {
        Curve *cu = ob->data;
  
        if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return;
  
        if (ob->type == OB_SURF) {
 -              BKE_displist_make_surf(scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution);
 +              BKE_displist_make_surf(depsgraph, scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution);
        }
        else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
                ListBase dlbev;
                }
  
                if (ob->type == OB_FONT) {
-                       BKE_vfont_to_curve_nubase(G.main, ob, FO_EDIT, &nubase);
+                       BKE_vfont_to_curve_nubase(ob, FO_EDIT, &nubase);
                }
                else {
                        BKE_nurbList_duplicate(&nubase, BKE_curve_nurbs_get(cu));
                }
  
                if (!for_orco)
 -                      curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution);
 +                      curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
  
                BKE_curve_bevelList_make(ob, &nubase, for_render != false);
  
                /* If curve has no bevel will return nothing */
 -              BKE_curve_bevel_make(scene, ob, &dlbev, for_render, use_render_resolution);
 +              BKE_curve_bevel_make(depsgraph, scene, ob, &dlbev, for_render, use_render_resolution);
  
                /* no bevel or extrude, and no width correction? */
                if (!dlbev.first && cu->width == 1.0f) {
                                                                                        taper_fac -= (1.0f - lastblend) / len;
                                                                        }
  
 -                                                                      fac = displist_calc_taper(scene, cu->taperobj, taper_fac);
 +                                                                      fac = displist_calc_taper(depsgraph, scene, cu->taperobj, taper_fac);
                                                                }
  
                                                                if (bevp->split_tag) {
  
                if (!for_orco) {
                        if ((cu->flag & CU_PATH) ||
 -                          DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CURVE_PATH)
 +                          DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH)
                        {
                                calc_curvepath(ob, &nubase);
                        }
  
                if (!for_orco) {
                        BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
 -                      curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution);
 +                      curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution);
                }
  
                if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) {
        }
  }
  
 -void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco)
 +void BKE_displist_make_curveTypes(Depsgraph *depsgraph, Scene *scene, Object *ob, const bool for_orco)
  {
        ListBase *dispbase;
  
  
        dispbase = &(ob->curve_cache->disp);
  
 -      do_makeDispListCurveTypes(scene, ob, dispbase, &ob->derivedFinal, 0, for_orco, 0);
 +      do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, &ob->derivedFinal, 0, for_orco, 0);
  
        boundbox_displist_object(ob);
  }
  
 -void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase *dispbase,
 -                                            DerivedMesh **r_dm_final, const bool for_orco,
 -                                            const bool use_render_resolution)
 +void BKE_displist_make_curveTypes_forRender(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
 +        DerivedMesh **r_dm_final, const bool for_orco,
 +        const bool use_render_resolution)
  {
        if (ob->curve_cache == NULL) {
                ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
        }
  
 -      do_makeDispListCurveTypes(scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution);
 +      do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution);
  }
  
 -void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase)
 +void BKE_displist_make_curveTypes_forOrco(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
  {
        if (ob->curve_cache == NULL) {
                ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
        }
  
 -      do_makeDispListCurveTypes(scene, ob, dispbase, NULL, 1, 1, 1);
 +      do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, NULL, 1, 1, 1);
  }
  
  /* add Orco layer to the displist object which has got derived mesh and return orco */
 -float *BKE_displist_make_orco(Scene *scene, Object *ob, DerivedMesh *dm_final,
 -                              const bool for_render,
 -                              const bool use_render_resolution)
 +/* XXX2.8(Sybren): can be removed once DerivedMesh port is done */
 +#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
 +float *BKE_displist_make_orco(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final,
 +        const bool for_render,
 +        const bool use_render_resolution)
  {
        float *orco;
  
                dm_final = ob->derivedFinal;
  
        if (!dm_final->getVertDataArray(dm_final, CD_ORCO)) {
 -              curve_calc_orcodm(scene, ob, dm_final, for_render, use_render_resolution);
 +              curve_calc_orcodm(depsgraph, scene, ob, dm_final, for_render, use_render_resolution);
        }
  
        orco = dm_final->getVertDataArray(dm_final, CD_ORCO);
  
        return orco;
  }
 +#endif
  
  void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3])
  {
index f7ab5415d1ce5b0295631f35e75ea055efb89a20,73199cebe36b97a45a0c29a2d711dfeb636cbeed..29767efa71f34d334cbccd73dad79eaff4795e19
@@@ -153,7 -153,7 +153,7 @@@ static PackedFile *get_builtin_packedfi
        }
  }
  
- static VFontData *vfont_get_data(Main *bmain, VFont *vfont)
+ static VFontData *vfont_get_data(VFont *vfont)
  {
        if (vfont == NULL) {
                return NULL;
                                }
                        }
                        else {
-                               pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH(bmain, &vfont->id));
+                               pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
  
                                if (vfont->temp_pf == NULL) {
-                                       vfont->temp_pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH(bmain, &vfont->id));
+                                       vfont->temp_pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
                                }
                        }
                        if (!pf) {
@@@ -349,13 -349,13 +349,13 @@@ VFont *BKE_vfont_builtin_get(void
  {
        VFont *vfont;
        
-       for (vfont = G.main->vfont.first; vfont; vfont = vfont->id.next) {
+       for (vfont = G_MAIN->vfont.first; vfont; vfont = vfont->id.next) {
                if (BKE_vfont_is_builtin(vfont)) {
                        return vfont;
                }
        }
        
-       return BKE_vfont_load(G.main, FO_BUILTIN_NAME);
+       return BKE_vfont_load(G_MAIN, FO_BUILTIN_NAME);
  }
  
  static VChar *find_vfont_char(VFontData *vfd, unsigned int character)
@@@ -423,7 -423,7 +423,7 @@@ static void build_underline(Curve *cu, 
        mul_v2_fl(bp[3].vec, cu->fsize);
  }
  
- static void buildchar(Main *bmain, Curve *cu, ListBase *nubase, unsigned int character, CharInfo *info,
+ static void buildchar(Curve *cu, ListBase *nubase, unsigned int character, CharInfo *info,
                        float ofsx, float ofsy, float rot, int charidx)
  {
        BezTriple *bezt1, *bezt2;
        VChar *che = NULL;
        int i;
  
-       vfd = vfont_get_data(bmain, which_vfont(cu, info));
+       vfd = vfont_get_data(which_vfont(cu, info));
        if (!vfd) return;
  
  #if 0
@@@ -635,7 -635,7 +635,7 @@@ struct TempLineInfo 
        int   wspace_nr;  /* number of whitespaces of line */
  };
  
- bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, Curve *cu, int mode, ListBase *r_nubase,
+ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
                             const wchar_t **r_text, int *r_text_len, bool *r_text_free,
                             struct CharTrans **r_chartransdata)
  {
        if (cu->str == NULL) return ok;
        if (vfont == NULL) return ok;
  
-       vfd = vfont_get_data(bmain, vfont);
+       vfd = vfont_get_data(vfont);
  
        /* The VFont Data can not be found */
        if (!vfd) return ok;
@@@ -770,7 -770,7 +770,7 @@@ makebreak
                if (vfont == NULL) break;
  
                if (vfont != oldvfont) {
-                       vfd = vfont_get_data(bmain, vfont);
+                       vfd = vfont_get_data(vfont);
                        oldvfont = vfont;
                }
  
                        /* top and top-baseline are the same when text-boxes are used */
                        if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) {
                                /* all previous textboxes are 'full', only align the last used text-box */
 -                              float yoff;
 +                              float yoff = 0.0f;
                                int lines;
                                struct CharTrans *ct_last, *ct_textbox;
  
                else {
                        /* non text-box case handled separately */
                        ct = chartransdata;
 -                      float yoff;
 +                      float yoff = 0.0f;
  
                        if (cu->align_y == CU_ALIGN_Y_TOP) {
                                yoff = -linedist;
                        }
                        /* We do not want to see any character for \n or \r */
                        if (cha != '\n')
-                               buildchar(bmain, cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i);
+                               buildchar(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i);
  
                        if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) {
                                float ulwidth, uloverlap = 0.0f;
@@@ -1340,19 -1340,19 +1340,19 @@@ finally
  }
  
  
- bool BKE_vfont_to_curve_nubase(Main *bmain, Object *ob, int mode, ListBase *r_nubase)
+ bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
  {
        BLI_assert(ob->type == OB_FONT);
  
-       return BKE_vfont_to_curve_ex(bmain, ob, ob->data, mode, r_nubase,
+       return BKE_vfont_to_curve_ex(ob, ob->data, mode, r_nubase,
                                     NULL, NULL, NULL, NULL);
  }
  
- bool BKE_vfont_to_curve(Main *bmain, Object *ob, int mode)
+ bool BKE_vfont_to_curve(Object *ob, int mode)
  {
        Curve *cu = ob->data;
  
-       return BKE_vfont_to_curve_ex(bmain, ob, ob->data, mode, &cu->nurb, NULL, NULL, NULL, NULL);
+       return BKE_vfont_to_curve_ex(ob, ob->data, mode, &cu->nurb, NULL, NULL, NULL, NULL);
  }
  
  
index 73e7041fda84c1dd0f0d2c05280bfec9115ef5bd,4201bf3d3fb9e324812376617daa06d0bb6a726c..57cdfdebcd35d3d7274ac10eaecdc1a9992bc4c4
  #include "DNA_vfont_types.h"
  
  #include "BKE_animsys.h"
 +#include "BKE_collection.h"
  #include "BKE_DerivedMesh.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_font.h"
 -#include "BKE_group.h"
  #include "BKE_global.h"
 +#include "BKE_idprop.h"
  #include "BKE_lattice.h"
  #include "BKE_main.h"
  #include "BKE_mesh.h"
 +#include "BKE_mesh_runtime.h"
  #include "BKE_object.h"
  #include "BKE_particle.h"
  #include "BKE_scene.h"
  #include "BKE_editmesh.h"
  #include "BKE_anim.h"
  
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_query.h"
  
  #include "BLI_strict_flags.h"
  #include "BLI_hash.h"
  /* Dupli-Geometry */
  
  typedef struct DupliContext {
 -      EvaluationContext *eval_ctx;
 -      bool do_update;
 -      bool animated;
 -      Group *group; /* XXX child objects are selected from this group if set, could be nicer */
 +      Depsgraph *depsgraph;
 +      Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */
 +      Object *obedit; /* Only to check if the object is in edit-mode. */
  
 -      Main *bmain;
        Scene *scene;
 +      ViewLayer *view_layer;
        Object *object;
        float space_mat[4][4];
 -      unsigned int lay;
  
        int persistent_id[MAX_DUPLI_RECUR];
        int level;
@@@ -99,20 -98,23 +99,20 @@@ static const DupliGenerator *get_dupli_
  
  /* create initial context for root object */
  static void init_context(
 -        DupliContext *r_ctx, Main *bmain, EvaluationContext *eval_ctx,
 -        Scene *scene, Object *ob, float space_mat[4][4], bool update)
 +        DupliContext *r_ctx, Depsgraph *depsgraph,
 +        Scene *scene, Object *ob, float space_mat[4][4])
  {
 -      r_ctx->eval_ctx = eval_ctx;
 -      r_ctx->bmain = bmain;
 +      r_ctx->depsgraph = depsgraph;
        r_ctx->scene = scene;
 -      /* don't allow BKE_object_handle_update for viewport during render, can crash */
 -      r_ctx->do_update = update && !(G.is_rendering && eval_ctx->mode != DAG_EVAL_RENDER);
 -      r_ctx->animated = false;
 -      r_ctx->group = NULL;
 +      r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph);
 +      r_ctx->collection = NULL;
  
        r_ctx->object = ob;
 +      r_ctx->obedit = OBEDIT_FROM_OBACT(ob);
        if (space_mat)
                copy_m4_m4(r_ctx->space_mat, space_mat);
        else
                unit_m4(r_ctx->space_mat);
 -      r_ctx->lay = ob->lay;
        r_ctx->level = 0;
  
        r_ctx->gen = get_dupli_generator(r_ctx);
  }
  
  /* create sub-context for recursive duplis */
 -static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated)
 +static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
  {
        *r_ctx = *ctx;
        
 -      r_ctx->animated |= animated; /* object animation makes all children animated */
 -
        /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
 -      if (ctx->gen->type == OB_DUPLIGROUP)
 -              r_ctx->group = ctx->object->dup_group;
 +      if (ctx->gen->type == OB_DUPLICOLLECTION)
 +              r_ctx->collection = ctx->object->dup_group;
  
        r_ctx->object = ob;
        if (mat)
   * mat is transform of the object relative to current context (including object obmat)
   */
  static DupliObject *make_dupli(const DupliContext *ctx,
 -                               Object *ob, float mat[4][4], int index,
 -                               bool animated, bool hide)
 +                               Object *ob, float mat[4][4], int index)
  {
        DupliObject *dob;
        int i;
        dob->ob = ob;
        mul_m4_m4m4(dob->mat, (float (*)[4])ctx->space_mat, mat);
        dob->type = ctx->gen->type;
 -      dob->animated = animated || ctx->animated; /* object itself or some parent is animated */
  
        /* set persistent id, which is an array with a persistent index for each level
         * (particle number, vertex number, ..). by comparing this we can find the same
        for (; i < MAX_DUPLI_RECUR; i++)
                dob->persistent_id[i] = INT_MAX;
  
 -      if (hide)
 -              dob->no_draw = true;
        /* metaballs never draw in duplis, they are instead merged into one by the basis
         * mball outside of the group. this does mean that if that mball is not in the
         * scene, they will not show up at all, limitation that should be solved once. */
  /* recursive dupli objects
   * space_mat is the local dupli space (excluding dupli object obmat!)
   */
 -static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated)
 +static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index)
  {
 -      /* simple preventing of too deep nested groups with MAX_DUPLI_RECUR */
 +      /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */
        if (ctx->level < MAX_DUPLI_RECUR) {
                DupliContext rctx;
 -              copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated);
 +              copy_dupli_context(&rctx, ctx, ob, space_mat, index);
                if (rctx.gen) {
                        rctx.gen->make_duplis(&rctx);
                }
@@@ -227,38 -235,41 +227,38 @@@ static bool is_child(const Object *ob, 
        return false;
  }
  
 -/* create duplis from every child in scene or group */
 +/* create duplis from every child in scene or collection */
  static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb)
  {
        Object *parent = ctx->object;
 -      Object *obedit = ctx->scene->obedit;
 -
 -      if (ctx->group) {
 -              unsigned int lay = ctx->group->layer;
 -              int groupid = 0;
 -              GroupObject *go;
 -              for (go = ctx->group->gobject.first; go; go = go->next, groupid++) {
 -                      Object *ob = go->ob;
  
 -                      if ((ob->lay & lay) && ob != obedit && is_child(ob, parent)) {
 +      if (ctx->collection) {
 +              int collectionid = 0;
 +              FOREACH_COLLECTION_BASE_RECURSIVE_BEGIN(ctx->collection, base)
 +              {
 +                      Object *ob = base->object;
 +                      if ((base->flag & BASE_VISIBLED) && ob != ctx->obedit && is_child(ob, parent)) {
                                DupliContext pctx;
 -                              copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false);
 +                              copy_dupli_context(&pctx, ctx, ctx->object, NULL, collectionid);
  
                                /* mballs have a different dupli handling */
 -                              if (ob->type != OB_MBALL)
 +                              if (ob->type != OB_MBALL) {
                                        ob->flag |= OB_DONE;  /* doesnt render */
 -
 +                              }
                                make_child_duplis_cb(&pctx, userdata, ob);
                        }
 +                      collectionid++;
                }
 +              FOREACH_COLLECTION_BASE_RECURSIVE_END
        }
        else {
 -              unsigned int lay = ctx->scene->lay;
                int baseid = 0;
 -              Base *base;
 -              for (base = ctx->scene->base.first; base; base = base->next, baseid++) {
 +              ViewLayer *view_layer = ctx->view_layer;
 +              for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) {
                        Object *ob = base->object;
 -
 -                      if ((base->lay & lay) && ob != obedit && is_child(ob, parent)) {
 +                      if ((ob != ctx->obedit) && is_child(ob, parent)) {
                                DupliContext pctx;
 -                              copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false);
 +                              copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid);
  
                                /* mballs have a different dupli handling */
                                if (ob->type != OB_MBALL)
  
  /*---- Implementations ----*/
  
 -/* OB_DUPLIGROUP */
 -static void make_duplis_group(const DupliContext *ctx)
 +/* OB_DUPLICOLLECTION */
 +static void make_duplis_collection(const DupliContext *ctx)
  {
 -      bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
        Object *ob = ctx->object;
 -      Group *group;
 -      GroupObject *go;
 -      float group_mat[4][4];
 +      Collection *collection;
 +      Base *base;
 +      float collection_mat[4][4];
        int id;
 -      bool animated, hide;
  
        if (ob->dup_group == NULL) return;
 -      group = ob->dup_group;
 +      collection = ob->dup_group;
  
 -      /* combine group offset and obmat */
 -      unit_m4(group_mat);
 -      sub_v3_v3(group_mat[3], group->dupli_ofs);
 -      mul_m4_m4m4(group_mat, ob->obmat, group_mat);
 +      /* combine collection offset and obmat */
 +      unit_m4(collection_mat);
 +      sub_v3_v3(collection_mat[3], collection->dupli_ofs);
 +      mul_m4_m4m4(collection_mat, ob->obmat, collection_mat);
        /* don't access 'ob->obmat' from now on. */
  
 -      /* handles animated groups */
 -
 -      /* we need to check update for objects that are not in scene... */
 -      if (ctx->do_update) {
 -              /* note: update is optional because we don't always need object
 -               * transformations to be correct. Also fixes bug [#29616]. */
 -              BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, ctx->scene, ob, group);
 -      }
 -
 -      animated = BKE_group_is_animated(group, ob);
 -
 -      for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
 -              /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
 -              if (go->ob != ob) {
 +      const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection);
 +      for (base = dup_collection_objects.first, id = 0; base; base = base->next, id++) {
 +              if (base->object != ob && (base->flag & BASE_VISIBLED)) {
                        float mat[4][4];
  
 -                      /* Special case for instancing dupli-groups, see: T40051
 -                       * this object may be instanced via dupli-verts/faces, in this case we don't want to render
 -                       * (blender convention), but _do_ show in the viewport.
 -                       *
 -                       * Regular objects work fine but not if we're instancing dupli-groups,
 -                       * because the rules for rendering aren't applied to objects they instance.
 -                       * We could recursively pass down the 'hide' flag instead, but that seems unnecessary.
 -                       */
 -                      if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) {
 -                              continue;
 -                      }
 -
 -                      /* group dupli offset, should apply after everything else */
 -                      mul_m4_m4m4(mat, group_mat, go->ob->obmat);
 +                      /* collection dupli offset, should apply after everything else */
 +                      mul_m4_m4m4(mat, collection_mat, base->object->obmat);
  
 -                      /* check the group instance and object layers match, also that the object visible flags are ok. */
 -                      hide = (go->ob->lay & group->layer) == 0 ||
 -                             (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW);
 -
 -                      make_dupli(ctx, go->ob, mat, id, animated, hide);
 +                      make_dupli(ctx, base->object, mat, id);
  
                        /* recursion */
 -                      make_recursive_duplis(ctx, go->ob, group_mat, id, animated);
 +                      make_recursive_duplis(ctx, base->object, collection_mat, id);
                }
        }
  }
  
 -static const DupliGenerator gen_dupli_group = {
 -    OB_DUPLIGROUP,                  /* type */
 -    make_duplis_group               /* make_duplis */
 +static const DupliGenerator gen_dupli_collection = {
 +    OB_DUPLICOLLECTION,             /* type */
 +    make_duplis_collection          /* make_duplis */
  };
  
  /* OB_DUPLIFRAMES */
  static void make_duplis_frames(const DupliContext *ctx)
  {
 +      Depsgraph *depsgraph = ctx->depsgraph;
        Scene *scene = ctx->scene;
        Object *ob = ctx->object;
        extern int enable_cu_speed; /* object.c */
        int cfrao = scene->r.cfra;
        int dupend = ob->dupend;
  
 -      /* dupliframes not supported inside groups */
 -      if (ctx->group)
 +      /* dupliframes not supported inside collections */
 +      if (ctx->collection)
                return;
        /* if we don't have any data/settings which will lead to object movement,
         * don't waste time trying, as it will all look the same...
        /* duplicate over the required range */
        if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed = 0;
  
 -      /* special flag to avoid setting recalc flags to notify the depsgraph of
 -       * updates, as this is not a permanent change to the object */
 -      ob->id.recalc |= ID_RECALC_SKIP_ANIM_TAG;
 -
        for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) {
                int ok = 1;
  
                         * and/or other objects which may affect this object's transforms are not updated either.
                         * However, this has always been the way that this worked (i.e. pre 2.5), so I guess that it'll be fine!
                         */
 -                      BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */
 -                      BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra);
 +                      /* ob-eval will do drivers, so we don't need to do them */
 +                      BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM);
 +                      BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra);
  
 -                      make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false);
 +                      make_dupli(ctx, ob, ob->obmat, scene->r.cfra);
                }
        }
  
         */
        scene->r.cfra = cfrao;
  
 -      BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */
 -      BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra);
 +      /* ob-eval will do drivers, so we don't need to do them */
 +      BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM);
 +      BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra);
  
        /* but, to make sure unkeyed object transforms are still sane,
         * let's copy object's original data back over
@@@ -449,13 -490,13 +449,13 @@@ static void vertex_dupli__mapFunc(void 
         */
        mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
  
 -      dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false);
 +      dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index);
  
        if (vdd->orco)
                copy_v3_v3(dob->orco, vdd->orco[index]);
  
        /* recursion */
 -      make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index, false);
 +      make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index);
  }
  
  static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child)
@@@ -498,7 -539,7 +498,7 @@@ static void make_duplis_verts(const Dup
  {
        Scene *scene = ctx->scene;
        Object *parent = ctx->object;
 -      bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
 +      bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
        VertexDupliData vdd;
  
        vdd.ctx = ctx;
                BMEditMesh *em = BKE_editmesh_from_object(parent);
                CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH);
  
 -              if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
 -                      vdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
 +              if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER) {
 +                      vdd.dm = mesh_create_derived_render(ctx->depsgraph, scene, parent, dm_mask);
                }
                else if (em) {
 -                      vdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
 +                      vdd.dm = editbmesh_get_derived_cage(ctx->depsgraph, scene, parent, em, dm_mask);
                }
                else {
 -                      vdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
 +                      vdd.dm = mesh_get_derived_final(ctx->depsgraph, scene, parent, dm_mask);
                }
                vdd.edit_btmesh = me->edit_btmesh;
  
@@@ -540,7 -581,7 +540,7 @@@ static const DupliGenerator gen_dupli_v
  };
  
  /* OB_DUPLIVERTS - FONT */
- static Object *find_family_object(const char *family, size_t family_len, unsigned int ch, GHash *family_gh)
+ static Object *find_family_object(Main *bmain, const char *family, size_t family_len, unsigned int ch, GHash *family_gh)
  {
        Object **ob_pt;
        Object *ob;
                ch_utf8[ch_utf8_len] = '\0';
                ch_utf8_len += 1;  /* compare with null terminator */
  
-               for (ob = G.main->object.first; ob; ob = ob->id.next) {
+               for (ob = bmain->object.first; ob; ob = ob->id.next) {
                        if (STREQLEN(ob->id.name + 2 + family_len, ch_utf8, ch_utf8_len)) {
                                if (STREQLEN(ob->id.name + 2, family, family_len)) {
                                        break;
@@@ -585,15 -626,15 +585,15 @@@ static void make_duplis_font(const Dupl
        const wchar_t *text = NULL;
        bool text_free = false;
  
 -      /* font dupliverts not supported inside groups */
 -      if (ctx->group)
 +      /* font dupliverts not supported inside collections */
 +      if (ctx->collection)
                return;
  
        copy_m4_m4(pmat, par->obmat);
  
        /* in par the family name is stored, use this to find the other objects */
  
-       BKE_vfont_to_curve_ex(G.main, par, par->data, FO_DUPLI, NULL,
+       BKE_vfont_to_curve_ex(par, par->data, FO_DUPLI, NULL,
                              &text, &text_len, &text_free, &chartransdata);
  
        if (text == NULL || chartransdata == NULL) {
        /* advance matching BLI_strncpy_wchar_from_utf8 */
        for (a = 0; a < text_len; a++, ct++) {
  
-               ob = find_family_object(cu->family, family_len, (unsigned int)text[a], family_gh);
 -              ob = find_family_object(ctx->bmain, cu->family, family_len, (unsigned int)text[a], family_gh);
++              /* XXX That G.main is *really* ugly, but not sure what to do here...
++               * Definitively don't think it would be safe to put back Main *bmain pointer in DupliContext as done in 2.7x? */
++              ob = find_family_object(G.main, cu->family, family_len, (unsigned int)text[a], family_gh);
                if (ob) {
                        vec[0] = fsize * (ct->xof - xof);
                        vec[1] = fsize * (ct->yof - yof);
  
                        copy_v3_v3(obmat[3], vec);
  
 -                      make_dupli(ctx, ob, obmat, a, false, false);
 +                      make_dupli(ctx, ob, obmat, a);
                }
        }
  
@@@ -702,7 -743,7 +704,7 @@@ static void make_child_duplis_faces(con
        float (*orco)[3] = fdd->orco;
        MLoopUV *mloopuv = fdd->mloopuv;
        int a, totface = fdd->totface;
 -      bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
 +      bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
        float child_imat[4][4];
        DupliObject *dob;
  
                 */
                mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
  
 -              dob = make_dupli(ctx, inst_ob, obmat, a, false, false);
 +              dob = make_dupli(ctx, inst_ob, obmat, a);
                if (use_texcoords) {
                        float w = 1.0f / (float)mp->totloop;
  
                }
  
                /* recursion */
 -              make_recursive_duplis(ctx, inst_ob, space_mat, a, false);
 +              make_recursive_duplis(ctx, inst_ob, space_mat, a);
        }
  }
  
@@@ -768,7 -809,7 +770,7 @@@ static void make_duplis_faces(const Dup
  {
        Scene *scene = ctx->scene;
        Object *parent = ctx->object;
 -      bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
 +      bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
        FaceDupliData fdd;
  
        fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0);
                BMEditMesh *em = BKE_editmesh_from_object(parent);
                CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH);
  
 -              if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
 -                      fdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
 +              if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER) {
 +                      fdd.dm = mesh_create_derived_render(ctx->depsgraph, scene, parent, dm_mask);
                }
                else if (em) {
 -                      fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
 +                      fdd.dm = editbmesh_get_derived_cage(ctx->depsgraph, scene, parent, em, dm_mask);
                }
                else {
 -                      fdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
 +                      fdd.dm = mesh_get_derived_final(ctx->depsgraph, scene, parent, dm_mask);
                }
  
                if (use_texcoords) {
@@@ -820,9 -861,10 +822,9 @@@ static void make_duplis_particle_system
  {
        Scene *scene = ctx->scene;
        Object *par = ctx->object;
 -      bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER;
 -      bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
 +      bool for_render = DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER;
 +      bool use_texcoords = for_render;
  
 -      GroupObject *go;
        Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL;
        DupliObject *dob;
        ParticleDupliWeight *dw;
        float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0;
        float (*obmat)[4];
        int a, b, hair = 0;
 -      int totpart, totchild, totgroup = 0 /*, pa_num */;
 -      const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene);
 +      int totpart, totchild, totcollection = 0 /*, pa_num */;
 +      RNG *rng;
  
        int no_draw_flag = PARS_UNEXIST;
  
        if (part == NULL)
                return;
  
 -      if (!psys_check_enabled(par, psys, (ctx->eval_ctx->mode == DAG_EVAL_RENDER)))
 +      if (!psys_check_enabled(par, psys, (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER)))
                return;
  
        if (!for_render)
                no_draw_flag |= PARS_NO_DISP;
  
 -      ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */
 +      ctime = DEG_get_ctime(ctx->depsgraph); /* NOTE: in old animsys, used parent object's timeoffset... */
  
        totpart = psys->totpart;
        totchild = psys->totchild;
  
 -      BLI_srandom((unsigned int)(31415926 + psys->seed));
 +      rng = BLI_rng_new_srandom(31415926u + (unsigned int)psys->seed);
  
 -      if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
 +      if ((for_render || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
                ParticleSimulationData sim = {NULL};
 +              sim.depsgraph = ctx->depsgraph;
                sim.scene = scene;
                sim.ob = par;
                sim.psys = psys;
                                return;
                }
                else { /*PART_DRAW_GR */
 -                      if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject))
 +                      if (part->dup_group == NULL)
                                return;
  
 -                      if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) {
 +                      const ListBase dup_collection_objects = BKE_collection_object_cache_get(part->dup_group);
 +                      if (BLI_listbase_is_empty(&dup_collection_objects))
 +                              return;
 +
 +                      if (BLI_findptr(&dup_collection_objects, par, offsetof(Base, object))) {
                                return;
                        }
                }
  
                /* gather list of objects or single object */
                if (part->ren_as == PART_DRAW_GR) {
 -                      if (ctx->do_update) {
 -                              BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, scene, par, part->dup_group);
 -                      }
 -
                        if (part->draw & PART_DRAW_COUNT_GR) {
                                for (dw = part->dupliweights.first; dw; dw = dw->next)
 -                                      totgroup += dw->count;
 +                                      totcollection += dw->count;
                        }
                        else {
 -                              for (go = part->dup_group->gobject.first; go; go = go->next)
 -                                      totgroup++;
 +                              FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object)
 +                              {
 +                                      (void) object;
 +                                      totcollection++;
 +                              }
 +                              FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
                        }
  
                        /* we also copy the actual objects to restore afterwards, since
                         * BKE_object_where_is_calc_time will change the object which breaks transform */
 -                      oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list");
 -                      obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list");
 +                      oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list");
 +                      obcopylist = MEM_callocN((size_t)totcollection * sizeof(Object), "dupcollection copy list");
  
 -                      if (part->draw & PART_DRAW_COUNT_GR && totgroup) {
 +                      if (part->draw & PART_DRAW_COUNT_GR && totcollection) {
                                dw = part->dupliweights.first;
  
 -                              for (a = 0; a < totgroup; dw = dw->next) {
 +                              for (a = 0; a < totcollection; dw = dw->next) {
                                        for (b = 0; b < dw->count; b++, a++) {
                                                oblist[a] = dw->ob;
                                                obcopylist[a] = *dw->ob;
                                }
                        }
                        else {
 -                              go = part->dup_group->gobject.first;
 -                              for (a = 0; a < totgroup; a++, go = go->next) {
 -                                      oblist[a] = go->ob;
 -                                      obcopylist[a] = *go->ob;
 +                              a = 0;
 +                              FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object)
 +                              {
 +                                      oblist[a] = object;
 +                                      obcopylist[a] = *object;
 +                                      a++;
 +
 +                                      if (a >= totcollection) {
 +                                              continue;
 +                                      }
                                }
 +                              FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
                        }
                }
                else {
  
                        if (part->ren_as == PART_DRAW_GR) {
                                /* prevent divide by zero below [#28336] */
 -                              if (totgroup == 0)
 +                              if (totcollection == 0)
                                        continue;
  
 -                              /* for groups, pick the object based on settings */
 +                              /* for collections, pick the object based on settings */
                                if (part->draw & PART_DRAW_RAND_GR)
 -                                      b = BLI_rand() % totgroup;
 +                                      b = BLI_rng_get_int(rng) % totcollection;
                                else
 -                                      b = a % totgroup;
 +                                      b = a % totcollection;
  
                                ob = oblist[b];
                                obmat = oblist[b]->obmat;
                        }
  
                        if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
 -                              for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) {
 -
 +                              b = 0;
 +                              FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object)
 +                              {
                                        copy_m4_m4(tmat, oblist[b]->obmat);
 +
                                        /* apply particle scale */
                                        mul_mat3_m4_fl(tmat, size * scale);
                                        mul_v3_fl(tmat[3], size * scale);
 -                                      /* group dupli offset, should apply after everything else */
 -                                      if (!is_zero_v3(part->dup_group->dupli_ofs))
 +
 +                                      /* collection dupli offset, should apply after everything else */
 +                                      if (!is_zero_v3(part->dup_group->dupli_ofs)) {
                                                sub_v3_v3(tmat[3], part->dup_group->dupli_ofs);
 +                                      }
 +
                                        /* individual particle transform */
                                        mul_m4_m4m4(mat, pamat, tmat);
  
 -                                      dob = make_dupli(ctx, go->ob, mat, a, false, false);
 +                                      dob = make_dupli(ctx, object, mat, a);
                                        dob->particle_system = psys;
 -                                      if (use_texcoords)
 +
 +                                      if (use_texcoords) {
                                                psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
 +                                      }
 +
 +                                      b++;
                                }
 +                              FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
                        }
                        else {
                                /* to give ipos in object correct offset */
 -                              BKE_object_where_is_calc_time(scene, ob, ctime - pa_time);
 +                              BKE_object_where_is_calc_time(ctx->depsgraph, scene, ob, ctime - pa_time);
  
                                copy_v3_v3(vec, obmat[3]);
                                obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;
                                if (part->draw & PART_DRAW_GLOBAL_OB)
                                        add_v3_v3v3(mat[3], mat[3], vec);
  
 -                              dob = make_dupli(ctx, ob, mat, a, false, false);
 +                              dob = make_dupli(ctx, ob, mat, a);
                                dob->particle_system = psys;
                                if (use_texcoords)
                                        psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
 -                              /* XXX blender internal needs this to be set to dupligroup to render
 -                               * groups correctly, but we don't want this hack for cycles */
 -                              if (dupli_type_hack && ctx->group)
 -                                      dob->type = OB_DUPLIGROUP;
                        }
                }
  
                /* restore objects since they were changed in BKE_object_where_is_calc_time */
                if (part->ren_as == PART_DRAW_GR) {
 -                      for (a = 0; a < totgroup; a++)
 +                      for (a = 0; a < totcollection; a++)
                                *(oblist[a]) = obcopylist[a];
                }
                else
                end_latt_deform(psys->lattice_deform_data);
                psys->lattice_deform_data = NULL;
        }
 +
 +      BLI_rng_free(rng);
  }
  
  static void make_duplis_particles(const DupliContext *ctx)
        for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) {
                /* particles create one more level for persistent psys index */
                DupliContext pctx;
 -              copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid, false);
 +              copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid);
                make_duplis_particle_system(&pctx, psys);
        }
  }
@@@ -1167,7 -1189,7 +1169,7 @@@ static const DupliGenerator *get_dupli_
                return NULL;
  
        /* Should the dupli's be generated for this object? - Respect restrict flags */
 -      if (ctx->eval_ctx->mode == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
 +      if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
                return NULL;
  
        if (transflag & OB_DUPLIPARTS) {
        else if (transflag & OB_DUPLIFRAMES) {
                return &gen_dupli_frames;
        }
 -      else if (transflag & OB_DUPLIGROUP) {
 -              return &gen_dupli_group;
 +      else if (transflag & OB_DUPLICOLLECTION) {
 +              return &gen_dupli_collection;
        }
  
        return NULL;
  /* ---- ListBase dupli container implementation ---- */
  
  /* Returns a list of DupliObject */
 -ListBase *object_duplilist_ex(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update)
 +ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
  {
        ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
        DupliContext ctx;
 -      init_context(&ctx, bmain, eval_ctx, scene, ob, NULL, update);
 +      init_context(&ctx, depsgraph, sce, ob, NULL);
        if (ctx.gen) {
                ctx.duplilist = duplilist;
                ctx.gen->make_duplis(&ctx);
        return duplilist;
  }
  
 -/* note: previously updating was always done, this is why it defaults to be on
 - * but there are likely places it can be called without updating */
 -ListBase *object_duplilist(Main *bmain, EvaluationContext *eval_ctx, Scene *sce, Object *ob)
 -{
 -      return object_duplilist_ex(bmain, eval_ctx, sce, ob, true);
 -}
 -
  void free_object_duplilist(ListBase *lb)
  {
        BLI_freelistN(lb);
@@@ -1248,7 -1277,7 +1250,7 @@@ int count_duplilist(Object *ob
        return 1;
  }
  
 -DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
 +DupliApplyData *duplilist_apply(Depsgraph *depsgraph, Object *ob, Scene *scene, ListBase *duplilist)
  {
        DupliApplyData *apply_data = NULL;
        int num_objects = BLI_listbase_count(duplilist);
                for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
                        /* make sure derivedmesh is calculated once, before drawing */
                        if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) {
 -                              mesh_get_derived_final(scene, dob->ob, scene->customdata_mask);
 +                              mesh_get_derived_final(depsgraph, scene, dob->ob, scene->customdata_mask);
                                dob->ob->transflag |= OB_DUPLICALCDERIVED;
                        }
                }
index 7cdfafdad43c4d7764d3be4fa40a00eb9279617c,bc4a4d0105dc2a1b006996d1a5ffda1ac0f4ab4e..75efdec3dd21e252058791611d808fe933939e5a
  
  #include "BKE_context.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_font.h"
  #include "BKE_library.h"
  #include "BKE_main.h"
  #include "BKE_object.h"
  #include "BKE_report.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "RNA_access.h"
  #include "RNA_define.h"
  
@@@ -246,7 -245,6 +246,6 @@@ static int insert_into_textbuf(Object *
  
  static void text_update_edited(bContext *C, Object *obedit, int mode)
  {
-       struct Main *bmain = CTX_data_main(C);
        Curve *cu = obedit->data;
        EditFont *ef = cu->editfont;
  
        /* run update first since it can move the cursor */
        if (mode == FO_EDIT) {
                /* re-tesselllate */
 -              DAG_id_tag_update(obedit->data, 0);
 +              DEG_id_tag_update(obedit->data, 0);
        }
        else {
                /* depsgraph runs above, but since we're not tagging for update, call direct */
-               BKE_vfont_to_curve(bmain, obedit, mode);
+               BKE_vfont_to_curve(obedit, mode);
        }
  
        cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
                }
        }
  
 +      BKE_curve_batch_cache_dirty(cu, BKE_CURVE_BATCH_DIRTY_SELECT);
 +
        WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
  }
  
@@@ -422,9 -418,7 +421,9 @@@ void FONT_OT_text_paste_from_file(wmOpe
  static void txt_add_object(bContext *C, TextLine *firstline, int totline, const float offset[3])
  {
        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);
        Curve *cu;
        Object *obedit;
        Base *base;
        int a;
        float rot[3] = {0.f, 0.f, 0.f};
  
 -      obedit = BKE_object_add(bmain, scene, OB_FONT, NULL);
 -      base = scene->basact;
 +      obedit = BKE_object_add(bmain, scene, view_layer, OB_FONT, NULL);
 +      base = view_layer->basact;
  
        /* seems to assume view align ? TODO - look into this, could be an operator option */
        ED_object_base_init_transform(C, base, NULL, rot);
  
 -      BKE_object_where_is_calc(scene, obedit);
 +      BKE_object_where_is_calc(depsgraph, scene, obedit);
  
        add_v3_v3(obedit->loc, offset);
  
@@@ -587,7 -581,7 +586,7 @@@ static int set_style(bContext *C, cons
                        ef->textbufinfo[i].flag |= style;
        }
  
 -      DAG_id_tag_update(obedit->data, 0);
 +      DEG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
  
        return OPERATOR_FINISHED;
@@@ -982,16 -976,14 +981,14 @@@ static int move_cursor(bContext *C, in
        /* apply virtical cursor motion to position immediately
         * otherwise the selection will lag behind */
        if (FO_CURS_IS_MOTION(cursmove)) {
-               struct Main *bmain = CTX_data_main(C);
-               BKE_vfont_to_curve(bmain, obedit, cursmove);
+               BKE_vfont_to_curve(obedit, cursmove);
                cursmove = FO_CURS;
        }
  
        if (select == 0) {
                if (ef->selstart) {
-                       struct Main *bmain = CTX_data_main(C);
                        ef->selstart = ef->selend = 0;
-                       BKE_vfont_to_curve(bmain, obedit, FO_SELCHANGE);
+                       BKE_vfont_to_curve(obedit, FO_SELCHANGE);
                }
        }
  
index e079cfd1d904d98f73198937663c4b7ef252dc06,10121e8ae2f12908ef5c0ca696f7ab4a86935f06..d75d5de0dbd96256e6b45c207a4392d37d9dec4b
@@@ -45,9 -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
@@@ -147,16 -146,6 +147,16 @@@ static const EnumPropertyItem field_typ
        {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])
        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);
  }
@@@ -218,7 -207,6 +218,7 @@@ void ED_object_base_init_transform(bCon
  {
        Object *ob = base->object;
        Scene *scene = CTX_data_scene(C);
 +      Depsgraph *depsgraph = CTX_data_depsgraph(C);
  
        if (!scene) return;
  
        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.
@@@ -306,7 -294,7 +306,7 @@@ void ED_object_add_generic_props(wmOper
  
  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,
@@@ -416,11 -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... */
        }
  
        /* 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)
  
        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;
  }
  
@@@ -504,79 -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 */
@@@ -620,7 -535,7 +620,7 @@@ static int effector_add_exec(bContext *
  
        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;
  }
@@@ -725,7 -640,7 +725,7 @@@ static int object_metaball_add_exec(bCo
                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);
@@@ -829,7 -744,7 +829,7 @@@ static int object_armature_add_exec(bCo
                newob = true;
        }
        else {
 -              DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
 +              DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
        }
  
        if (obedit == NULL) {
@@@ -1017,7 -932,7 +1017,7 @@@ static int object_lamp_add_exec(bContex
        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;
        }
@@@ -1048,12 -963,12 +1048,12 @@@ void OBJECT_OT_lamp_add(wmOperatorType 
        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];
  
                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;
                }
        }
        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);
  
  }
  
  /* 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);
@@@ -1190,22 -1096,35 +1190,22 @@@ void OBJECT_OT_speaker_add(wmOperatorTy
  
  /**************************** 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)
        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;
                }
  
                 * 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;
                }
                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);
                                }
                        }
                }
        /* 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);
@@@ -1333,13 -1262,15 +1333,13 @@@ static void copy_object_set_idnew(bCont
        }
        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)
  }
  
  /**
 - * \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)
@@@ -1412,8 -1343,6 +1412,8 @@@ static void make_object_duplilist_real(
                                         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;
                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 {
                        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);
                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);
  
                /* 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 */
                                 * 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));
                        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);
                        }
                }
        }
@@@ -1586,7 -1518,7 +1586,7 @@@ static int object_duplicates_make_real_
        }
        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);
  
@@@ -1620,43 -1552,46 +1620,43 @@@ static const EnumPropertyItem convert_t
        {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;
        }
  
        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;
        /* 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) */
                        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");
        {
                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.
                                            "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) {
                        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  */
                                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! */
                        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  */
                        }
                        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);
  
                        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  */
                         *               datablock, but for until we've got granular update
                         *               lets take care by selves.
                         */
-                       BKE_vfont_to_curve(bmain, newob, FO_EDIT);
+                       BKE_vfont_to_curve(newob, FO_EDIT);
  
                        newob->type = OB_CURVE;
                        cu->type = OB_CURVE;
                                        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);
                                                }
                                        }
                                }
                        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);
  
                        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  */
                                        newob = ob;
                                }
  
 -                              curvetomesh(bmain, scene, newob);
 +                              curvetomesh(bmain, depsgraph, scene, newob);
  
                                /* meshes doesn't use displist */
                                BKE_object_free_curve_cache(newob);
                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 */
                        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;
                                        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) {
                }
  
                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 */
                }
        }
  
        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);
  
        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);
  
@@@ -2056,43 -1998,39 +2056,43 @@@ void OBJECT_OT_convert(wmOperatorType *
  /* 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);
                        }
                }
  
                                }
                                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) {
                        }
  
                        if (dupflag & USER_DUP_ACT) {
 -                              bActuator *act;
 -
                                BKE_animdata_copy_id_action(bmain, (ID *)obn->data, true);
                                if (key) {
                                        BKE_animdata_copy_id_action(bmain, (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) {
   * 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;
        }
  
        /* 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);
@@@ -2321,29 -2277,29 +2321,29 @@@ static int duplicate_exec(bContext *C, 
  {
        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;
  
        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);
  
@@@ -2390,9 -2344,9 +2390,9 @@@ static int add_named_exec(bContext *C, 
        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;
                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) {
                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);
@@@ -2476,9 -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;
        }
@@@ -2529,9 -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;
        }