Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_view3d / view3d_view.c
index 92f226f72de3077f8e775600390f125e33061881..98ae57e9c426614aaee5460d8a162840e06b9ebf 100644 (file)
 #include "BKE_action.h"
 #include "BKE_camera.h"
 #include "BKE_context.h"
-#include "BKE_depsgraph.h"
 #include "BKE_object.h"
 #include "BKE_global.h"
+#include "BKE_layer.h"
 #include "BKE_main.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
 
-#include "BIF_gl.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
 
 #include "UI_resources.h"
 
+#include "GPU_glew.h"
 #include "GPU_select.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
 
+#include "ED_object.h"
 #include "ED_screen.h"
 
-#ifdef WITH_GAMEENGINE
-#  include "BLI_listbase.h"
-#  include "BLI_callbacks.h"
-
-#  include "GPU_draw.h"
-
-#  include "BL_System.h"
-#endif
+#include "DRW_engine.h"
 
 #include "view3d_intern.h"  /* own include */
 
@@ -125,7 +123,7 @@ static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms
 /* the arguments are the desired situation */
 void ED_view3d_smooth_view_ex(
         /* avoid passing in the context */
-        wmWindowManager *wm, wmWindow *win, ScrArea *sa,
+        const Depsgraph *depsgraph, wmWindowManager *wm, wmWindow *win, ScrArea *sa,
         View3D *v3d, ARegion *ar, const int smooth_viewtx,
         const V3D_SmoothParams *sview)
 {
@@ -156,7 +154,7 @@ void ED_view3d_smooth_view_ex(
         * we allow camera option locking to initialize the view settings from the camera.
         */
        if (sview->camera == NULL && sview->camera_old == NULL) {
-               ED_view3d_camera_lock_init(v3d, rv3d);
+               ED_view3d_camera_lock_init(depsgraph, v3d, rv3d);
        }
 
        /* store the options we want to end with */
@@ -181,13 +179,14 @@ void ED_view3d_smooth_view_ex(
        }
 
        if (sview->camera) {
-               sms.dst.dist = ED_view3d_offset_distance(sview->camera->obmat, sview->ofs, VIEW3D_DIST_FALLBACK);
-               ED_view3d_from_object(sview->camera, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens);
+               Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera);
+               sms.dst.dist = ED_view3d_offset_distance(ob_camera_eval->obmat, sview->ofs, VIEW3D_DIST_FALLBACK);
+               ED_view3d_from_object(ob_camera_eval, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens);
                sms.to_camera = true; /* restore view3d values in end */
        }
 
        /* skip smooth viewing for render engine draw */
-       if (smooth_viewtx && v3d->drawtype != OB_RENDER) {
+       if (smooth_viewtx && v3d->shading.type != OB_RENDER) {
                bool changed = false; /* zero means no difference */
 
                if (sview->camera_old != sview->camera)
@@ -206,9 +205,10 @@ void ED_view3d_smooth_view_ex(
                if (changed) {
                        /* original values */
                        if (sview->camera_old) {
-                               sms.src.dist = ED_view3d_offset_distance(sview->camera_old->obmat, rv3d->ofs, 0.0f);
+                               Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old);
+                               sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, rv3d->ofs, 0.0f);
                                /* this */
-                               ED_view3d_from_object(sview->camera_old, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
+                               ED_view3d_from_object(ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
                        }
                        /* grid draw as floor */
                        if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
@@ -230,9 +230,10 @@ void ED_view3d_smooth_view_ex(
                        /* ensure it shows correct */
                        if (sms.to_camera) {
                                /* use ortho if we move from an ortho view to an ortho camera */
+                               Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera);
                                rv3d->persp = (((rv3d->is_persp == false) &&
-                                               (sview->camera->type == OB_CAMERA) &&
-                                               (((Camera *)sview->camera->data)->type == CAM_ORTHO)) ?
+                                               (ob_camera_eval->type == OB_CAMERA) &&
+                                               (((Camera *)ob_camera_eval->data)->type == CAM_ORTHO)) ?
                                                RV3D_ORTHO : RV3D_PERSP);
                        }
 
@@ -265,7 +266,7 @@ void ED_view3d_smooth_view_ex(
                        rv3d->dist = sms.dst.dist;
                        v3d->lens = sms.dst.lens;
 
-                       ED_view3d_camera_lock_sync(v3d, rv3d);
+                       ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
                }
 
                if (rv3d->viewlock & RV3D_BOXVIEW) {
@@ -281,11 +282,13 @@ void ED_view3d_smooth_view(
         View3D *v3d, ARegion *ar, const int smooth_viewtx,
         const struct V3D_SmoothParams *sview)
 {
+       const Depsgraph *depsgraph = CTX_data_depsgraph(C);
        wmWindowManager *wm = CTX_wm_manager(C);
        wmWindow *win = CTX_wm_window(C);
        ScrArea *sa = CTX_wm_area(C);
 
        ED_view3d_smooth_view_ex(
+               depsgraph,
                wm, win, sa,
                v3d, ar, smooth_viewtx,
                sview);
@@ -294,6 +297,7 @@ void ED_view3d_smooth_view(
 /* only meant for timer usage */
 static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool sync_boxview)
 {
+       const Depsgraph *depsgraph = CTX_data_depsgraph(C);
        RegionView3D *rv3d = ar->regiondata;
        struct SmoothView3DStore *sms = rv3d->sms;
        float step, step_inv;
@@ -314,7 +318,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool
                else {
                        view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d);
 
-                       ED_view3d_camera_lock_sync(v3d, rv3d);
+                       ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
                        ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
                }
 
@@ -347,7 +351,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool
                rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv;
                v3d->lens  = sms->dst.lens * step + sms->src.lens * step_inv;
 
-               ED_view3d_camera_lock_sync(v3d, rv3d);
+               ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
                if (ED_screen_animation_playing(CTX_wm_manager(C))) {
                        ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
                }
@@ -405,8 +409,9 @@ void ED_view3d_smooth_view_force_finish(
 
                /* force update of view matrix so tools that run immediately after
                 * can use them without redrawing first */
+               Depsgraph *depsgraph = CTX_data_depsgraph(C);
                Scene *scene = CTX_data_scene(C);
-               ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL, NULL);
+               ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL);
        }
 }
 
@@ -433,6 +438,7 @@ void VIEW3D_OT_smoothview(wmOperatorType *ot)
 
 static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op))
 {
+       const Depsgraph *depsgraph = CTX_data_depsgraph(C);
        View3D *v3d;
        ARegion *ar;
        RegionView3D *rv3d;
@@ -446,11 +452,11 @@ static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op))
 
        BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
 
-       ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
+       ED_view3d_to_object(depsgraph, v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
 
        BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag);
 
-       DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
+       DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
        rv3d->persp = RV3D_CAMOB;
 
        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, v3d->camera);
@@ -503,29 +509,30 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot)
  * meant to take into account vertex/bone selection for eg. */
 static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op)
 {
-       Main *bmain = CTX_data_main(C);
+       Depsgraph *depsgraph = CTX_data_depsgraph(C);
        Scene *scene = CTX_data_scene(C);
        View3D *v3d = CTX_wm_view3d(C);  /* can be NULL */
        Object *camera_ob = v3d ? v3d->camera : scene->camera;
+       Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob);
 
        float r_co[3]; /* the new location to apply */
        float r_scale; /* only for ortho cameras */
 
-       if (camera_ob == NULL) {
+       if (camera_ob_eval == NULL) {
                BKE_report(op->reports, RPT_ERROR, "No active camera");
                return OPERATOR_CANCELLED;
        }
 
        /* this function does all the important stuff */
-       if (BKE_camera_view_frame_fit_to_scene(bmain, scene, v3d, camera_ob, r_co, &r_scale)) {
+       if (BKE_camera_view_frame_fit_to_scene(depsgraph, scene, camera_ob_eval, r_co, &r_scale)) {
                ObjectTfmProtectedChannels obtfm;
                float obmat_new[4][4];
 
-               if ((camera_ob->type == OB_CAMERA) && (((Camera *)camera_ob->data)->type == CAM_ORTHO)) {
+               if ((camera_ob_eval->type == OB_CAMERA) && (((Camera *)camera_ob_eval->data)->type == CAM_ORTHO)) {
                        ((Camera *)camera_ob->data)->ortho_scale = r_scale;
                }
 
-               copy_m4_m4(obmat_new, camera_ob->obmat);
+               copy_m4_m4(obmat_new, camera_ob_eval->obmat);
                copy_v3_v3(obmat_new[3], r_co);
 
                /* only touch location */
@@ -534,7 +541,7 @@ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op)
                BKE_object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D);
 
                /* notifiers */
-               DAG_id_tag_update(&camera_ob->id, OB_RECALC_OB);
+               DEG_id_tag_update(&camera_ob->id, OB_RECALC_OB);
                WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, camera_ob);
                return OPERATOR_FINISHED;
        }
@@ -689,14 +696,14 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
 /**
  * \param rect optional for picking (can be NULL).
  */
-void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect)
+void view3d_winmatrix_set(Depsgraph *depsgraph, ARegion *ar, const View3D *v3d, const rcti *rect)
 {
        RegionView3D *rv3d = ar->regiondata;
        rctf viewplane;
        float clipsta, clipend;
        bool is_ortho;
 
-       is_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
+       is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
        rv3d->is_persp = !is_ortho;
 
 #if 0
@@ -715,14 +722,14 @@ void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect)
        }
 
        if (is_ortho) {
-               wmOrtho(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+               GPU_matrix_ortho_set(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
        }
        else {
-               wmFrustum(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+               GPU_matrix_frustum_set(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
        }
 
        /* update matrix in 3d view region */
-       glGetFloatv(GL_PROJECTION_MATRIX, (float *)rv3d->winmat);
+       GPU_matrix_projection_get(rv3d->winmat);
 }
 
 static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
@@ -741,6 +748,7 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
 /**
  * Sets #RegionView3D.viewmat
  *
+ * \param depsgraph: Depsgraph.
  * \param scene: Scene for camera and cursor location.
  * \param v3d: View 3D space data.
  * \param rv3d: 3D region which stores the final matrices.
@@ -750,13 +758,14 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
  * \note don't set windows active in here, is used by renderwin too.
  */
 void view3d_viewmatrix_set(
-        Scene *scene,
+        Depsgraph *depsgraph, Scene *scene,
         const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2])
 {
        if (rv3d->persp == RV3D_CAMOB) {      /* obs/camera */
                if (v3d->camera) {
-                       BKE_object_where_is_calc(scene, v3d->camera);
-                       obmat_to_viewmat(rv3d, v3d->camera);
+                       Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
+                       BKE_object_where_is_calc(depsgraph, scene, ob_camera_eval);
+                       obmat_to_viewmat(rv3d, ob_camera_eval);
                }
                else {
                        quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
@@ -774,15 +783,15 @@ void view3d_viewmatrix_set(
                quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
                if (rv3d->persp == RV3D_PERSP) rv3d->viewmat[3][2] -= rv3d->dist;
                if (v3d->ob_centre) {
-                       Object *ob = v3d->ob_centre;
+                       Object *ob_eval = DEG_get_evaluated_object(depsgraph, v3d->ob_centre);
                        float vec[3];
 
-                       copy_v3_v3(vec, ob->obmat[3]);
-                       if (ob->type == OB_ARMATURE && v3d->ob_centre_bone[0]) {
-                               bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, v3d->ob_centre_bone);
+                       copy_v3_v3(vec, ob_eval->obmat[3]);
+                       if (ob_eval->type == OB_ARMATURE && v3d->ob_centre_bone[0]) {
+                               bPoseChannel *pchan = BKE_pose_channel_find_name(ob_eval->pose, v3d->ob_centre_bone);
                                if (pchan) {
                                        copy_v3_v3(vec, pchan->pose_mat[3]);
-                                       mul_m4_v3(ob->obmat, vec);
+                                       mul_m4_v3(ob_eval->obmat, vec);
                                }
                        }
                        translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
@@ -790,7 +799,7 @@ void view3d_viewmatrix_set(
                }
                else if (v3d->ob_centre_cursor) {
                        float vec[3];
-                       copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, (View3D *)v3d));
+                       copy_v3_v3(vec, scene->cursor.location);
                        translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
                        use_lock_ofs = true;
                }
@@ -849,6 +858,71 @@ void view3d_opengl_select_cache_end(void)
        GPU_select_cache_end();
 }
 
+struct DrawSelectLoopUserData {
+       uint  pass;
+       uint  hits;
+       uint *buffer;
+       uint  buffer_len;
+       const rcti *rect;
+       char gpu_select_mode;
+};
+
+static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
+{
+       bool continue_pass = false;
+       struct DrawSelectLoopUserData *data = user_data;
+       if (stage == DRW_SELECT_PASS_PRE) {
+               GPU_select_begin(data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits);
+               /* always run POST after PRE. */
+               continue_pass = true;
+       }
+       else if (stage == DRW_SELECT_PASS_POST) {
+               int hits = GPU_select_end();
+               if (data->pass == 0) {
+                       /* quirk of GPU_select_end, only take hits value from first call. */
+                       data->hits = hits;
+               }
+               if (data->gpu_select_mode == GPU_SELECT_NEAREST_FIRST_PASS) {
+                       data->gpu_select_mode = GPU_SELECT_NEAREST_SECOND_PASS;
+                       continue_pass = (hits > 0);
+               }
+               data->pass += 1;
+       }
+       else {
+               BLI_assert(0);
+       }
+       return continue_pass;
+
+}
+
+eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const Scene *scene, const Object *obact)
+{
+       if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+               if (obact && (obact->mode & OB_MODE_WEIGHT_PAINT) &&
+                   BKE_object_pose_armature_get((Object *)obact))
+               {
+                       return VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK;
+               }
+               return VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK;
+       }
+       return VIEW3D_SELECT_FILTER_NOP;
+}
+
+/** Implement #VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK. */
+static bool drw_select_filter_object_mode_lock(Object *ob, void *user_data)
+{
+       const Object *obact = user_data;
+       return BKE_object_is_mode_compat(ob, obact->mode);
+}
+
+/** Implement #VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK for special case when
+ * we want to select pose bones (this doesn't switch modes). */
+static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void *user_data)
+{
+       const Object *ob_pose = user_data;
+       return (DEG_get_original_object(ob) == ob_pose);
+}
+
 /**
  * \warning be sure to account for a negative return value
  * This is an error, "Too many objects in select buffer"
@@ -858,25 +932,27 @@ void view3d_opengl_select_cache_end(void)
  */
 int view3d_opengl_select(
         ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input,
-        eV3DSelectMode select_mode)
+        eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter)
 {
        struct bThemeState theme_state;
+       Depsgraph *depsgraph = vc->depsgraph;
        Scene *scene = vc->scene;
        View3D *v3d = vc->v3d;
        ARegion *ar = vc->ar;
        rcti rect;
-       int hits;
-       const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL);
+       int hits = 0;
+       const bool use_obedit_skip = (OBEDIT_FROM_VIEW_LAYER(vc->view_layer) != NULL) && (vc->obedit == NULL);
        const bool is_pick_select = (U.gpu_select_pick_deph != 0);
        const bool do_passes = (
                (is_pick_select == false) &&
                (select_mode == VIEW3D_SELECT_PICK_NEAREST) &&
                GPU_select_query_check_active());
        const bool use_nearest = (is_pick_select && select_mode == VIEW3D_SELECT_PICK_NEAREST);
+       bool draw_surface = true;
 
        char gpu_select_mode;
 
-       /* case not a border select */
+       /* case not a box select */
        if (input->xmin == input->xmax) {
                /* seems to be default value for bones only now */
                BLI_rcti_init_pt_radius(&rect, (const int[2]){input->xmin, input->ymin}, 12);
@@ -905,6 +981,35 @@ int view3d_opengl_select(
                }
        }
 
+       struct {
+               DRW_ObjectFilterFn fn;
+               void *user_data;
+       } object_filter = {NULL, NULL};
+       switch (select_filter) {
+               case VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK:
+               {
+                       Object *obact = OBACT(vc->view_layer);
+                       if (obact && obact->mode != OB_MODE_OBJECT) {
+                               object_filter.fn = drw_select_filter_object_mode_lock;
+                               object_filter.user_data = obact;
+                       }
+                       break;
+               }
+               case VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK:
+               {
+                       Object *obact = OBACT(vc->view_layer);
+                       BLI_assert(obact && (obact->mode & OB_MODE_WEIGHT_PAINT));
+                       Object *ob_pose = BKE_object_pose_armature_get(obact);
+
+                       object_filter.fn = drw_select_filter_object_mode_lock_for_weight_paint;
+                       object_filter.user_data = ob_pose;
+                       break;
+               }
+               case VIEW3D_SELECT_FILTER_NOP:
+                       break;
+
+       }
+
        /* Tools may request depth outside of regular drawing code. */
        UI_Theme_Store(&theme_state);
        UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
@@ -918,47 +1023,81 @@ int view3d_opengl_select(
                goto finally;
        }
 
+       /* All of the queries need to be perform on the drawing context. */
+       DRW_opengl_context_enable();
+
        G.f |= G_PICKSEL;
 
        /* Important we use the 'viewmat' and don't re-calculate since
         * the object & bone view locking takes 'rect' into account, see: T51629. */
-       ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, vc->rv3d->viewmat, NULL, &rect);
+       ED_view3d_draw_setup_view(vc->win, depsgraph, scene, ar, v3d, vc->rv3d->viewmat, NULL, &rect);
 
-       if (v3d->drawtype > OB_WIRE) {
-               v3d->zbuf = true;
-               glEnable(GL_DEPTH_TEST);
+       if (v3d->shading.type > OB_WIRE) {
+               GPU_depth_test(true);
        }
 
-       if (vc->rv3d->rflag & RV3D_CLIPPING)
+       if (vc->rv3d->rflag & RV3D_CLIPPING) {
                ED_view3d_clipping_set(vc->rv3d);
+       }
 
-       GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
-
-       ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest);
-
-       hits = GPU_select_end();
-
-       /* second pass, to get the closest object to camera */
-       if (do_passes && (hits > 0)) {
-               GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
-
-               ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest);
+       /* If in xray mode, we select the wires in priority. */
+       if ((v3d->shading.flag & V3D_XRAY_FLAG(v3d)) && use_nearest) {
+               /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop
+                * because the OpenGL context created & destroyed inside this function. */
+               struct DrawSelectLoopUserData drw_select_loop_user_data = {
+                       .pass = 0,
+                       .hits = 0,
+                       .buffer = buffer,
+                       .buffer_len = bufsize,
+                       .rect = &rect,
+                       .gpu_select_mode = gpu_select_mode,
+               };
+               draw_surface = false;
+               DRW_draw_select_loop(
+                       depsgraph, ar, v3d,
+                       use_obedit_skip, draw_surface, use_nearest, &rect,
+                       drw_select_loop_pass, &drw_select_loop_user_data,
+                       object_filter.fn, object_filter.user_data);
+               hits = drw_select_loop_user_data.hits;
+               /* FIX: This cleanup the state before doing another selection pass.
+                * (see T56695) */
+               GPU_select_cache_end();
+       }
 
-               GPU_select_end();
+       if (hits == 0) {
+               /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop
+                * because the OpenGL context created & destroyed inside this function. */
+               struct DrawSelectLoopUserData drw_select_loop_user_data = {
+                       .pass = 0,
+                       .hits = 0,
+                       .buffer = buffer,
+                       .buffer_len = bufsize,
+                       .rect = &rect,
+                       .gpu_select_mode = gpu_select_mode,
+               };
+               draw_surface = true;
+               DRW_draw_select_loop(
+                       depsgraph, ar, v3d,
+                       use_obedit_skip, draw_surface, use_nearest, &rect,
+                       drw_select_loop_pass, &drw_select_loop_user_data,
+                       object_filter.fn, object_filter.user_data);
+               hits = drw_select_loop_user_data.hits;
        }
 
        G.f &= ~G_PICKSEL;
-       ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL);
+       ED_view3d_draw_setup_view(vc->win, depsgraph, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL);
 
-       if (v3d->drawtype > OB_WIRE) {
-               v3d->zbuf = 0;
-               glDisable(GL_DEPTH_TEST);
+       if (v3d->shading.type > OB_WIRE) {
+               GPU_depth_test(false);
        }
 
        if (vc->rv3d->rflag & RV3D_CLIPPING)
                ED_view3d_clipping_disable();
 
+       DRW_opengl_context_disable();
+
 finally:
+
        if (hits < 0) printf("Too many objects in select buffer\n");  /* XXX make error message */
 
        UI_Theme_Restore(&theme_state);
@@ -974,11 +1113,10 @@ finally:
 
 static unsigned int free_localbit(Main *bmain)
 {
-       unsigned int lay;
        ScrArea *sa;
        bScreen *sc;
 
-       lay = 0;
+       unsigned short local_view_bits = 0;
 
        /* sometimes we loose a localview: when an area is closed */
        /* check all areas: which localviews are in use? */
@@ -988,72 +1126,38 @@ static unsigned int free_localbit(Main *bmain)
                        for (; sl; sl = sl->next) {
                                if (sl->spacetype == SPACE_VIEW3D) {
                                        View3D *v3d = (View3D *) sl;
-                                       lay |= v3d->lay;
+                                       if (v3d->localvd) {
+                                               local_view_bits |= v3d->local_view_uuid;
+                                       }
                                }
                        }
                }
        }
 
-       if ((lay & 0x01000000) == 0) return 0x01000000;
-       if ((lay & 0x02000000) == 0) return 0x02000000;
-       if ((lay & 0x04000000) == 0) return 0x04000000;
-       if ((lay & 0x08000000) == 0) return 0x08000000;
-       if ((lay & 0x10000000) == 0) return 0x10000000;
-       if ((lay & 0x20000000) == 0) return 0x20000000;
-       if ((lay & 0x40000000) == 0) return 0x40000000;
-       if ((lay & 0x80000000) == 0) return 0x80000000;
-
-       return 0;
-}
-
-int ED_view3d_scene_layer_set(int lay, const bool *values, int *active)
-{
-       int i, tot = 0;
-
-       /* ensure we always have some layer selected */
-       for (i = 0; i < 20; i++)
-               if (values[i])
-                       tot++;
-
-       if (tot == 0)
-               return lay;
-
-       for (i = 0; i < 20; i++) {
-
-               if (active) {
-                       /* if this value has just been switched on, make that layer active */
-                       if (values[i] && (lay & (1 << i)) == 0) {
-                               *active = (1 << i);
-                       }
-               }
-
-               if (values[i]) lay |= (1 << i);
-               else lay &= ~(1 << i);
-       }
-
-       /* ensure always an active layer */
-       if (active && (lay & *active) == 0) {
-               for (i = 0; i < 20; i++) {
-                       if (lay & (1 << i)) {
-                               *active = 1 << i;
-                               break;
-                       }
+       for (int i = 0; i < 16; i++) {
+               if ((local_view_bits & (1 << i)) == 0) {
+                       return (1 << i);
                }
        }
 
-       return lay;
+       return 0;
 }
 
 static bool view3d_localview_init(
-        wmWindowManager *wm, wmWindow *win,
-        Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx,
+        const Depsgraph *depsgraph,
+        wmWindowManager *wm,
+        wmWindow *win,
+        Main *bmain,
+        ViewLayer *view_layer,
+        ScrArea *sa,
+        const int smooth_viewtx,
         ReportList *reports)
 {
        View3D *v3d = sa->spacedata.first;
        Base *base;
        float min[3], max[3], box[3], mid[3];
        float size = 0.0f;
-       unsigned int locallay;
+       unsigned int local_view_bit;
        bool ok = false;
 
        if (v3d->localvd) {
@@ -1062,27 +1166,31 @@ static bool view3d_localview_init(
 
        INIT_MINMAX(min, max);
 
-       locallay = free_localbit(bmain);
+       local_view_bit = free_localbit(bmain);
 
-       if (locallay == 0) {
-               BKE_report(reports, RPT_ERROR, "No more than 8 local views");
+       if (local_view_bit == 0) {
+               /* TODO(dfelinto): We can kick one of the other 3D views out of local view
+                  specially if it is not being used.  */
+               BKE_report(reports, RPT_ERROR, "No more than 16 local views");
                ok = false;
        }
        else {
-               if (scene->obedit) {
-                       BKE_object_minmax(scene->obedit, min, max, false);
-
-                       ok = true;
-
-                       BASACT->lay |= locallay;
-                       scene->obedit->lay = BASACT->lay;
+               Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+               if (obedit) {
+                       FOREACH_BASE_IN_EDIT_MODE_BEGIN(view_layer, v3d, base_iter) {
+                               BKE_object_minmax(base_iter->object, min, max, false);
+                               base_iter->local_view_bits |= local_view_bit;
+                               ok = true;
+                       } FOREACH_BASE_IN_EDIT_MODE_END;
                }
                else {
-                       for (base = FIRSTBASE; base; base = base->next) {
+                       for (base = FIRSTBASE(view_layer); base; base = base->next) {
                                if (TESTBASE(v3d, base)) {
                                        BKE_object_minmax(base->object, min, max, false);
-                                       base->lay |= locallay;
-                                       base->object->lay = base->lay;
+                                       base->local_view_bits |= local_view_bit;
+                                       /* Technically we should leave for Depsgraph to handle this.
+                                          But it is harmless to do it here, and it seems to be necessary. */
+                                       base->object->base_local_view_bits = base->local_view_bits;
                                        ok = true;
                                }
                        }
@@ -1101,14 +1209,12 @@ static bool view3d_localview_init(
 
                mid_v3_v3v3(mid, min, max);
 
-               copy_v3_v3(v3d->cursor, mid);
-
                for (ar = sa->regionbase.first; ar; ar = ar->next) {
                        if (ar->regiontype == RGN_TYPE_WINDOW) {
                                RegionView3D *rv3d = ar->regiondata;
                                bool ok_dist = true;
 
-                               /* new view values */
+                               /* New view values. */
                                Object *camera_old = NULL;
                                float dist_new, ofs_new[3];
 
@@ -1129,14 +1235,16 @@ static bool view3d_localview_init(
                                }
 
                                if (ok_dist) {
-                                       dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
+                                       dist_new = ED_view3d_radius_to_dist(v3d, ar, depsgraph, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
+
                                        if (rv3d->persp == RV3D_PERSP) {
-                                               /* don't zoom closer than the near clipping plane */
+                                               /* Don't zoom closer than the near clipping plane. */
                                                dist_new = max_ff(dist_new, v3d->near * 1.5f);
                                        }
                                }
 
                                ED_view3d_smooth_view_ex(
+                                       depsgraph,
                                        wm, win, sa, v3d, ar, smooth_viewtx,
                                            &(const V3D_SmoothParams) {
                                                .camera_old = camera_old,
@@ -1145,26 +1253,20 @@ static bool view3d_localview_init(
                        }
                }
 
-               v3d->lay = locallay;
-       }
-       else {
-               /* clear flags */
-               for (base = FIRSTBASE; base; base = base->next) {
-                       if (base->lay & locallay) {
-                               base->lay -= locallay;
-                               if (base->lay == 0) base->lay = v3d->layact;
-                               if (base->object != scene->obedit) base->flag |= SELECT;
-                               base->object->lay = base->lay;
-                       }
-               }
+               v3d->local_view_uuid = local_view_bit;
        }
 
-       DAG_on_visible_update(bmain, false);
-
+       DEG_on_visible_update(bmain, false);
        return ok;
 }
 
-static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, ScrArea *sa, const int smooth_viewtx)
+static void restore_localviewdata(
+        const Depsgraph *depsgraph,
+        wmWindowManager *wm,
+        wmWindow *win,
+        Main *bmain,
+        ScrArea *sa,
+        const int smooth_viewtx)
 {
        const bool free = true;
        ARegion *ar;
@@ -1176,9 +1278,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai
        camera_old = v3d->camera;
        camera_new = v3d->localvd->camera;
 
-       v3d->lay = v3d->localvd->lay;
-       v3d->layact = v3d->localvd->layact;
-       v3d->drawtype = v3d->localvd->drawtype;
+       v3d->local_view_uuid = 0;
        v3d->camera = v3d->localvd->camera;
 
        if (free) {
@@ -1201,6 +1301,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai
                                rv3d->camzoom = rv3d->localvd->camzoom;
 
                                ED_view3d_smooth_view_ex(
+                                       depsgraph,
                                        wm, win, sa,
                                        v3d, ar, smooth_viewtx,
                                        &(const V3D_SmoothParams) {
@@ -1220,35 +1321,35 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai
 }
 
 static bool view3d_localview_exit(
-        wmWindowManager *wm, wmWindow *win,
-        Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx)
+        const Depsgraph *depsgraph,
+        wmWindowManager *wm,
+        wmWindow *win,
+        Main *bmain,
+        ViewLayer *view_layer,
+        ScrArea *sa,
+        const int smooth_viewtx)
 {
        View3D *v3d = sa->spacedata.first;
        struct Base *base;
-       unsigned int locallay;
+       unsigned int local_view_bit;
 
        if (v3d->localvd) {
 
-               locallay = v3d->lay & 0xFF000000;
-
-               restore_localviewdata(wm, win, bmain, sa, smooth_viewtx);
+               local_view_bit = v3d->local_view_uuid;
 
-               /* for when in other window the layers have changed */
-               if (v3d->scenelock) v3d->lay = scene->lay;
+               restore_localviewdata(depsgraph, wm, win, bmain, sa, smooth_viewtx);
 
-               for (base = FIRSTBASE; base; base = base->next) {
-                       if (base->lay & locallay) {
-                               base->lay -= locallay;
-                               if (base->lay == 0) base->lay = v3d->layact;
-                               if (base->object != scene->obedit) {
-                                       base->flag |= SELECT;
-                                       base->object->flag |= SELECT;
+               Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+               for (base = FIRSTBASE(view_layer); base; base = base->next) {
+                       if (base->local_view_bits & local_view_bit) {
+                               base->local_view_bits &= ~local_view_bit;
+                               if (base->object != obedit) {
+                                       ED_object_base_select(base, BA_SELECT);
                                }
-                               base->object->lay = base->lay;
                        }
                }
 
-               DAG_on_visible_update(bmain, false);
+               DEG_on_visible_update(bmain, false);
 
                return true;
        }
@@ -1259,30 +1360,36 @@ static bool view3d_localview_exit(
 
 static int localview_exec(bContext *C, wmOperator *op)
 {
+       const Depsgraph *depsgraph = CTX_data_depsgraph(C);
        const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
        wmWindowManager *wm = CTX_wm_manager(C);
        wmWindow *win = CTX_wm_window(C);
        Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
+       ViewLayer *view_layer = CTX_data_view_layer(C);
        ScrArea *sa = CTX_wm_area(C);
        View3D *v3d = CTX_wm_view3d(C);
        bool changed;
 
        if (v3d->localvd) {
-               changed = view3d_localview_exit(wm, win, bmain, scene, sa, smooth_viewtx);
+               changed = view3d_localview_exit(depsgraph, wm, win, bmain, view_layer, sa, smooth_viewtx);
        }
        else {
-               changed = view3d_localview_init(wm, win, bmain, scene, sa, smooth_viewtx, op->reports);
+               changed = view3d_localview_init(depsgraph, wm, win, bmain, view_layer, sa, smooth_viewtx, op->reports);
        }
 
        if (changed) {
-               DAG_id_type_tag(bmain, ID_OB);
+               DEG_id_type_tag(bmain, ID_OB);
                ED_area_tag_redraw(sa);
 
-               /* unselected objects become selected when exiting */
+               /* Unselected objects become selected when exiting. */
                if (v3d->localvd == NULL) {
+                       DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
                        WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
                }
+               else {
+                       DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
+               }
 
                return OPERATOR_FINISHED;
        }
@@ -1305,217 +1412,105 @@ void VIEW3D_OT_localview(wmOperatorType *ot)
        ot->poll = ED_operator_view3d_active;
 }
 
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Game Engine Operator
- *
- * Start the game engine (handles context switching).
- * \{ */
-
-#ifdef WITH_GAMEENGINE
-
-static ListBase queue_back;
-static void game_engine_save_state(bContext *C, wmWindow *win)
+static int localview_remove_from_exec(bContext *C, wmOperator *op)
 {
+       View3D *v3d = CTX_wm_view3d(C);
        Main *bmain = CTX_data_main(C);
-       Object *obact = CTX_data_active_object(C);
-
-       glPushAttrib(GL_ALL_ATTRIB_BITS);
+       Scene *scene = CTX_data_scene(C);
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       bool changed = false;
 
-       if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
-               GPU_paint_set_mipmap(bmain, 1);
+       for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
+               if (TESTBASE(v3d, base)) {
+                       base->local_view_bits &= ~v3d->local_view_uuid;
+                       ED_object_base_select(base, BA_DESELECT);
 
-       queue_back = win->queue;
+                       if (base == BASACT(view_layer)) {
+                               view_layer->basact = NULL;
+                       }
+                       changed = true;
+               }
+       }
 
-       BLI_listbase_clear(&win->queue);
+       if (changed) {
+               DEG_on_visible_update(bmain, false);
+               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);
+               return OPERATOR_FINISHED;
+       }
+       else {
+               BKE_report(op->reports, RPT_ERROR, "No object selected");
+               return OPERATOR_CANCELLED;
+       }
 }
 
-static void game_engine_restore_state(bContext *C, wmWindow *win)
+static bool localview_remove_from_poll(bContext *C)
 {
-       Main *bmain = CTX_data_main(C);
-       Object *obact = CTX_data_active_object(C);
-
-       if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
-               GPU_paint_set_mipmap(bmain, 0);
-
-       /* check because closing win can set to NULL */
-       if (win) {
-               win->queue = queue_back;
+       if (CTX_data_edit_object(C) != NULL) {
+               return false;
        }
 
-       GPU_state_init();
-       GPU_set_tpage(NULL, 0, 0);
-
-       glPopAttrib();
+       View3D *v3d = CTX_wm_view3d(C);
+       return v3d && v3d->localvd;
 }
 
-/* was space_set_commmandline_options in 2.4x */
-static void game_set_commmandline_options(GameData *gm)
+void VIEW3D_OT_localview_remove_from(wmOperatorType *ot)
 {
-       SYS_SystemHandle syshandle;
-       int test;
-
-       if ((syshandle = SYS_GetSystem())) {
-               /* User defined settings */
-               test = (U.gameflags & USER_DISABLE_MIPMAP);
-               GPU_set_mipmap(G_MAIN, !test);
-               SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
-
-               /* File specific settings: */
-               /* Only test the first one. These two are switched
-                * simultaneously. */
-               test = (gm->flag & GAME_SHOW_FRAMERATE);
-               SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
-               SYS_WriteCommandLineInt(syshandle, "show_profile", test);
-
-               test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
-               SYS_WriteCommandLineInt(syshandle, "show_properties", test);
-
-               test = (gm->flag & GAME_SHOW_PHYSICS);
-               SYS_WriteCommandLineInt(syshandle, "show_physics", test);
-
-               test = (gm->flag & GAME_ENABLE_ALL_FRAMES);
-               SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
-
-               test = (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
-               SYS_WriteCommandLineInt(syshandle, "animation_record", test);
-
-               test = (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
-               SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
-
-               test = (gm->matmode == GAME_MAT_MULTITEX);
-               SYS_WriteCommandLineInt(syshandle, "blender_material", test);
-               test = (gm->matmode == GAME_MAT_GLSL);
-               SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
-               test = (gm->flag & GAME_DISPLAY_LISTS);
-               SYS_WriteCommandLineInt(syshandle, "displaylists", test);
-
+       /* identifiers */
+       ot->name = "Remove from Local View";
+       ot->description = "Move selected objects out of local view";
+       ot->idname = "VIEW3D_OT_localview_remove_from";
 
-       }
+       /* api callbacks */
+       ot->exec = localview_remove_from_exec;
+       ot->invoke = WM_operator_confirm;
+       ot->poll = localview_remove_from_poll;
+       ot->flag = OPTYPE_UNDO;
 }
 
-#endif /* WITH_GAMEENGINE */
-
-static bool game_engine_poll(bContext *C)
-{
-       bScreen *screen;
-       /* we need a context and area to launch BGE
-        * it's a temporary solution to avoid crash at load time
-        * if we try to auto run the BGE. Ideally we want the
-        * context to be set as soon as we load the file. */
-
-       if (CTX_wm_window(C) == NULL) return 0;
-       if ((screen = CTX_wm_screen(C)) == NULL) return 0;
-
-       if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)
-               return 0;
-
-       if (!BKE_scene_uses_blender_game(screen->scene))
-               return 0;
+/** \} */
 
-       return 1;
-}
+/* -------------------------------------------------------------------- */
+/** \name View Layer Utilities
+ * \{ */
 
-static int game_engine_exec(bContext *C, wmOperator *op)
+int ED_view3d_view_layer_set(int lay, const bool *values, int *active)
 {
-#ifdef WITH_GAMEENGINE
-       Scene *startscene = CTX_data_scene(C);
-       Main *bmain = CTX_data_main(C);
-       ScrArea /* *sa, */ /* UNUSED */ *prevsa = CTX_wm_area(C);
-       ARegion *ar, *prevar = CTX_wm_region(C);
-       wmWindow *prevwin = CTX_wm_window(C);
-       RegionView3D *rv3d;
-       rcti cam_frame;
-
-       UNUSED_VARS(op);
-
-       /* bad context switch .. */
-       if (!ED_view3d_context_activate(C))
-               return OPERATOR_CANCELLED;
-
-       /* redraw to hide any menus/popups, we don't go back to
-        * the window manager until after this operator exits */
-       WM_redraw_windows(C);
-
-       BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_PRE);
-
-       rv3d = CTX_wm_region_view3d(C);
-       /* sa = CTX_wm_area(C); */ /* UNUSED */
-       ar = CTX_wm_region(C);
-
-       view3d_operator_needs_opengl(C);
-
-       game_set_commmandline_options(&startscene->gm);
+       int i, tot = 0;
 
-       if ((rv3d->persp == RV3D_CAMOB) &&
-           (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) &&
-           (startscene->gm.stereoflag != STEREO_DOME))
-       {
-               /* Letterbox */
-               rctf cam_framef;
-               ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false);
-               cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
-               cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
-               cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
-               cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
-               BLI_rcti_isect(&ar->winrct, &cam_frame, &cam_frame);
-       }
-       else {
-               cam_frame.xmin = ar->winrct.xmin;
-               cam_frame.xmax = ar->winrct.xmax;
-               cam_frame.ymin = ar->winrct.ymin;
-               cam_frame.ymax = ar->winrct.ymax;
-       }
+       /* ensure we always have some layer selected */
+       for (i = 0; i < 20; i++)
+               if (values[i])
+                       tot++;
 
+       if (tot == 0)
+               return lay;
 
-       game_engine_save_state(C, prevwin);
+       for (i = 0; i < 20; i++) {
 
-       StartKetsjiShell(C, ar, &cam_frame, 1);
+               if (active) {
+                       /* if this value has just been switched on, make that layer active */
+                       if (values[i] && (lay & (1 << i)) == 0) {
+                               *active = (1 << i);
+                       }
+               }
 
-       /* window wasnt closed while the BGE was running */
-       if (BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) {
-               prevwin = NULL;
-               CTX_wm_window_set(C, NULL);
+               if (values[i]) lay |= (1 << i);
+               else lay &= ~(1 << i);
        }
 
-       ED_area_tag_redraw(CTX_wm_area(C));
-
-       if (prevwin) {
-               /* restore context, in case it changed in the meantime, for
-                * example by working in another window or closing it */
-               CTX_wm_region_set(C, prevar);
-               CTX_wm_window_set(C, prevwin);
-               CTX_wm_area_set(C, prevsa);
+       /* ensure always an active layer */
+       if (active && (lay & *active) == 0) {
+               for (i = 0; i < 20; i++) {
+                       if (lay & (1 << i)) {
+                               *active = 1 << i;
+                               break;
+                       }
+               }
        }
 
-       game_engine_restore_state(C, prevwin);
-
-       //XXX restore_all_scene_cfra(scene_cfra_store);
-       BKE_scene_set_background(CTX_data_main(C), startscene);
-       //XXX BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
-
-       BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_POST);
-
-       return OPERATOR_FINISHED;
-#else
-       UNUSED_VARS(C);
-       BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build");
-       return OPERATOR_CANCELLED;
-#endif
-}
-
-void VIEW3D_OT_game_start(wmOperatorType *ot)
-{
-       /* identifiers */
-       ot->name = "Start Game Engine";
-       ot->description = "Start game engine";
-       ot->idname = "VIEW3D_OT_game_start";
-
-       /* api callbacks */
-       ot->exec = game_engine_exec;
-
-       ot->poll = game_engine_poll;
+       return lay;
 }
 
 /** \} */