diff options
author | Dalai Felinto <dfelinto@gmail.com> | 2018-11-25 14:50:34 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2018-11-25 14:50:34 +0300 |
commit | 4c3ed98ca27667c3403361199096e31eaa93cce2 (patch) | |
tree | 653c568d9d0547f7ac4beb847a590912d97102c0 /source/blender/editors/space_view3d | |
parent | e60c49ecf06815039137c98f86a7198d6ee81e14 (diff) |
Local View
Bring back per-viewport localview. This is based on Blender 2.79.
We have a limit of 16 different local view viewports.
We are using both the numpad /, as well as the regular /.
Missing features:
* Hack to make sure lights are always visible.
* Make rendered mode with external engines to support this as well
(probably just need to support this in the RNA iterators).
* Support over 16 viewports by taking existing viewports out of local view.
The code can use a cleanup pass in the future to unify the test to see
if an object is visible (or we can use TESTBASE in more places).
Diffstat (limited to 'source/blender/editors/space_view3d')
8 files changed, 330 insertions, 22 deletions
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index abb6fed965e..c3a02ecb1a2 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -2853,13 +2853,13 @@ static int viewselected_exec(bContext *C, wmOperator *op) } else if (obedit) { /* only selected */ - FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, obedit->mode, ob_eval_iter) { + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, obedit->mode, ob_eval_iter) { ok |= ED_view3d_minmax_verts(ob_eval_iter, min, max); } FOREACH_OBJECT_IN_MODE_END; } else if (ob_eval && (ob_eval->mode & OB_MODE_POSE)) { - FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, ob_eval->mode, ob_eval_iter) { + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, ob_eval->mode, ob_eval_iter) { ok |= BKE_pose_minmax(ob_eval_iter, min, max, true, true); } FOREACH_OBJECT_IN_MODE_END; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c index 6cd94830fe9..be07928d5fc 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c @@ -107,12 +107,13 @@ static int gizmo_preselect_elem_test_select( { ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); if (((gz_ele->bases)) == NULL || (gz_ele->bases[0] != view_layer->basact)) { MEM_SAFE_FREE(gz_ele->bases); gz_ele->bases = BKE_view_layer_array_from_bases_in_edit_mode( - view_layer, &gz_ele->bases_len); + view_layer, v3d, &gz_ele->bases_len); } } @@ -298,12 +299,13 @@ static int gizmo_preselect_edgering_test_select( { ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); if (((gz_ring->bases)) == NULL || (gz_ring->bases[0] != view_layer->basact)) { MEM_SAFE_FREE(gz_ring->bases); gz_ring->bases = BKE_view_layer_array_from_bases_in_edit_mode( - view_layer, &gz_ring->bases_len); + view_layer, v3d, &gz_ring->bases_len); } } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 05f2d8f67e1..9f77f671a7d 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -171,10 +171,12 @@ void VIEW3D_OT_select_box(struct wmOperatorType *ot); void VIEW3D_OT_select_lasso(struct wmOperatorType *ot); void VIEW3D_OT_select_menu(struct wmOperatorType *ot); +/* view3d_view.c */ void VIEW3D_OT_smoothview(struct wmOperatorType *ot); void VIEW3D_OT_camera_to_view(struct wmOperatorType *ot); void VIEW3D_OT_camera_to_view_selected(struct wmOperatorType *ot); void VIEW3D_OT_object_as_camera(struct wmOperatorType *ot); +void VIEW3D_OT_localview(struct wmOperatorType *ot); bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]); bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const struct BoundBox *bb); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 2dbe0a0b843..8092dc9f0f7 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -204,6 +204,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_camera_to_view); WM_operatortype_append(VIEW3D_OT_camera_to_view_selected); WM_operatortype_append(VIEW3D_OT_object_as_camera); + WM_operatortype_append(VIEW3D_OT_localview); WM_operatortype_append(VIEW3D_OT_fly); WM_operatortype_append(VIEW3D_OT_walk); WM_operatortype_append(VIEW3D_OT_navigate); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index f973f84cf6f..aafe931ff07 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -456,7 +456,7 @@ static Base **do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len) { Base **bases = NULL; BLI_array_declare(bases); - FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, OB_MODE_POSE, base_iter) { + FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, vc->v3d, OB_MODE_POSE, base_iter) { Object *ob_iter = base_iter->object; bArmature *arm = ob_iter->data; for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -1001,7 +1001,7 @@ static void view3d_lasso_select( } else { /* Edit Mode */ - FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, ob->mode, ob_iter) { + FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->mode, ob_iter) { ED_view3d_viewcontext_init_object(vc, ob_iter); switch (vc->obedit->type) { @@ -1729,7 +1729,7 @@ static bool ed_object_select_pick( } } else if (ED_armature_pose_select_pick_with_buffer( - view_layer, basact, buffer, hits, extend, deselect, toggle, do_nearest)) + view_layer, v3d, basact, buffer, hits, extend, deselect, toggle, do_nearest)) { /* then bone is found */ @@ -2252,7 +2252,7 @@ static int do_armature_box_select( VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP); uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc->view_layer, &objects_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc->view_layer, vc->v3d, &objects_len); /* clear flag we use to detect point was affected */ for (uint ob_index = 0; ob_index < objects_len; ob_index++) { @@ -2531,7 +2531,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) if (vc.obedit) { - FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.obedit->mode, ob_iter) { + FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, vc.obedit->mode, ob_iter) { ED_view3d_viewcontext_init_object(&vc, ob_iter); switch (vc.obedit->type) { @@ -3264,7 +3264,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) { view3d_operator_needs_opengl(C); - FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, obact->mode, ob_iter) { + FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->mode, ob_iter) { ED_view3d_viewcontext_init_object(&vc, ob_iter); obact = vc.obact; diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 9089a34ecaf..760208ffe28 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -90,7 +90,7 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) if (obedit) { ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { obedit = objects[ob_index]; @@ -132,7 +132,7 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) else { struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); - FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(view_layer_eval, ob_eval) + FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(view_layer_eval, v3d, ob_eval) { Object *ob = DEG_get_original_object(ob_eval); if (ob->mode & OB_MODE_POSE) { @@ -268,7 +268,7 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global float snap_target_local[3]; ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { obedit = objects[ob_index]; @@ -624,7 +624,7 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) int global_transverts_tot = 0; ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { obedit = objects[ob_index]; @@ -687,7 +687,7 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) } } else { - FOREACH_SELECTED_OBJECT_BEGIN(view_layer_eval, ob_eval) + FOREACH_SELECTED_OBJECT_BEGIN(view_layer_eval, v3d, ob_eval) { copy_v3_v3(vec, ob_eval->obmat[3]); diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 022fccd7ce7..8b0124a7a2b 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -91,14 +91,9 @@ void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float } } -View3DCursor *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d) +View3DCursor *ED_view3d_cursor3d_get(Scene *scene, View3D *UNUSED(v3d)) { - if (v3d && v3d->localvd) { - return &v3d->cursor; - } - else { - return &scene->cursor; - } + return &scene->cursor; } void ED_view3d_cursor3d_calc_mat3(const Scene *scene, const View3D *v3d, float mat[3][3]) diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index f8f2e9635e4..a7098ae255d 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -43,6 +43,7 @@ #include "BKE_context.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" @@ -60,6 +61,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_object.h" #include "ED_screen.h" #include "DRW_engine.h" @@ -1106,6 +1108,312 @@ finally: /** \} */ /* -------------------------------------------------------------------- */ +/** \name Local View Operators + * \{ */ + +static unsigned int free_localbit(Main *bmain) +{ + ScrArea *sa; + bScreen *sc; + + unsigned short local_view_bits = 0; + + /* sometimes we loose a localview: when an area is closed */ + /* check all areas: which localviews are in use? */ + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl = sa->spacedata.first; + for (; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *) sl; + if (v3d->localvd) { + local_view_bits |= v3d->local_view_uuid; + } + } + } + } + } + + for (int i = 0; i < 16; i++) { + if ((local_view_bits & (1 << i)) == 0) { + return (1 << i); + } + } + + return 0; +} + +static bool view3d_localview_init( + 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 local_view_bit; + bool ok = false; + + if (v3d->localvd) { + return ok; + } + + INIT_MINMAX(min, max); + + local_view_bit = free_localbit(bmain); + + 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 { + 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(view_layer); base; base = base->next) { + if (TESTBASE(v3d, base)) { + BKE_object_minmax(base->object, min, max, false); + 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; + } + } + } + + sub_v3_v3v3(box, max, min); + size = max_fff(box[0], box[1], box[2]); + } + + if (ok == true) { + ARegion *ar; + + v3d->localvd = MEM_mallocN(sizeof(View3D), "localview"); + + memcpy(v3d->localvd, v3d, sizeof(View3D)); + + mid_v3_v3v3(mid, min, max); + + 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. */ + Object *camera_old = NULL; + float dist_new, ofs_new[3]; + + rv3d->localvd = MEM_mallocN(sizeof(RegionView3D), "localview region"); + memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D)); + + negate_v3_v3(ofs_new, mid); + + if (rv3d->persp == RV3D_CAMOB) { + rv3d->persp = RV3D_PERSP; + camera_old = v3d->camera; + } + + if (rv3d->persp == RV3D_ORTHO) { + if (size < 0.0001f) { + ok_dist = false; + } + } + + if (ok_dist) { + 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. */ + 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, + .ofs = ofs_new, .quat = rv3d->viewquat, + .dist = ok_dist ? &dist_new : NULL, .lens = &v3d->lens}); + } + } + + v3d->local_view_uuid = local_view_bit; + } + + DEG_on_visible_update(bmain, false); + return ok; +} + +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; + View3D *v3d = sa->spacedata.first; + Object *camera_old, *camera_new; + + if (v3d->localvd == NULL) return; + + camera_old = v3d->camera; + camera_new = v3d->localvd->camera; + + v3d->local_view_uuid = 0; + v3d->camera = v3d->localvd->camera; + + if (free) { + MEM_freeN(v3d->localvd); + v3d->localvd = NULL; + } + + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->localvd) { + Object *camera_old_rv3d, *camera_new_rv3d; + + camera_old_rv3d = (rv3d->persp == RV3D_CAMOB) ? camera_old : NULL; + camera_new_rv3d = (rv3d->localvd->persp == RV3D_CAMOB) ? camera_new : NULL; + + rv3d->view = rv3d->localvd->view; + rv3d->persp = rv3d->localvd->persp; + rv3d->camzoom = rv3d->localvd->camzoom; + + ED_view3d_smooth_view_ex( + depsgraph, + wm, win, sa, + v3d, ar, smooth_viewtx, + &(const V3D_SmoothParams) { + .camera_old = camera_old_rv3d, .camera = camera_new_rv3d, + .ofs = rv3d->localvd->ofs, .quat = rv3d->localvd->viewquat, + .dist = &rv3d->localvd->dist}); + + if (free) { + MEM_freeN(rv3d->localvd); + rv3d->localvd = NULL; + } + } + + ED_view3d_shade_update(bmain, v3d, sa); + } + } +} + +static bool view3d_localview_exit( + 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 local_view_bit; + + if (v3d->localvd) { + + local_view_bit = v3d->local_view_uuid; + + restore_localviewdata(depsgraph, wm, win, bmain, sa, smooth_viewtx); + + 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); + } + } + } + + DEG_on_visible_update(bmain, false); + + return true; + } + else { + return false; + } +} + +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(depsgraph, wm, win, bmain, view_layer, sa, smooth_viewtx); + } + else { + changed = view3d_localview_init(depsgraph, wm, win, bmain, view_layer, sa, smooth_viewtx, op->reports); + } + + if (changed) { + DEG_id_type_tag(bmain, ID_OB); + ED_area_tag_redraw(sa); + + /* Unselected objects become selected when exiting. */ + if (v3d->localvd == NULL) { + 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; + } + else { + return OPERATOR_CANCELLED; + } +} + +void VIEW3D_OT_localview(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Local View"; + ot->description = "Toggle display of selected object(s) separately and centered in view"; + ot->idname = "VIEW3D_OT_localview"; + + /* api callbacks */ + ot->exec = localview_exec; + ot->flag = OPTYPE_UNDO; /* localview changes object layer bitflags */ + + ot->poll = ED_operator_view3d_active; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name View Layer Utilities * \{ */ |