Merge branch 'master' into blender2.8
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Tue, 14 Aug 2018 13:41:11 +0000 (15:41 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Tue, 14 Aug 2018 13:41:11 +0000 (15:41 +0200)
1  2 
source/blender/editors/object/object_add.c

index 8b4412ed6f97f12d03a0db0efbc698102d4416d3,efc69c36cc38a39670e3297667cf4a0b6b835e03..f322e544307a75c4d7d5f10a77eeda11fadfdc75
@@@ -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_gpencil.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 "ED_armature.h"
  #include "ED_curve.h"
 +#include "ED_gpencil.h"
  #include "ED_mball.h"
  #include "ED_mesh.h"
  #include "ED_node.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
   * kept here because of linking order.
   * Icons are only defined here */
 -const EnumPropertyItem rna_enum_lamp_type_items[] = {
 -      {LA_LOCAL, "POINT", ICON_LAMP_POINT, "Point", "Omnidirectional point light source"},
 -      {LA_SUN, "SUN", ICON_LAMP_SUN, "Sun", "Constant direction parallel ray light source"},
 -      {LA_SPOT, "SPOT", ICON_LAMP_SPOT, "Spot", "Directional cone light source"},
 -      {LA_HEMI, "HEMI", ICON_LAMP_HEMI, "Hemi", "180 degree constant light source"},
 -      {LA_AREA, "AREA", ICON_LAMP_AREA, "Area", "Directional area light source"},
 +const EnumPropertyItem rna_enum_light_type_items[] = {
 +      {LA_LOCAL, "POINT", ICON_LIGHT_POINT, "Point", "Omnidirectional point light source"},
 +      {LA_SUN, "SUN", ICON_LIGHT_SUN, "Sun", "Constant direction parallel ray light source"},
 +      {LA_SPOT, "SPOT", ICON_LIGHT_SPOT, "Spot", "Directional cone light source"},
 +      {LA_HEMI, "HEMI", ICON_LIGHT_HEMI, "Hemi", "180 degree constant light source"},
 +      {LA_AREA, "AREA", ICON_LIGHT_AREA, "Area", "Directional area light source"},
        {0, NULL, 0, NULL, NULL}
  };
  
@@@ -149,16 -146,6 +149,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);
  }
@@@ -220,7 -207,6 +220,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.
@@@ -308,7 -294,7 +308,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,
@@@ -419,11 -405,10 +419,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;
  }
  
@@@ -507,79 -493,6 +507,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 */
@@@ -623,7 -536,7 +623,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;
  }
@@@ -728,7 -641,7 +728,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);
@@@ -832,7 -745,7 +832,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) {
@@@ -934,7 -847,6 +934,7 @@@ static int empty_drop_named_image_invok
        /* if empty under cursor, then set object */
        if (base && base->object->type == OB_EMPTY) {
                ob = base->object;
 +              DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
                WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
        }
        else {
  
                /* add under the mouse */
                ED_object_location_from_view(C, ob->loc);
 -              ED_view3d_cursor3d_position(C, event->mval, ob->loc);
 +              ED_view3d_cursor3d_position(C, event->mval, false, ob->loc);
        }
  
        BKE_object_empty_draw_type_set(ob, OB_EMPTY_IMAGE);
@@@ -987,122 -899,9 +987,122 @@@ void OBJECT_OT_drop_named_image(wmOpera
        ED_object_add_generic_props(ot, false);
  }
  
 -/********************* Add Lamp Operator ********************/
 +/********************* Add Gpencil Operator ********************/
  
 -static const char *get_lamp_defname(int type)
 +static int object_gpencil_add_exec(bContext *C, wmOperator *op)
 +{
 +      Object *ob = CTX_data_active_object(C);
 +      bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? ob->data : NULL;
 +
 +      const int type = RNA_enum_get(op->ptr, "type");
 +
 +      float loc[3], rot[3];
 +      unsigned int layer;
 +      bool newob = false;
 +
 +      /* Hack: Force view-align to be on by default
 +       * since it's not nice for adding shapes in 2D
 +       * for them to end up aligned oddly, but only for Monkey
 +       */
 +      if ((RNA_struct_property_is_set(op->ptr, "view_align") == false) &&
 +          (type == GP_MONKEY))
 +      {
 +              RNA_boolean_set(op->ptr, "view_align", true);
 +      }
 +
 +      /* Note: We use 'Y' here (not 'Z'), as */
 +      WM_operator_view3d_unit_defaults(C, op);
 +      if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &layer, NULL))
 +              return OPERATOR_CANCELLED;
 +
 +      /* add new object if not currently editing a GP object,
 +       * or if "empty" was chosen (i.e. user wants a blank GP canvas)
 +       */
 +      if ((gpd == NULL) || (GPENCIL_ANY_MODE(gpd) == false) || (type == GP_EMPTY)) {
 +              const char *ob_name = (type == GP_MONKEY) ? "Suzanne" : NULL;
 +              float radius = RNA_float_get(op->ptr, "radius");
 +
 +              ob = ED_object_add_type(C, OB_GPENCIL, ob_name, loc, rot, true, layer);
 +              gpd = ob->data;
 +              newob = true;
 +
 +              BKE_object_obdata_size_init(ob, GP_OBGPENCIL_DEFAULT_SIZE * radius);
 +      }
 +      else {
 +              DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +              WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_ADDED, NULL);
 +      }
 +
 +      /* create relevant geometry */
 +      switch (type) {
 +              case GP_STROKE:
 +              {
 +                      float radius = RNA_float_get(op->ptr, "radius");
 +                      float mat[4][4];
 +
 +                      ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
 +                      mul_v3_fl(mat[0], radius);
 +                      mul_v3_fl(mat[1], radius);
 +                      mul_v3_fl(mat[2], radius);
 +
 +                      ED_gpencil_create_stroke(C, mat);
 +                      break;
 +              }
 +              case GP_MONKEY:
 +              {
 +                      float radius = RNA_float_get(op->ptr, "radius");
 +                      float mat[4][4];
 +
 +                      ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
 +                      mul_v3_fl(mat[0], radius);
 +                      mul_v3_fl(mat[1], radius);
 +                      mul_v3_fl(mat[2], radius);
 +
 +                      ED_gpencil_create_monkey(C, mat);
 +                      break;
 +              }
 +              case GP_EMPTY:
 +                      /* do nothing */
 +                      break;
 +
 +              default:
 +                      BKE_report(op->reports, RPT_WARNING, "Not implemented");
 +                      break;
 +      }
 +
 +      /* if this is a new object, initialise default stuff (colors, etc.) */
 +      if (newob) {
 +              ED_gpencil_add_defaults(C);
 +      }
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OBJECT_OT_gpencil_add(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Add GPencil";
 +      ot->description = "Add a grease pencil object to the scene";
 +      ot->idname = "OBJECT_OT_gpencil_add";
 +
 +      /* api callbacks */
 +      ot->invoke = WM_menu_invoke;
 +      ot->exec = object_gpencil_add_exec;
 +      ot->poll = ED_operator_scene_editable;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      /* properties */
 +      ED_object_add_unit_props(ot);
 +      ED_object_add_generic_props(ot, false);
 +
 +      ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", "");
 +}
 +
 +/********************* Add Light Operator ********************/
 +
 +static const char *get_light_defname(int type)
  {
        switch (type) {
                case LA_LOCAL: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Point");
                case LA_HEMI: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Hemi");
                case LA_AREA: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Area");
                default:
 -                      return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Lamp");
 +                      return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Light");
        }
  }
  
 -static int object_lamp_add_exec(bContext *C, wmOperator *op)
 +static int object_light_add_exec(bContext *C, wmOperator *op)
  {
        Scene *scene = CTX_data_scene(C);
        Object *ob;
        if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
                return OPERATOR_CANCELLED;
  
 -      ob = ED_object_add_type(C, OB_LAMP, get_lamp_defname(type), loc, rot, false, layer);
 -      BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
 +      ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false, layer);
 +
 +      float size = RNA_float_get(op->ptr, "radius");
 +      /* Better defaults for light size. */
 +      switch (type) {
 +              case LA_LOCAL:
 +              case LA_SPOT:
 +                      break;
 +              case LA_AREA:
 +                      size *= 4.0f;
 +                      break;
 +              default:
 +                      size *= 0.5f;
 +                      break;
 +      }
 +      BKE_object_obdata_size_init(ob, size);
  
        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;
        }
        return OPERATOR_FINISHED;
  }
  
 -void OBJECT_OT_lamp_add(wmOperatorType *ot)
 +void OBJECT_OT_light_add(wmOperatorType *ot)
  {
        /* identifiers */
 -      ot->name = "Add Lamp";
 -      ot->description = "Add a lamp object to the scene";
 -      ot->idname = "OBJECT_OT_lamp_add";
 +      ot->name = "Add Light";
 +      ot->description = "Add a light object to the scene";
 +      ot->idname = "OBJECT_OT_light_add";
  
        /* api callbacks */
        ot->invoke = WM_menu_invoke;
 -      ot->exec = object_lamp_add_exec;
 +      ot->exec = object_light_add_exec;
        ot->poll = ED_operator_objectmode;
  
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  
        /* properties */
 -      ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_lamp_type_items, 0, "Type", "");
 +      ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_light_type_items, 0, "Type", "");
        RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_LAMP);
  
        ED_object_add_unit_props(ot);
        ED_object_add_generic_props(ot, false);
  }
  
 -/********************* Add Group Instance Operator ********************/
 +/********************* Add Collection Instance Operator ********************/
  
 -static int group_instance_add_exec(bContext *C, wmOperator *op)
 +static int collection_instance_add_exec(bContext *C, wmOperator *op)
  {
        Main *bmain = CTX_data_main(C);
 -      Group *group;
 +      Collection *collection;
        unsigned int layer;
        float loc[3], rot[3];
  
                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;
                        const int mval[2] = {event->x - ar->winrct.xmin,
                                             event->y - ar->winrct.ymin};
                        ED_object_location_from_view(C, loc);
 -                      ED_view3d_cursor3d_position(C, mval, loc);
 +                      ED_view3d_cursor3d_position(C, mval, false, loc);
                        RNA_float_set_array(op->ptr, "location", loc);
                }
        }
        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);
  
 -              /* works without this except if you try render right after, see: 22027 */
 -              DAG_relations_tag_update(bmain);
 +              /* 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 */
 +              DEG_relations_tag_update(bmain);
 +              DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
                WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
  
                return OPERATOR_FINISHED;
  }
  
  /* 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);
@@@ -1320,22 -1097,35 +1320,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);
  
 +                      DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
                        WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
                        WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
                }
@@@ -1464,13 -1263,15 +1464,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)
@@@ -1543,8 -1344,6 +1543,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);
  
                ob_dst->parent = NULL;
                BKE_constraints_free(&ob_dst->constraints);
 -              ob_dst->curve_cache = NULL;
 +              ob_dst->runtime.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);
                        }
                }
        }
@@@ -1717,7 -1519,7 +1717,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);
  
@@@ -1751,43 -1553,46 +1751,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) {
 +      if (ob->runtime.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 bool 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 *ob1, *newob, *obact = CTX_data_active_object(C);
 -      Object *ob, *ob1, *obact = CTX_data_active_object(C);
++      Object *ob1, *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) {
+               Object *newob = NULL;
                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) {
                                if (ob->type == OB_MESH) {
                                        BKE_object_free_modifiers(ob, 0);  /* after derivedmesh calls! */
                                }
 +                              if (ob->type == OB_GPENCIL) {
 +                                      BKE_object_free_modifiers(ob, 0);  /* after derivedmesh calls! */
 +                                      BKE_object_free_shaderfx(ob, 0);
 +                              }
                        }
                }
                else if (ob->type == OB_MESH && target == OB_CURVE) {
                        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  */
                                        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);
 -                              BKE_mesh_from_metaball(&baseob->curve_cache->disp, newob->data);
 +                              convert_ensure_curve_cache(depsgraph, scene, baseob);
 +                              BKE_mesh_from_metaball(&baseob->runtime.curve_cache->disp, newob->data);
  
                                if (obact->type == OB_MBALL) {
                                        basact = basen;
                }
  
                /* Ensure new object has consistent material data with its new obdata. */
-               test_object_materials(bmain, newob, newob->data);
+               if (newob) {
+                       test_object_materials(bmain, newob, newob->data);
+               }
  
                /* tag obdata if it was been changed */
  
                }
  
                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);
        }
  
  // 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);
 +      DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
        WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
        WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
  
@@@ -2192,43 -2005,39 +2195,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_VISIBLE)) {
 +                      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);
                        }
                }
  
                                        ID_NEW_REMAP_US(obn->mat[a])
                                        else {
                                                obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a]));
 +                                              /* duplicate grease pencil settings */
 +                                              if (ob->mat[a]->gp_style) {
 +                                                      obn->mat[a]->gp_style = MEM_dupallocN(ob->mat[a]->gp_style);
 +                                              }
                                        }
                                        id_us_min(id);
  
                                }
                                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) {
                                        ID_NEW_REMAP_US2(obn->data)
                                        else {
                                                obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data));
 -                                              BKE_pose_rebuild(obn, obn->data);
 +                                              BKE_pose_rebuild(bmain, obn, obn->data, true);
                                                didit = 1;
                                        }
                                        id_us_min(id);
                                        id_us_min(id);
                                }
                                break;
 +                      case OB_GPENCIL:
 +                              if (dupflag != 0) {
 +                                      ID_NEW_REMAP_US2(obn->data)
 +                                      else {
 +                                              obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data));
 +                                              didit = 1;
 +                                      }
 +                                      id_us_min(id);
 +                              }
 +                              break;
                }
  
                /* check if obdata is copied */
                        }
  
                        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);
@@@ -2471,29 -2284,29 +2474,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);
 +      DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
  
        WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
  
@@@ -2539,9 -2351,9 +2542,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) {
                const int mval[2] = {event->x - ar->winrct.xmin,
                                     event->y - ar->winrct.ymin};
                ED_object_location_from_view(C, basen->object->loc);
 -              ED_view3d_cursor3d_position(C, mval, basen->object->loc);
 +              ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
        }
  
 -      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);
  
 +      DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
        WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
        WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
  
@@@ -2618,7 -2437,7 +2621,7 @@@ static bool join_poll(bContext *C
  
        if (!ob || ID_IS_LINKED(ob)) return 0;
  
 -      if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
 +      if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE, OB_GPENCIL))
                return ED_operator_screenactive(C);
        else
                return 0;
  
  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;
        }
                BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata");
                return OPERATOR_CANCELLED;
        }
 +      else if (ob->type == OB_GPENCIL) {
 +              bGPdata *gpd = (bGPdata *)ob->data;
 +              if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
 +                      BKE_report(op->reports, RPT_ERROR, "This data does not support joining in this mode");
 +                      return OPERATOR_CANCELLED;
 +              }
 +      }
  
        if (ob->type == OB_MESH)
                return join_mesh_exec(C, op);
                return join_curve_exec(C, op);
        else if (ob->type == OB_ARMATURE)
                return join_armature_exec(C, op);
 +      else if (ob->type == OB_GPENCIL)
 +              return ED_gpencil_join_objects_exec(C, op);
  
        return OPERATOR_CANCELLED;
  }
@@@ -2688,9 -2499,10 +2691,9 @@@ static bool join_shapes_poll(bContext *
  
  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;
        }