Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_view3d/view3d_view.c')
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c308
1 files changed, 308 insertions, 0 deletions
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
* \{ */