Cleanup: move 3D view utilities into own file
authorCampbell Barton <ideasman42@gmail.com>
Sun, 28 Jan 2018 03:44:42 +0000 (14:44 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 28 Jan 2018 04:01:35 +0000 (15:01 +1100)
Operators and utility functions were getting too mixed up,
the files were also quite large.

source/blender/editors/include/ED_view3d.h
source/blender/editors/space_view3d/CMakeLists.txt
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/editors/space_view3d/view3d_project.c
source/blender/editors/space_view3d/view3d_utils.c [new file with mode: 0644]
source/blender/editors/space_view3d/view3d_view.c

index e262e3eece660dc67749ec9d251b65dd634160f6..6e01245e6dcb7fa9123ba571d2fce1ce6c3c3ff4 100644 (file)
@@ -215,6 +215,8 @@ eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *ar, float perspm
 eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
 eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
 
+float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
+
 float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
 bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]);
 bool ED_view3d_win_to_ray(
@@ -276,8 +278,6 @@ void ED_view3d_clipping_set(struct RegionView3D *rv3d);
 void ED_view3d_clipping_enable(void);
 void ED_view3d_clipping_disable(void);
 
-float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
-
 float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
 float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
 float ED_view3d_radius_to_dist(
@@ -406,6 +406,9 @@ uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d)
 uint64_t ED_view3d_screen_datamask(const struct bScreen *screen);
 
 bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
+void ED_view3d_persp_switch_from_camera(struct View3D *v3d, struct RegionView3D *rv3d, const char persp);
+bool ED_view3d_persp_ensure(struct View3D *v3d, struct ARegion *ar);
+
 
 /* camera lock functions */
 bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
index a5c60248bf175dc82a1d45afa1adf77379fa470e..e25a9c04f15b3648bb45d24189b84ed2431b1bc3 100644 (file)
@@ -63,6 +63,7 @@ set(SRC
        view3d_select.c
        view3d_snap.c
        view3d_toolbar.c
+       view3d_utils.c
        view3d_view.c
 
        view3d_intern.h
index 7b5fc8ee06145ee87b784dd2e75e4bc187f37c67..861808118cd19b241ecc78a643c8d9a6b1f1e11e 100644 (file)
 
 #include "MEM_guardedalloc.h"
 
-#include "BLI_bitmap_draw_2d.h"
 #include "BLI_blenlib.h"
-#include "BLI_kdopbvh.h"
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 
 #include "BKE_armature.h"
-#include "BKE_camera.h"
 #include "BKE_context.h"
 #include "BKE_font.h"
 #include "BKE_library.h"
@@ -60,7 +57,6 @@
 #include "BKE_scene.h"
 #include "BKE_screen.h"
 #include "BKE_action.h"
-#include "BKE_depsgraph.h" /* for ED_view3d_camera_lock_sync */
 
 
 #include "BIF_gl.h"
@@ -74,7 +70,6 @@
 
 #include "ED_armature.h"
 #include "ED_particle.h"
-#include "ED_keyframing.h"
 #include "ED_screen.h"
 #include "ED_transform.h"
 #include "ED_mesh.h"
 
 #include "view3d_intern.h"  /* own include */
 
-static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar);
-
-/* -------------------------------------------------------------------- */
-/** \name View Utilities
- *
- * Lock the camera to the view-port, allowing view manipulation to transform the camera.
- * \{ */
-
-/**
- * Use to store the last view, before entering camera view.
- */
-void ED_view3d_lastview_store(RegionView3D *rv3d)
-{
-       copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
-       rv3d->lview = rv3d->view;
-       if (rv3d->persp != RV3D_CAMOB) {
-               rv3d->lpersp = rv3d->persp;
-       }
-}
-
-void ED_view3d_lock_clear(View3D *v3d)
-{
-       v3d->ob_centre = NULL;
-       v3d->ob_centre_bone[0] = '\0';
-       v3d->ob_centre_cursor = false;
-       v3d->flag2 &= ~V3D_LOCK_CAMERA;
-}
-
-bool ED_view3d_offset_lock_check(const  View3D *v3d, const  RegionView3D *rv3d)
-{
-       return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
-}
-
-/**
- * For viewport operators that exit camera persp.
- *
- * \note This differs from simply setting ``rv3d->persp = persp`` because it
- * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera,
- * otherwise switching out of camera view may jump to a different part of the scene.
- */
-static void view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp)
-{
-       BLI_assert(rv3d->persp == RV3D_CAMOB);
-       BLI_assert(persp != RV3D_CAMOB);
-
-       if (v3d->camera) {
-               rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
-               ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
-       }
-
-       if (!ED_view3d_camera_lock_check(v3d, rv3d)) {
-               rv3d->persp = persp;
-       }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Camera Lock API
- *
- * Lock the camera to the view-port, allowing view manipulation to transform the camera.
- * \{ */
-
-/**
- * \return true when the view-port is locked to its camera.
- */
-bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
-{
-       return ((v3d->camera) &&
-               (!ID_IS_LINKED(v3d->camera)) &&
-               (v3d->flag2 & V3D_LOCK_CAMERA) &&
-               (rv3d->persp == RV3D_CAMOB));
-}
-
-/**
- * Apply the camera object transformation to the view-port.
- * (needed so we can use regular view-port manipulation operators, that sync back to the camera).
- */
-void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist)
-{
-       if (ED_view3d_camera_lock_check(v3d, rv3d)) {
-               if (calc_dist) {
-                       /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */
-                       rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
-               }
-               ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
-       }
-}
-
-void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d)
-{
-       ED_view3d_camera_lock_init_ex(v3d, rv3d, true);
-}
-
-/**
- * Apply the view-port transformation back to the camera object.
- *
- * \return true if the camera is moved.
- */
-bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
-{
-       if (ED_view3d_camera_lock_check(v3d, rv3d)) {
-               ObjectTfmProtectedChannels obtfm;
-               Object *root_parent;
-
-               if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
-                       Object *ob_update;
-                       float tmat[4][4];
-                       float imat[4][4];
-                       float view_mat[4][4];
-                       float diff_mat[4][4];
-                       float parent_mat[4][4];
-
-                       while (root_parent->parent) {
-                               root_parent = root_parent->parent;
-                       }
-
-                       ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
-
-                       normalize_m4_m4(tmat, v3d->camera->obmat);
-
-                       invert_m4_m4(imat, tmat);
-                       mul_m4_m4m4(diff_mat, view_mat, imat);
-
-                       mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat);
-
-                       BKE_object_tfm_protected_backup(root_parent, &obtfm);
-                       BKE_object_apply_mat4(root_parent, parent_mat, true, false);
-                       BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag);
-
-                       ob_update = v3d->camera;
-                       while (ob_update) {
-                               DAG_id_tag_update(&ob_update->id, OB_RECALC_OB);
-                               WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update);
-                               ob_update = ob_update->parent;
-                       }
-               }
-               else {
-                       /* always maintain the same scale */
-                       const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ);
-                       BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
-                       ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
-                       BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all);
-
-                       DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
-                       WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera);
-               }
-
-               return true;
-       }
-       else {
-               return false;
-       }
-}
-
-bool ED_view3d_camera_autokey(
-        Scene *scene, ID *id_key,
-        struct bContext *C, const bool do_rotate, const bool do_translate)
-{
-       if (autokeyframe_cfra_can_key(scene, id_key)) {
-               const float cfra = (float)CFRA;
-               ListBase dsources = {NULL, NULL};
-
-               /* add data-source override for the camera object */
-               ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
-
-               /* insert keyframes
-                * 1) on the first frame
-                * 2) on each subsequent frame
-                *    TODO: need to check in future that frame changed before doing this
-                */
-               if (do_rotate) {
-                       struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID);
-                       ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
-               }
-               if (do_translate) {
-                       struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
-                       ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
-               }
-
-               /* free temp data */
-               BLI_freelistN(&dsources);
-
-               return true;
-       }
-       else {
-               return false;
-       }
-}
-
-/**
- * Call after modifying a locked view.
- *
- * \note Not every view edit currently auto-keys (numpad for eg),
- * this is complicated because of smoothview.
- */
-bool ED_view3d_camera_lock_autokey(
-        View3D *v3d, RegionView3D *rv3d,
-        struct bContext *C, const bool do_rotate, const bool do_translate)
-{
-       /* similar to ED_view3d_cameracontrol_update */
-       if (ED_view3d_camera_lock_check(v3d, rv3d)) {
-               Scene *scene = CTX_data_scene(C);
-               ID *id_key;
-               Object *root_parent;
-               if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
-                       while (root_parent->parent) {
-                               root_parent = root_parent->parent;
-                       }
-                       id_key = &root_parent->id;
-               }
-               else {
-                       id_key = &v3d->camera->id;
-               }
-
-               return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
-       }
-       else {
-               return false;
-       }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Box View Support
- *
- * Use with quad-split so each view is clipped by the bounds of each view axis.
- * \{ */
-
-static void view3d_boxview_clip(ScrArea *sa)
-{
-       ARegion *ar;
-       BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
-       float clip[6][4];
-       float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
-       int val;
-
-       /* create bounding box */
-       for (ar = sa->regionbase.first; ar; ar = ar->next) {
-               if (ar->regiontype == RGN_TYPE_WINDOW) {
-                       RegionView3D *rv3d = ar->regiondata;
-
-                       if (rv3d->viewlock & RV3D_BOXCLIP) {
-                               if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
-                                       if (ar->winx > ar->winy) x1 = rv3d->dist;
-                                       else x1 = ar->winx * rv3d->dist / ar->winy;
-
-                                       if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx;
-                                       else y1 = rv3d->dist;
-                                       copy_v2_v2(ofs, rv3d->ofs);
-                               }
-                               else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
-                                       ofs[2] = rv3d->ofs[2];
-
-                                       if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx;
-                                       else z1 = rv3d->dist;
-                               }
-                       }
-               }
-       }
-
-       for (val = 0; val < 8; val++) {
-               if (ELEM(val, 0, 3, 4, 7))
-                       bb->vec[val][0] = -x1 - ofs[0];
-               else
-                       bb->vec[val][0] =  x1 - ofs[0];
-
-               if (ELEM(val, 0, 1, 4, 5))
-                       bb->vec[val][1] = -y1 - ofs[1];
-               else
-                       bb->vec[val][1] =  y1 - ofs[1];
-
-               if (val > 3)
-                       bb->vec[val][2] = -z1 - ofs[2];
-               else
-                       bb->vec[val][2] =  z1 - ofs[2];
-       }
-
-       /* normals for plane equations */
-       normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]);
-       normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]);
-       normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]);
-       normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]);
-       normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]);
-       normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]);
-
-       /* then plane equations */
-       for (val = 0; val < 6; val++) {
-               clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]);
-       }
-
-       /* create bounding box */
-       for (ar = sa->regionbase.first; ar; ar = ar->next) {
-               if (ar->regiontype == RGN_TYPE_WINDOW) {
-                       RegionView3D *rv3d = ar->regiondata;
-
-                       if (rv3d->viewlock & RV3D_BOXCLIP) {
-                               rv3d->rflag |= RV3D_CLIPPING;
-                               memcpy(rv3d->clip, clip, sizeof(clip));
-                               if (rv3d->clipbb) MEM_freeN(rv3d->clipbb);
-                               rv3d->clipbb = MEM_dupallocN(bb);
-                       }
-               }
-       }
-       MEM_freeN(bb);
-}
-
-/**
- * Find which axis values are shared between both views and copy to \a rv3d_dst
- * taking axis flipping into account.
- */
-static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src)
-{
-       /* absolute axis values above this are considered to be set (will be ~1.0f) */
-       const float axis_eps = 0.5f;
-       float viewinv[4];
-
-       /* use the view rotation to identify which axis to sync on */
-       float view_axis_all[4][3] = {
-           {1.0f, 0.0f, 0.0f},
-           {0.0f, 1.0f, 0.0f},
-           {1.0f, 0.0f, 0.0f},
-           {0.0f, 1.0f, 0.0f}};
-
-       float *view_src_x = &view_axis_all[0][0];
-       float *view_src_y = &view_axis_all[1][0];
-
-       float *view_dst_x = &view_axis_all[2][0];
-       float *view_dst_y = &view_axis_all[3][0];
-       int i;
-
-
-       /* we could use rv3d->viewinv, but better not depend on view matrix being updated */
-       if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) {
-               return;
-       }
-       invert_qt_normalized(viewinv);
-       mul_qt_v3(viewinv, view_src_x);
-       mul_qt_v3(viewinv, view_src_y);
-
-       if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) {
-               return;
-       }
-       invert_qt_normalized(viewinv);
-       mul_qt_v3(viewinv, view_dst_x);
-       mul_qt_v3(viewinv, view_dst_y);
-
-       /* check source and dest have a matching axis */
-       for (i = 0; i < 3; i++) {
-               if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) &&
-                   ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps)))
-               {
-                       rv3d_dst->ofs[i] = rv3d_src->ofs[i];
-               }
-       }
-}
-
-/* sync center/zoom view of region to others, for view transforms */
-static void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
-{
-       ARegion *artest;
-       RegionView3D *rv3d = ar->regiondata;
-       short clip = 0;
-
-       for (artest = sa->regionbase.first; artest; artest = artest->next) {
-               if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
-                       RegionView3D *rv3dtest = artest->regiondata;
-
-                       if (rv3dtest->viewlock & RV3D_LOCKED) {
-                               rv3dtest->dist = rv3d->dist;
-                               view3d_boxview_sync_axis(rv3dtest, rv3d);
-                               clip |= rv3dtest->viewlock & RV3D_BOXCLIP;
-
-                               ED_region_tag_redraw(artest);
-                       }
-               }
-       }
-
-       if (clip) {
-               view3d_boxview_clip(sa);
-       }
-}
-
-/* for home, center etc */
-void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
-{
-       ARegion *artest;
-       RegionView3D *rv3d = ar->regiondata;
-       bool clip = false;
-
-       for (artest = sa->regionbase.first; artest; artest = artest->next) {
-               if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
-                       RegionView3D *rv3dtest = artest->regiondata;
-
-                       if (rv3dtest->viewlock) {
-                               rv3dtest->dist = rv3d->dist;
-                               copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
-                               ED_region_tag_redraw(artest);
-
-                               clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0);
-                       }
-               }
-       }
-
-       if (clip) {
-               view3d_boxview_clip(sa);
-       }
-}
-
-/* 'clip' is used to know if our clip setting has changed */
-void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
-{
-       ARegion *ar_sync = NULL;
-       RegionView3D *rv3d = ar->regiondata;
-       short viewlock;
-       /* this function copies flags from the first of the 3 other quadview
-        * regions to the 2 other, so it assumes this is the region whose
-        * properties are always being edited, weak */
-       viewlock = rv3d->viewlock;
-
-       if ((viewlock & RV3D_LOCKED) == 0) {
-               do_clip = (viewlock & RV3D_BOXCLIP) != 0;
-               viewlock = 0;
-       }
-       else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) {
-               do_clip = true;
-               viewlock &= ~RV3D_BOXCLIP;
-       }
-
-       for (; ar; ar = ar->prev) {
-               if (ar->alignment == RGN_ALIGN_QSPLIT) {
-                       rv3d = ar->regiondata;
-                       rv3d->viewlock = viewlock;
-
-                       if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) {
-                               rv3d->rflag &= ~RV3D_BOXCLIP;
-                       }
-
-                       /* use ar_sync so we sync with one of the aligned views below
-                        * else the view jumps on changing view settings like 'clip'
-                        * since it copies from the perspective view */
-                       ar_sync = ar;
-               }
-       }
-
-       if (rv3d->viewlock & RV3D_BOXVIEW) {
-               view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last);
-       }
-
-       /* ensure locked regions have an axis, locked user views don't make much sense */
-       if (viewlock & RV3D_LOCKED) {
-               int index_qsplit = 0;
-               for (ar = sa->regionbase.first; ar; ar = ar->next) {
-                       if (ar->alignment == RGN_ALIGN_QSPLIT) {
-                               rv3d = ar->regiondata;
-                               if (rv3d->viewlock) {
-                                       if (!RV3D_VIEW_IS_AXIS(rv3d->view)) {
-                                               rv3d->view = ED_view3d_lock_view_from_index(index_qsplit);
-                                               rv3d->persp = RV3D_ORTHO;
-                                               ED_view3d_lock(rv3d);
-                                       }
-                               }
-                               index_qsplit++;
-                       }
-               }
-       }
-
-       ED_area_tag_redraw(sa);
-}
-
-/** \} */
-
 /* -------------------------------------------------------------------- */
 /** \name Generic View Operator Custom-Data
  * \{ */
@@ -764,7 +286,7 @@ static enum eViewOpsOrbit viewops_orbit_mode(void)
 /**
  * Calculate the values for #ViewOpsData
  *
- * \param use_ensure_persp: When enabled run #view3d_ensure_persp this may switch out of
+ * \param use_ensure_persp: When enabled run #ED_view3d_persp_ensure this may switch out of
  * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled.
  * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common
  * so we don't want it to trigger auto-perspective).
@@ -793,7 +315,7 @@ static void viewops_data_create_ex(
        }
 
        if (use_ensure_persp) {
-               if (view3d_ensure_persp(vod->v3d, vod->ar)) {
+               if (ED_view3d_persp_ensure(vod->v3d, vod->ar)) {
                        /* If we're switching from camera view to the perspective one,
                         * need to tag viewport update, so camera vuew and borders
                         * are properly updated.
@@ -927,7 +449,7 @@ static void viewops_data_free(bContext *C, wmOperator *op)
 /** \} */
 
 /* -------------------------------------------------------------------- */
-/** \name View Rotate
+/** \name View Rotate Operator
  * \{ */
 
 enum {
@@ -1260,37 +782,6 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
        return ret;
 }
 
-/**
- * Action to take when rotating the view,
- * handle auto-persp and logic for switching out of views.
- *
- * shared with NDOF.
- */
-static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar)
-{
-       RegionView3D *rv3d = ar->regiondata;
-       const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
-
-       BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
-
-       if (ED_view3d_camera_lock_check(v3d, rv3d))
-               return false;
-
-       if (rv3d->persp != RV3D_PERSP) {
-               if (rv3d->persp == RV3D_CAMOB) {
-                       /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */
-                       char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp;
-                       view3d_persp_switch_from_camera(v3d, rv3d, persp);
-               }
-               else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
-                       rv3d->persp = RV3D_PERSP;
-               }
-               return true;
-       }
-
-       return false;
-}
-
 static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
        ViewOpsData *vod;
@@ -1525,7 +1016,7 @@ static void view3d_ndof_orbit(
 
        BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
 
-       view3d_ensure_persp(v3d, ar);
+       ED_view3d_persp_ensure(v3d, ar);
 
        rv3d->view = RV3D_VIEW_USER;
 
@@ -2038,8 +1529,9 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y)
 
                add_v3_v3(vod->rv3d->ofs, dvec);
 
-               if (vod->rv3d->viewlock & RV3D_BOXVIEW)
+               if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
                        view3d_boxview_sync(vod->sa, vod->ar);
+               }
        }
 
        vod->oldx = x;
@@ -2402,8 +1894,9 @@ static void viewzoom_apply_3d(
        /* these limits were in old code too */
        CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]);
 
-       if (vod->rv3d->viewlock & RV3D_BOXVIEW)
+       if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
                view3d_boxview_sync(vod->sa, vod->ar);
+       }
 
        ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
 
@@ -2539,8 +2032,9 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
                }
        }
 
-       if (rv3d->viewlock & RV3D_BOXVIEW)
+       if (rv3d->viewlock & RV3D_BOXVIEW) {
                view3d_boxview_sync(sa, ar);
+       }
 
        ED_view3d_depth_tag_update(rv3d);
 
@@ -2728,8 +2222,9 @@ static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_inv
        if (zfac != 1.0f)
                view_dolly_mouseloc(vod->ar, vod->ofs, vod->mousevec, zfac);
 
-       if (vod->rv3d->viewlock & RV3D_BOXVIEW)
+       if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
                view3d_boxview_sync(vod->sa, vod->ar);
+       }
 
        ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
 
@@ -2829,8 +2324,9 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
                view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 1.8f);
        }
 
-       if (rv3d->viewlock & RV3D_BOXVIEW)
+       if (rv3d->viewlock & RV3D_BOXVIEW) {
                view3d_boxview_sync(sa, ar);
+       }
 
        ED_view3d_depth_tag_update(rv3d);
 
@@ -2868,7 +2364,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
        if (vod->rv3d->persp != RV3D_PERSP) {
                if (vod->rv3d->persp == RV3D_CAMOB) {
                        /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */
-                       view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP);
+                       ED_view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP);
                }
                else {
                        vod->rv3d->persp = RV3D_PERSP;
@@ -3842,8 +3338,9 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
                C, v3d, ar, smooth_viewtx,
                &(const V3D_SmoothParams) {.ofs = new_ofs, .dist = &new_dist});
 
-       if (rv3d->viewlock & RV3D_BOXVIEW)
+       if (rv3d->viewlock & RV3D_BOXVIEW) {
                view3d_boxview_sync(CTX_wm_area(C), ar);
+       }
 
        return OPERATOR_FINISHED;
 }
@@ -4226,7 +3723,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
                        float quat_new[4];
 
                        if (view_opposite == RV3D_VIEW_USER) {
-                               view3d_ensure_persp(v3d, ar);
+                               ED_view3d_persp_ensure(v3d, ar);
                        }
 
                        if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) {
@@ -4347,8 +3844,9 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y))
                view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->ofs, vod->oldquat, vod->rv3d->viewquat, vod->dyn_ofs);
        }
 
-       if (vod->rv3d->viewlock & RV3D_BOXVIEW)
+       if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
                view3d_boxview_sync(vod->sa, vod->ar);
+       }
 
        ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
 
@@ -5116,368 +4614,3 @@ void VIEW3D_OT_toggle_render(wmOperatorType *ot)
 }
 
 /** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name View Distance Utilities
- * \{ */
-
-static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin)
-{
-       ViewDepths depth_temp = {0};
-       rcti rect;
-       float depth_close;
-
-       if (margin == 0) {
-               /* Get Z Depths, needed for perspective, nice for ortho */
-               rect.xmin = mval[0];
-               rect.ymin = mval[1];
-               rect.xmax = mval[0] + 1;
-               rect.ymax = mval[1] + 1;
-       }
-       else {
-               BLI_rcti_init_pt_radius(&rect, mval, margin);
-       }
-
-       view3d_update_depths_rect(ar, &depth_temp, &rect);
-       depth_close = view3d_depth_near(&depth_temp);
-       MEM_SAFE_FREE(depth_temp.depths);
-       return depth_close;
-}
-
-/**
- * Get the world-space 3d location from a screen-space 2d point.
- *
- * \param mval: Input screen-space pixel location.
- * \param mouse_worldloc: Output world-space location.
- * \param fallback_depth_pt: Use this points depth when no depth can be found.
- */
-bool ED_view3d_autodist(
-        Scene *scene, ARegion *ar, View3D *v3d,
-        const int mval[2], float mouse_worldloc[3],
-        const bool alphaoverride, const float fallback_depth_pt[3])
-{
-       bglMats mats; /* ZBuffer depth vars */
-       float depth_close;
-       double cent[2],  p[3];
-       int margin_arr[] = {0, 2, 4};
-       int i;
-       bool depth_ok = false;
-
-       /* Get Z Depths, needed for perspective, nice for ortho */
-       ED_view3d_draw_depth(scene, ar, v3d, alphaoverride);
-
-       /* call after in case settings have been modified since last drawing, see: T47089 */
-       bgl_get_mats(&mats);
-
-       /* Attempt with low margin's first */
-       i = 0;
-       do {
-               depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize);
-               depth_ok = (depth_close != FLT_MAX);
-       } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
-
-       if (depth_ok) {
-               cent[0] = (double)mval[0] + 0.5;
-               cent[1] = (double)mval[1] + 0.5;
-
-               if (gluUnProject(cent[0], cent[1], depth_close,
-                                mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
-               {
-                       mouse_worldloc[0] = (float)p[0];
-                       mouse_worldloc[1] = (float)p[1];
-                       mouse_worldloc[2] = (float)p[2];
-                       return true;
-               }
-       }
-
-       if (fallback_depth_pt) {
-               ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc);
-               return true;
-       }
-       else {
-               return false;
-       }
-}
-
-void ED_view3d_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode)
-{
-       /* Get Z Depths, needed for perspective, nice for ortho */
-       switch (mode) {
-               case 0:
-                       ED_view3d_draw_depth(scene, ar, v3d, true);
-                       break;
-               case 1:
-                       ED_view3d_draw_depth_gpencil(scene, ar, v3d);
-                       break;
-       }
-}
-
-/* no 4x4 sampling, run #ED_view3d_autodist_init first */
-bool ED_view3d_autodist_simple(
-        ARegion *ar, const int mval[2], float mouse_worldloc[3],
-        int margin, float *force_depth)
-{
-       bglMats mats; /* ZBuffer depth vars, could cache? */
-       float depth;
-       double cent[2],  p[3];
-
-       /* Get Z Depths, needed for perspective, nice for ortho */
-       if (force_depth)
-               depth = *force_depth;
-       else
-               depth = view_autodist_depth_margin(ar, mval, margin);
-
-       if (depth == FLT_MAX)
-               return false;
-
-       cent[0] = (double)mval[0] + 0.5;
-       cent[1] = (double)mval[1] + 0.5;
-
-       bgl_get_mats(&mats);
-
-       if (!gluUnProject(cent[0], cent[1], depth,
-                         mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
-       {
-               return false;
-       }
-
-       mouse_worldloc[0] = (float)p[0];
-       mouse_worldloc[1] = (float)p[1];
-       mouse_worldloc[2] = (float)p[2];
-       return true;
-}
-
-bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth)
-{
-       *depth = view_autodist_depth_margin(ar, mval, margin);
-
-       return (*depth != FLT_MAX);
-}
-
-static bool depth_segment_cb(int x, int y, void *userData)
-{
-       struct { ARegion *ar; int margin; float depth; } *data = userData;
-       int mval[2];
-       float depth;
-
-       mval[0] = x;
-       mval[1] = y;
-
-       depth = view_autodist_depth_margin(data->ar, mval, data->margin);
-
-       if (depth != FLT_MAX) {
-               data->depth = depth;
-               return 0;
-       }
-       else {
-               return 1;
-       }
-}
-
-bool ED_view3d_autodist_depth_seg(
-        ARegion *ar, const int mval_sta[2], const int mval_end[2],
-        int margin, float *depth)
-{
-       struct { ARegion *ar; int margin; float depth; } data = {NULL};
-       int p1[2];
-       int p2[2];
-
-       data.ar = ar;
-       data.margin = margin;
-       data.depth = FLT_MAX;
-
-       copy_v2_v2_int(p1, mval_sta);
-       copy_v2_v2_int(p2, mval_end);
-
-       BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data);
-
-       *depth = data.depth;
-
-       return (*depth != FLT_MAX);
-}
-
-/* problem - ofs[3] can be on same location as camera itself.
- * Blender needs proper dist value for zoom.
- * use fallback_dist to override small values
- */
-float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist)
-{
-       float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
-       float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f};
-       float dist;
-       
-       mul_m4_v4(mat, pos);
-       add_v3_v3(pos, ofs);
-       mul_m4_v4(mat, dir);
-       normalize_v3(dir);
-
-       dist = dot_v3v3(pos, dir);
-
-       if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) {
-               dist = fallback_dist;
-       }
-
-       return dist;
-}
-
-/**
- * Set the dist without moving the view (compensate with #RegionView3D.ofs)
- *
- * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first.
- */
-void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
-{
-       float viewinv[4];
-       float tvec[3];
-
-       BLI_assert(dist >= 0.0f);
-
-       copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist);
-       /* rv3d->viewinv isn't always valid */
-#if 0
-       mul_mat3_m4_v3(rv3d->viewinv, tvec);
-#else
-       invert_qt_qt_normalized(viewinv, rv3d->viewquat);
-       mul_qt_v3(viewinv, tvec);
-#endif
-       sub_v3_v3(rv3d->ofs, tvec);
-
-       rv3d->dist = dist;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name View Transform Utilities
- * \{ */
-
-/**
- * Set the view transformation from a 4x4 matrix.
- *
- * \param mat The view 4x4 transformation matrix to assign.
- * \param ofs The view offset, normally from RegionView3D.ofs.
- * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist The view distance from ofs, normally from RegionView3D.dist.
- */
-void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist)
-{
-       float nmat[3][3];
-
-       /* dist depends on offset */
-       BLI_assert(dist == NULL || ofs != NULL);
-
-       copy_m3_m4(nmat, mat);
-       normalize_m3(nmat);
-
-       /* Offset */
-       if (ofs)
-               negate_v3_v3(ofs, mat[3]);
-
-       /* Quat */
-       if (quat) {
-               mat3_normalized_to_quat(quat, nmat);
-               invert_qt_normalized(quat);
-       }
-
-       if (ofs && dist) {
-               madd_v3_v3fl(ofs, nmat[2], *dist);
-       }
-}
-
-/**
- * Calculate the view transformation matrix from RegionView3D input.
- * The resulting matrix is equivalent to RegionView3D.viewinv
- * \param mat The view 4x4 transformation matrix to calculate.
- * \param ofs The view offset, normally from RegionView3D.ofs.
- * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist The view distance from ofs, normally from RegionView3D.dist.
- */
-void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
-{
-       float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
-       float dvec[3] = {0.0f, 0.0f, dist};
-
-       quat_to_mat4(mat, iviewquat);
-       mul_mat3_m4_v3(mat, dvec);
-       sub_v3_v3v3(mat[3], dvec, ofs);
-}
-
-/**
- * Set the RegionView3D members from an objects transformation and optionally lens.
- * \param ob The object to set the view to.
- * \param ofs The view offset to be set, normally from RegionView3D.ofs.
- * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat.
- * \param dist The view distance from ofs to be set, normally from RegionView3D.dist.
- * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens.
- */
-void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
-{
-       ED_view3d_from_m4(ob->obmat, ofs, quat, dist);
-
-       if (lens) {
-               CameraParams params;
-
-               BKE_camera_params_init(&params);
-               BKE_camera_params_from_object(&params, ob);
-               *lens = params.lens;
-       }
-}
-
-/**
- * Set the object transformation from RegionView3D members.
- * \param ob The object which has the transformation assigned.
- * \param ofs The view offset, normally from RegionView3D.ofs.
- * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist The view distance from ofs, normally from RegionView3D.dist.
- */
-void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist)
-{
-       float mat[4][4];
-       ED_view3d_to_m4(mat, ofs, quat, dist);
-       BKE_object_apply_mat4(ob, mat, true, true);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Background Image Utilities
- * \{ */
-
-BGpic *ED_view3d_background_image_new(View3D *v3d)
-{
-       BGpic *bgpic = MEM_callocN(sizeof(BGpic), "Background Image");
-
-       bgpic->rotation = 0.0f;
-       bgpic->size = 5.0f;
-       bgpic->blend = 0.5f;
-       bgpic->iuser.fie_ima = 2;
-       bgpic->iuser.ok = 1;
-       bgpic->view = 0; /* 0 for all */
-       bgpic->flag |= V3D_BGPIC_EXPANDED;
-
-       BLI_addtail(&v3d->bgpicbase, bgpic);
-
-       return bgpic;
-}
-
-void ED_view3d_background_image_remove(View3D *v3d, BGpic *bgpic)
-{
-       BLI_remlink(&v3d->bgpicbase, bgpic);
-
-       MEM_freeN(bgpic);
-}
-
-void ED_view3d_background_image_clear(View3D *v3d)
-{
-       BGpic *bgpic = v3d->bgpicbase.first;
-
-       while (bgpic) {
-               BGpic *next_bgpic = bgpic->next;
-
-               ED_view3d_background_image_remove(v3d, bgpic);
-
-               bgpic = next_bgpic;
-       }
-}
-
-/** \} */
index 59b4f770ec3f021a674e119eeb54ed6e4eba62ae..6237bfe669332b92235276fd27925ffc4a787fdb 100644 (file)
@@ -107,6 +107,7 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
 void VIEW3D_OT_toggle_render(struct wmOperatorType *ot);
 
 void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
+void view3d_boxview_sync(ScrArea *sa, ARegion *ar);
 
 void view3d_orbit_apply_dyn_ofs(
         float r_ofs[3], const float ofs_old[3], const float viewquat_old[4],
index 65a6dee2f6cb4d9ad257fd9acce076c41a604f4f..2e876bc48b3ae787dc0396a66f25a441d3e0c937 100644 (file)
@@ -278,6 +278,11 @@ eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[
 /* More Generic Window/Ray/Vector projection functions
  * *************************************************** */
 
+float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
+{
+       return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
+}
+
 /**
  * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
  */
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
new file mode 100644 (file)
index 0000000..e40a4b3
--- /dev/null
@@ -0,0 +1,1477 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_utils.c
+ *  \ingroup spview3d
+ *
+ * 3D View checks and manipulation (no operators).
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_bitmap_draw_2d.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_camera.h"
+#include "BKE_context.h"
+#include "BKE_object.h"
+#include "BKE_screen.h"
+#include "BKE_depsgraph.h" /* for ED_view3d_camera_lock_sync */
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_keyframing.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "view3d_intern.h"  /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name View Data Access Utilities
+ *
+ * \{ */
+
+float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d)
+{
+       if (v3d && v3d->localvd) return v3d->cursor;
+       else return scene->cursor;
+}
+
+Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
+{
+       /* establish the camera object, so we can default to view mapping if anything is wrong with it */
+       if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
+               return v3d->camera->data;
+       }
+       else {
+               return NULL;
+       }
+}
+
+void ED_view3d_dist_range_get(
+        const View3D *v3d,
+        float r_dist_range[2])
+{
+       r_dist_range[0] = v3d->grid * 0.001f;
+       r_dist_range[1] = v3d->far * 10.0f;
+}
+
+/**
+ * \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
+ */
+bool ED_view3d_clip_range_get(
+        const View3D *v3d, const RegionView3D *rv3d,
+        float *r_clipsta, float *r_clipend,
+        const bool use_ortho_factor)
+{
+       CameraParams params;
+
+       BKE_camera_params_init(&params);
+       BKE_camera_params_from_view3d(&params, v3d, rv3d);
+
+       if (use_ortho_factor && params.is_ortho) {
+               const float fac = 2.0f / (params.clipend - params.clipsta);
+               params.clipsta *= fac;
+               params.clipend *= fac;
+       }
+
+       if (r_clipsta) *r_clipsta = params.clipsta;
+       if (r_clipend) *r_clipend = params.clipend;
+
+       return params.is_ortho;
+}
+
+bool ED_view3d_viewplane_get(
+        const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
+        rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
+{
+       CameraParams params;
+
+       BKE_camera_params_init(&params);
+       BKE_camera_params_from_view3d(&params, v3d, rv3d);
+       BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
+
+       if (r_viewplane) *r_viewplane = params.viewplane;
+       if (r_clipsta) *r_clipsta = params.clipsta;
+       if (r_clipend) *r_clipend = params.clipend;
+       if (r_pixsize) *r_pixsize = params.viewdx;
+
+       return params.is_ortho;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name View State/Context Utilities
+ *
+ * \{ */
+
+/**
+ * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727]
+ */
+void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
+{
+       float viewdist;
+
+       if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
+               return;
+       }
+
+       viewdist = rv3d->dist;
+
+       /* special exception for ortho camera (viewdist isnt used for perspective cameras) */
+       if (dist != 0.0f) {
+               if (rv3d->persp == RV3D_CAMOB) {
+                       if (rv3d->is_persp == false) {
+                               viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1]));
+                       }
+               }
+       }
+
+       bglPolygonOffset(viewdist, dist);
+}
+
+bool ED_view3d_context_activate(bContext *C)
+{
+       bScreen *sc = CTX_wm_screen(C);
+       ScrArea *sa = CTX_wm_area(C);
+       ARegion *ar;
+
+       /* sa can be NULL when called from python */
+       if (sa == NULL || sa->spacetype != SPACE_VIEW3D) {
+               sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0);
+       }
+
+       if (sa == NULL) {
+               return false;
+       }
+
+       ar = BKE_area_find_region_active_win(sa);
+       if (ar == NULL) {
+               return false;
+       }
+
+       /* bad context switch .. */
+       CTX_wm_area_set(C, sa);
+       CTX_wm_region_set(C, ar);
+
+       return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Clipping Utilities
+ *
+ * \{ */
+void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip)
+{
+       int val;
+
+       for (val = 0; val < 4; val++) {
+               normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
+               if (UNLIKELY(is_flip)) {
+                       negate_v3(clip[val]);
+               }
+
+               clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]);
+       }
+}
+
+void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, const rcti *rect)
+{
+       float modelview[4][4];
+       double xs, ys, p[3];
+       int val, flip_sign, a;
+
+       /* near zero floating point values can give issues with gluUnProject
+        * in side view on some implementations */
+       if (fabs(mats->modelview[0]) < 1e-6) mats->modelview[0] = 0.0;
+       if (fabs(mats->modelview[5]) < 1e-6) mats->modelview[5] = 0.0;
+
+       /* Set up viewport so that gluUnProject will give correct values */
+       mats->viewport[0] = 0;
+       mats->viewport[1] = 0;
+
+       /* four clipping planes and bounding volume */
+       /* first do the bounding volume */
+       for (val = 0; val < 4; val++) {
+               xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax;
+               ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax;
+
+               gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
+               copy_v3fl_v3db(bb->vec[val], p);
+
+               gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
+               copy_v3fl_v3db(bb->vec[4 + val], p);
+       }
+
+       /* verify if we have negative scale. doing the transform before cross
+        * product flips the sign of the vector compared to doing cross product
+        * before transform then, so we correct for that. */
+       for (a = 0; a < 16; a++)
+               ((float *)modelview)[a] = mats->modelview[a];
+       flip_sign = is_negative_m4(modelview);
+
+       ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Bound-Box Utilities
+ *
+ * \{ */
+
+static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
+{
+       int a, flag = -1, fl;
+
+       for (a = 0; a < 8; a++) {
+               float vec[4], min, max;
+               copy_v3_v3(vec, bb->vec[a]);
+               vec[3] = 1.0;
+               mul_m4_v4(persmatob, vec);
+               max = vec[3];
+               min = -vec[3];
+
+               fl = 0;
+               if (vec[0] < min) fl += 1;
+               if (vec[0] > max) fl += 2;
+               if (vec[1] < min) fl += 4;
+               if (vec[1] > max) fl += 8;
+               if (vec[2] < min) fl += 16;
+               if (vec[2] > max) fl += 32;
+
+               flag &= fl;
+               if (flag == 0) return true;
+       }
+
+       return false;
+}
+
+bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
+{
+       /* return 1: draw */
+
+       float persmatob[4][4];
+
+       if (bb == NULL) return true;
+       if (bb->flag & BOUNDBOX_DISABLED) return true;
+
+       mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat);
+
+       return view3d_boundbox_clip_m4(bb, persmatob);
+}
+
+bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
+{
+       if (bb == NULL) return true;
+       if (bb->flag & BOUNDBOX_DISABLED) return true;
+
+       return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Perspective & Mode Switching
+ *
+ * Misc view utility functions.
+ * \{ */
+
+bool ED_view3d_offset_lock_check(const  View3D *v3d, const  RegionView3D *rv3d)
+{
+       return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
+}
+
+/**
+ * Use to store the last view, before entering camera view.
+ */
+void ED_view3d_lastview_store(RegionView3D *rv3d)
+{
+       copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
+       rv3d->lview = rv3d->view;
+       if (rv3d->persp != RV3D_CAMOB) {
+               rv3d->lpersp = rv3d->persp;
+       }
+}
+
+void ED_view3d_lock_clear(View3D *v3d)
+{
+       v3d->ob_centre = NULL;
+       v3d->ob_centre_bone[0] = '\0';
+       v3d->ob_centre_cursor = false;
+       v3d->flag2 &= ~V3D_LOCK_CAMERA;
+}
+
+/**
+ * For viewport operators that exit camera perspective.
+ *
+ * \note This differs from simply setting ``rv3d->persp = persp`` because it
+ * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera,
+ * otherwise switching out of camera view may jump to a different part of the scene.
+ */
+void ED_view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp)
+{
+       BLI_assert(rv3d->persp == RV3D_CAMOB);
+       BLI_assert(persp != RV3D_CAMOB);
+
+       if (v3d->camera) {
+               rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
+               ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
+       }
+
+       if (!ED_view3d_camera_lock_check(v3d, rv3d)) {
+               rv3d->persp = persp;
+       }
+}
+/**
+ * Action to take when rotating the view,
+ * handle auto-persp and logic for switching out of views.
+ *
+ * shared with NDOF.
+ */
+bool ED_view3d_persp_ensure(struct View3D *v3d, ARegion *ar)
+{
+       RegionView3D *rv3d = ar->regiondata;
+       const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
+
+       BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
+
+       if (ED_view3d_camera_lock_check(v3d, rv3d))
+               return false;
+
+       if (rv3d->persp != RV3D_PERSP) {
+               if (rv3d->persp == RV3D_CAMOB) {
+                       /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */
+                       char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp;
+                       ED_view3d_persp_switch_from_camera(v3d, rv3d, persp);
+               }
+               else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
+                       rv3d->persp = RV3D_PERSP;
+               }
+               return true;
+       }
+
+       return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera Lock API
+ *
+ * Lock the camera to the view-port, allowing view manipulation to transform the camera.
+ * \{ */
+
+/**
+ * \return true when the view-port is locked to its camera.
+ */
+bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
+{
+       return ((v3d->camera) &&
+               (!ID_IS_LINKED(v3d->camera)) &&
+               (v3d->flag2 & V3D_LOCK_CAMERA) &&
+               (rv3d->persp == RV3D_CAMOB));
+}
+
+/**
+ * Apply the camera object transformation to the view-port.
+ * (needed so we can use regular view-port manipulation operators, that sync back to the camera).
+ */
+void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist)
+{
+       if (ED_view3d_camera_lock_check(v3d, rv3d)) {
+               if (calc_dist) {
+                       /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */
+                       rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
+               }
+               ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
+       }
+}
+
+void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d)
+{
+       ED_view3d_camera_lock_init_ex(v3d, rv3d, true);
+}
+
+/**
+ * Apply the view-port transformation back to the camera object.
+ *
+ * \return true if the camera is moved.
+ */
+bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
+{
+       if (ED_view3d_camera_lock_check(v3d, rv3d)) {
+               ObjectTfmProtectedChannels obtfm;
+               Object *root_parent;
+
+               if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
+                       Object *ob_update;
+                       float tmat[4][4];
+                       float imat[4][4];
+                       float view_mat[4][4];
+                       float diff_mat[4][4];
+                       float parent_mat[4][4];
+
+                       while (root_parent->parent) {
+                               root_parent = root_parent->parent;
+                       }
+
+                       ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
+
+                       normalize_m4_m4(tmat, v3d->camera->obmat);
+
+                       invert_m4_m4(imat, tmat);
+                       mul_m4_m4m4(diff_mat, view_mat, imat);
+
+                       mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat);
+
+                       BKE_object_tfm_protected_backup(root_parent, &obtfm);
+                       BKE_object_apply_mat4(root_parent, parent_mat, true, false);
+                       BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag);
+
+                       ob_update = v3d->camera;
+                       while (ob_update) {
+                               DAG_id_tag_update(&ob_update->id, OB_RECALC_OB);
+                               WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update);
+                               ob_update = ob_update->parent;
+                       }
+               }
+               else {
+                       /* always maintain the same scale */
+                       const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ);
+                       BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
+                       ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
+                       BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all);
+
+                       DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
+                       WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera);
+               }
+
+               return true;
+       }
+       else {
+               return false;
+       }
+}
+
+bool ED_view3d_camera_autokey(
+        Scene *scene, ID *id_key,
+        struct bContext *C, const bool do_rotate, const bool do_translate)
+{
+       if (autokeyframe_cfra_can_key(scene, id_key)) {
+               const float cfra = (float)CFRA;
+               ListBase dsources = {NULL, NULL};
+
+               /* add data-source override for the camera object */
+               ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
+
+               /* insert keyframes
+                * 1) on the first frame
+                * 2) on each subsequent frame
+                *    TODO: need to check in future that frame changed before doing this
+                */
+               if (do_rotate) {
+                       struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID);
+                       ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+               }
+               if (do_translate) {
+                       struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
+                       ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+               }
+
+               /* free temp data */
+               BLI_freelistN(&dsources);
+
+               return true;
+       }
+       else {
+               return false;
+       }
+}
+
+/**
+ * Call after modifying a locked view.
+ *
+ * \note Not every view edit currently auto-keys (numpad for eg),
+ * this is complicated because of smoothview.
+ */
+bool ED_view3d_camera_lock_autokey(
+        View3D *v3d, RegionView3D *rv3d,
+        struct bContext *C, const bool do_rotate, const bool do_translate)
+{
+       /* similar to ED_view3d_cameracontrol_update */
+       if (ED_view3d_camera_lock_check(v3d, rv3d)) {
+               Scene *scene = CTX_data_scene(C);
+               ID *id_key;
+               Object *root_parent;
+               if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
+                       while (root_parent->parent) {
+                               root_parent = root_parent->parent;
+                       }
+                       id_key = &root_parent->id;
+               }
+               else {
+                       id_key = &v3d->camera->id;
+               }
+
+               return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
+       }
+       else {
+               return false;
+       }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Box View Support
+ *
+ * Use with quad-split so each view is clipped by the bounds of each view axis.
+ * \{ */
+
+static void view3d_boxview_clip(ScrArea *sa)
+{
+       ARegion *ar;
+       BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
+       float clip[6][4];
+       float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
+       int val;
+
+       /* create bounding box */
+       for (ar = sa->regionbase.first; ar; ar = ar->next) {
+               if (ar->regiontype == RGN_TYPE_WINDOW) {
+                       RegionView3D *rv3d = ar->regiondata;
+
+                       if (rv3d->viewlock & RV3D_BOXCLIP) {
+                               if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
+                                       if (ar->winx > ar->winy) x1 = rv3d->dist;
+                                       else x1 = ar->winx * rv3d->dist / ar->winy;
+
+                                       if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx;
+                                       else y1 = rv3d->dist;
+                                       copy_v2_v2(ofs, rv3d->ofs);
+                               }
+                               else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
+                                       ofs[2] = rv3d->ofs[2];
+
+                                       if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx;
+                                       else z1 = rv3d->dist;
+                               }
+                       }
+               }
+       }
+
+       for (val = 0; val < 8; val++) {
+               if (ELEM(val, 0, 3, 4, 7))
+                       bb->vec[val][0] = -x1 - ofs[0];
+               else
+                       bb->vec[val][0] =  x1 - ofs[0];
+
+               if (ELEM(val, 0, 1, 4, 5))
+                       bb->vec[val][1] = -y1 - ofs[1];
+               else
+                       bb->vec[val][1] =  y1 - ofs[1];
+
+               if (val > 3)
+                       bb->vec[val][2] = -z1 - ofs[2];
+               else
+                       bb->vec[val][2] =  z1 - ofs[2];
+       }
+
+       /* normals for plane equations */
+       normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]);
+       normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]);
+       normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]);
+       normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]);
+       normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]);
+       normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]);
+
+       /* then plane equations */
+       for (val = 0; val < 6; val++) {
+               clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]);
+       }
+
+       /* create bounding box */
+       for (ar = sa->regionbase.first; ar; ar = ar->next) {
+               if (ar->regiontype == RGN_TYPE_WINDOW) {
+                       RegionView3D *rv3d = ar->regiondata;
+
+                       if (rv3d->viewlock & RV3D_BOXCLIP) {
+                               rv3d->rflag |= RV3D_CLIPPING;
+                               memcpy(rv3d->clip, clip, sizeof(clip));
+                               if (rv3d->clipbb) MEM_freeN(rv3d->clipbb);
+                               rv3d->clipbb = MEM_dupallocN(bb);
+                       }
+               }
+       }
+       MEM_freeN(bb);
+}
+
+/**
+ * Find which axis values are shared between both views and copy to \a rv3d_dst
+ * taking axis flipping into account.
+ */
+static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src)
+{
+       /* absolute axis values above this are considered to be set (will be ~1.0f) */
+       const float axis_eps = 0.5f;
+       float viewinv[4];
+
+       /* use the view rotation to identify which axis to sync on */
+       float view_axis_all[4][3] = {
+           {1.0f, 0.0f, 0.0f},
+           {0.0f, 1.0f, 0.0f},
+           {1.0f, 0.0f, 0.0f},
+           {0.0f, 1.0f, 0.0f}};
+
+       float *view_src_x = &view_axis_all[0][0];
+       float *view_src_y = &view_axis_all[1][0];
+
+       float *view_dst_x = &view_axis_all[2][0];
+       float *view_dst_y = &view_axis_all[3][0];
+       int i;
+
+
+       /* we could use rv3d->viewinv, but better not depend on view matrix being updated */
+       if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) {
+               return;
+       }
+       invert_qt_normalized(viewinv);
+       mul_qt_v3(viewinv, view_src_x);
+       mul_qt_v3(viewinv, view_src_y);
+
+       if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) {
+               return;
+       }
+       invert_qt_normalized(viewinv);
+       mul_qt_v3(viewinv, view_dst_x);
+       mul_qt_v3(viewinv, view_dst_y);
+
+       /* check source and dest have a matching axis */
+       for (i = 0; i < 3; i++) {
+               if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) &&
+                   ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps)))
+               {
+                       rv3d_dst->ofs[i] = rv3d_src->ofs[i];
+               }
+       }
+}
+
+/* sync center/zoom view of region to others, for view transforms */
+void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
+{
+       ARegion *artest;
+       RegionView3D *rv3d = ar->regiondata;
+       short clip = 0;
+
+       for (artest = sa->regionbase.first; artest; artest = artest->next) {
+               if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
+                       RegionView3D *rv3dtest = artest->regiondata;
+
+                       if (rv3dtest->viewlock & RV3D_LOCKED) {
+                               rv3dtest->dist = rv3d->dist;
+                               view3d_boxview_sync_axis(rv3dtest, rv3d);
+                               clip |= rv3dtest->viewlock & RV3D_BOXCLIP;
+
+                               ED_region_tag_redraw(artest);
+                       }
+               }
+       }
+
+       if (clip) {
+               view3d_boxview_clip(sa);
+       }
+}
+
+/* for home, center etc */
+void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
+{
+       ARegion *artest;
+       RegionView3D *rv3d = ar->regiondata;
+       bool clip = false;
+
+       for (artest = sa->regionbase.first; artest; artest = artest->next) {
+               if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
+                       RegionView3D *rv3dtest = artest->regiondata;
+
+                       if (rv3dtest->viewlock) {
+                               rv3dtest->dist = rv3d->dist;
+                               copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
+                               ED_region_tag_redraw(artest);
+
+                               clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0);
+                       }
+               }
+       }
+
+       if (clip) {
+               view3d_boxview_clip(sa);
+       }
+}
+
+/* 'clip' is used to know if our clip setting has changed */
+void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
+{
+       ARegion *ar_sync = NULL;
+       RegionView3D *rv3d = ar->regiondata;
+       short viewlock;
+       /* this function copies flags from the first of the 3 other quadview
+        * regions to the 2 other, so it assumes this is the region whose
+        * properties are always being edited, weak */
+       viewlock = rv3d->viewlock;
+
+       if ((viewlock & RV3D_LOCKED) == 0) {
+               do_clip = (viewlock & RV3D_BOXCLIP) != 0;
+               viewlock = 0;
+       }
+       else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) {
+               do_clip = true;
+               viewlock &= ~RV3D_BOXCLIP;
+       }
+
+       for (; ar; ar = ar->prev) {
+               if (ar->alignment == RGN_ALIGN_QSPLIT) {
+                       rv3d = ar->regiondata;
+                       rv3d->viewlock = viewlock;
+
+                       if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) {
+                               rv3d->rflag &= ~RV3D_BOXCLIP;
+                       }
+
+                       /* use ar_sync so we sync with one of the aligned views below
+                        * else the view jumps on changing view settings like 'clip'
+                        * since it copies from the perspective view */
+                       ar_sync = ar;
+               }
+       }
+
+       if (rv3d->viewlock & RV3D_BOXVIEW) {
+               view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last);
+       }
+
+       /* ensure locked regions have an axis, locked user views don't make much sense */
+       if (viewlock & RV3D_LOCKED) {
+               int index_qsplit = 0;
+               for (ar = sa->regionbase.first; ar; ar = ar->next) {
+                       if (ar->alignment == RGN_ALIGN_QSPLIT) {
+                               rv3d = ar->regiondata;
+                               if (rv3d->viewlock) {
+                                       if (!RV3D_VIEW_IS_AXIS(rv3d->view)) {
+                                               rv3d->view = ED_view3d_lock_view_from_index(index_qsplit);
+                                               rv3d->persp = RV3D_ORTHO;
+                                               ED_view3d_lock(rv3d);
+                                       }
+                               }
+                               index_qsplit++;
+                       }
+               }
+       }
+
+       ED_area_tag_redraw(sa);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Auto-Depth Utilities
+ * \{ */
+
+static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin)
+{
+       ViewDepths depth_temp = {0};
+       rcti rect;
+       float depth_close;
+
+       if (margin == 0) {
+               /* Get Z Depths, needed for perspective, nice for ortho */
+               rect.xmin = mval[0];
+               rect.ymin = mval[1];
+               rect.xmax = mval[0] + 1;
+               rect.ymax = mval[1] + 1;
+       }
+       else {
+               BLI_rcti_init_pt_radius(&rect, mval, margin);
+       }
+
+       view3d_update_depths_rect(ar, &depth_temp, &rect);
+       depth_close = view3d_depth_near(&depth_temp);
+       MEM_SAFE_FREE(depth_temp.depths);
+       return depth_close;
+}
+
+/**
+ * Get the world-space 3d location from a screen-space 2d point.
+ *
+ * \param mval: Input screen-space pixel location.
+ * \param mouse_worldloc: Output world-space location.
+ * \param fallback_depth_pt: Use this points depth when no depth can be found.
+ */
+bool ED_view3d_autodist(
+        Scene *scene, ARegion *ar, View3D *v3d,
+        const int mval[2], float mouse_worldloc[3],
+        const bool alphaoverride, const float fallback_depth_pt[3])
+{
+       bglMats mats; /* ZBuffer depth vars */
+       float depth_close;
+       double cent[2],  p[3];
+       int margin_arr[] = {0, 2, 4};
+       int i;
+       bool depth_ok = false;
+
+       /* Get Z Depths, needed for perspective, nice for ortho */
+       ED_view3d_draw_depth(scene, ar, v3d, alphaoverride);
+
+       /* call after in case settings have been modified since last drawing, see: T47089 */
+       bgl_get_mats(&mats);
+
+       /* Attempt with low margin's first */
+       i = 0;
+       do {
+               depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize);
+               depth_ok = (depth_close != FLT_MAX);
+       } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
+
+       if (depth_ok) {
+               cent[0] = (double)mval[0] + 0.5;
+               cent[1] = (double)mval[1] + 0.5;
+
+               if (gluUnProject(cent[0], cent[1], depth_close,
+                                mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
+               {
+                       mouse_worldloc[0] = (float)p[0];
+                       mouse_worldloc[1] = (float)p[1];
+                       mouse_worldloc[2] = (float)p[2];
+                       return true;
+               }
+       }
+
+       if (fallback_depth_pt) {
+               ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc);
+               return true;
+       }
+       else {
+               return false;
+       }
+}
+
+void ED_view3d_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode)
+{
+       /* Get Z Depths, needed for perspective, nice for ortho */
+       switch (mode) {
+               case 0:
+                       ED_view3d_draw_depth(scene, ar, v3d, true);
+                       break;
+               case 1:
+                       ED_view3d_draw_depth_gpencil(scene, ar, v3d);
+                       break;
+       }
+}
+
+/* no 4x4 sampling, run #ED_view3d_autodist_init first */
+bool ED_view3d_autodist_simple(
+        ARegion *ar, const int mval[2], float mouse_worldloc[3],
+        int margin, float *force_depth)
+{
+       bglMats mats; /* ZBuffer depth vars, could cache? */
+       float depth;
+       double cent[2],  p[3];
+
+       /* Get Z Depths, needed for perspective, nice for ortho */
+       if (force_depth)
+               depth = *force_depth;
+       else
+               depth = view_autodist_depth_margin(ar, mval, margin);
+
+       if (depth == FLT_MAX)
+               return false;
+
+       cent[0] = (double)mval[0] + 0.5;
+       cent[1] = (double)mval[1] + 0.5;
+
+       bgl_get_mats(&mats);
+
+       if (!gluUnProject(cent[0], cent[1], depth,
+                         mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
+       {
+               return false;
+       }
+
+       mouse_worldloc[0] = (float)p[0];
+       mouse_worldloc[1] = (float)p[1];
+       mouse_worldloc[2] = (float)p[2];
+       return true;
+}
+
+bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth)
+{
+       *depth = view_autodist_depth_margin(ar, mval, margin);
+
+       return (*depth != FLT_MAX);
+}
+
+static bool depth_segment_cb(int x, int y, void *userData)
+{
+       struct { ARegion *ar; int margin; float depth; } *data = userData;
+       int mval[2];
+       float depth;
+
+       mval[0] = x;
+       mval[1] = y;
+
+       depth = view_autodist_depth_margin(data->ar, mval, data->margin);
+
+       if (depth != FLT_MAX) {
+               data->depth = depth;
+               return 0;
+       }
+       else {
+               return 1;
+       }
+}
+
+bool ED_view3d_autodist_depth_seg(
+        ARegion *ar, const int mval_sta[2], const int mval_end[2],
+        int margin, float *depth)
+{
+       struct { ARegion *ar; int margin; float depth; } data = {NULL};
+       int p1[2];
+       int p2[2];
+
+       data.ar = ar;
+       data.margin = margin;
+       data.depth = FLT_MAX;
+
+       copy_v2_v2_int(p1, mval_sta);
+       copy_v2_v2_int(p2, mval_end);
+
+       BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data);
+
+       *depth = data.depth;
+
+       return (*depth != FLT_MAX);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Radius/Distance Utilities
+ *
+ * Use to calculate a distance to a point based on it's radius.
+ * \{ */
+
+float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
+{
+       return radius * (1.0f / tanf(angle / 2.0f));
+}
+
+float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
+{
+       return radius / (DEFAULT_SENSOR_WIDTH / lens);
+}
+
+/**
+ * Return a new RegionView3D.dist value to fit the \a radius.
+ *
+ * \note Depth isn't taken into account, this will fit a flat plane exactly,
+ * but points towards the view (with a perspective projection),
+ * may be within the radius but outside the view. eg:
+ *
+ * <pre>
+ *           +
+ * pt --> + /^ radius
+ *         / |
+ *        /  |
+ * view  +   +
+ *        \  |
+ *         \ |
+ *          \|
+ *           +
+ * </pre>
+ *
+ * \param ar  Can be NULL if \a use_aspect is false.
+ * \param persp  Allow the caller to tell what kind of perspective to use (ortho/view/camera)
+ * \param use_aspect  Increase the distance to account for non 1:1 view aspect.
+ * \param radius  The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN).
+ */
+float ED_view3d_radius_to_dist(
+        const View3D *v3d, const ARegion *ar,
+        const char persp, const bool use_aspect,
+        const float radius)
+{
+       float dist;
+
+       BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB));
+       BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
+
+       if (persp == RV3D_ORTHO) {
+               dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
+       }
+       else {
+               float lens, sensor_size, zoom;
+               float angle;
+
+               if (persp == RV3D_CAMOB) {
+                       CameraParams params;
+                       BKE_camera_params_init(&params);
+                       params.clipsta = v3d->near;
+                       params.clipend = v3d->far;
+                       BKE_camera_params_from_object(&params, v3d->camera);
+
+                       lens = params.lens;
+                       sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
+
+                       /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */
+                       zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB;
+               }
+               else {
+                       lens = v3d->lens;
+                       sensor_size = DEFAULT_SENSOR_WIDTH;
+                       zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
+               }
+
+               angle = focallength_to_fov(lens, sensor_size);
+
+               /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */
+               angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
+
+               dist = ED_view3d_radius_to_dist_persp(angle, radius);
+       }
+
+       if (use_aspect) {
+               const RegionView3D *rv3d = ar->regiondata;
+
+               float winx, winy;
+
+               if (persp == RV3D_CAMOB) {
+                       /* camera frame x/y in pixels */
+                       winx = ar->winx / rv3d->viewcamtexcofac[0];
+                       winy = ar->winy / rv3d->viewcamtexcofac[1];
+               }
+               else {
+                       winx = ar->winx;
+                       winy = ar->winy;
+               }
+
+               if (winx && winy) {
+                       float aspect = winx / winy;
+                       if (aspect < 1.0f) {
+                               aspect = 1.0f / aspect;
+                       }
+                       dist *= aspect;
+               }
+       }
+
+       return dist;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Distance Utilities
+ * \{ */
+
+/* problem - ofs[3] can be on same location as camera itself.
+ * Blender needs proper dist value for zoom.
+ * use fallback_dist to override small values
+ */
+float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist)
+{
+       float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+       float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+       float dist;
+
+       mul_m4_v4(mat, pos);
+       add_v3_v3(pos, ofs);
+       mul_m4_v4(mat, dir);
+       normalize_v3(dir);
+
+       dist = dot_v3v3(pos, dir);
+
+       if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) {
+               dist = fallback_dist;
+       }
+
+       return dist;
+}
+
+/**
+ * Set the dist without moving the view (compensate with #RegionView3D.ofs)
+ *
+ * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first.
+ */
+void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
+{
+       float viewinv[4];
+       float tvec[3];
+
+       BLI_assert(dist >= 0.0f);
+
+       copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist);
+       /* rv3d->viewinv isn't always valid */
+#if 0
+       mul_mat3_m4_v3(rv3d->viewinv, tvec);
+#else
+       invert_qt_qt_normalized(viewinv, rv3d->viewquat);
+       mul_qt_v3(viewinv, tvec);
+#endif
+       sub_v3_v3(rv3d->ofs, tvec);
+
+       rv3d->dist = dist;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Axis Utilities
+ * \{ */
+static float view3d_quat_axis[6][4] = {
+       {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f},    /* RV3D_VIEW_FRONT */
+       {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2},   /* RV3D_VIEW_BACK */
+       {0.5f, -0.5f, 0.5f, 0.5f},              /* RV3D_VIEW_LEFT */
+       {0.5f, -0.5f, -0.5f, -0.5f},            /* RV3D_VIEW_RIGHT */
+       {1.0f, 0.0f, 0.0f, 0.0f},               /* RV3D_VIEW_TOP */
+       {0.0f, -1.0f, 0.0f, 0.0f},              /* RV3D_VIEW_BOTTOM */
+};
+
+
+bool ED_view3d_quat_from_axis_view(const char view, float quat[4])
+{
+       if (RV3D_VIEW_IS_AXIS(view)) {
+               copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]);
+               return true;
+       }
+       else {
+               return false;
+       }
+}
+
+char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon)
+{
+       /* quat values are all unit length */
+
+       char view;
+
+       for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
+               if (fabsf(angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT])) < epsilon) {
+                       return view;
+               }
+       }
+
+       return RV3D_VIEW_USER;
+}
+
+char ED_view3d_lock_view_from_index(int index)
+{
+       switch (index) {
+               case 0:  return RV3D_VIEW_FRONT;
+               case 1:  return RV3D_VIEW_TOP;
+               case 2:  return RV3D_VIEW_RIGHT;
+               default: return RV3D_VIEW_USER;
+       }
+
+}
+
+char ED_view3d_axis_view_opposite(char view)
+{
+       switch (view) {
+               case RV3D_VIEW_FRONT:   return RV3D_VIEW_BACK;
+               case RV3D_VIEW_BACK:    return RV3D_VIEW_FRONT;
+               case RV3D_VIEW_LEFT:    return RV3D_VIEW_RIGHT;
+               case RV3D_VIEW_RIGHT:   return RV3D_VIEW_LEFT;
+               case RV3D_VIEW_TOP:     return RV3D_VIEW_BOTTOM;
+               case RV3D_VIEW_BOTTOM:  return RV3D_VIEW_TOP;
+       }
+
+       return RV3D_VIEW_USER;
+}
+
+
+bool ED_view3d_lock(RegionView3D *rv3d)
+{
+       return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Transform Utilities
+ * \{ */
+
+/**
+ * Set the view transformation from a 4x4 matrix.
+ *
+ * \param mat The view 4x4 transformation matrix to assign.
+ * \param ofs The view offset, normally from RegionView3D.ofs.
+ * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
+ * \param dist The view distance from ofs, normally from RegionView3D.dist.
+ */
+void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist)
+{
+       float nmat[3][3];
+
+       /* dist depends on offset */
+       BLI_assert(dist == NULL || ofs != NULL);
+
+       copy_m3_m4(nmat, mat);
+       normalize_m3(nmat);
+
+       /* Offset */
+       if (ofs)
+               negate_v3_v3(ofs, mat[3]);
+
+       /* Quat */
+       if (quat) {
+               mat3_normalized_to_quat(quat, nmat);
+               invert_qt_normalized(quat);
+       }
+
+       if (ofs && dist) {
+               madd_v3_v3fl(ofs, nmat[2], *dist);
+       }
+}
+
+/**
+ * Calculate the view transformation matrix from RegionView3D input.
+ * The resulting matrix is equivalent to RegionView3D.viewinv
+ * \param mat The view 4x4 transformation matrix to calculate.
+ * \param ofs The view offset, normally from RegionView3D.ofs.
+ * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
+ * \param dist The view distance from ofs, normally from RegionView3D.dist.
+ */
+void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
+{
+       float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
+       float dvec[3] = {0.0f, 0.0f, dist};
+
+       quat_to_mat4(mat, iviewquat);
+       mul_mat3_m4_v3(mat, dvec);
+       sub_v3_v3v3(mat[3], dvec, ofs);
+}
+
+/**
+ * Set the RegionView3D members from an objects transformation and optionally lens.
+ * \param ob The object to set the view to.
+ * \param ofs The view offset to be set, normally from RegionView3D.ofs.
+ * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat.
+ * \param dist The view distance from ofs to be set, normally from RegionView3D.dist.
+ * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens.
+ */
+void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
+{
+       ED_view3d_from_m4(ob->obmat, ofs, quat, dist);
+
+       if (lens) {
+               CameraParams params;
+
+               BKE_camera_params_init(&params);
+               BKE_camera_params_from_object(&params, ob);
+               *lens = params.lens;
+       }
+}
+
+/**
+ * Set the object transformation from RegionView3D members.
+ * \param ob The object which has the transformation assigned.
+ * \param ofs The view offset, normally from RegionView3D.ofs.
+ * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
+ * \param dist The view distance from ofs, normally from RegionView3D.dist.
+ */
+void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist)
+{
+       float mat[4][4];
+       ED_view3d_to_m4(mat, ofs, quat, dist);
+       BKE_object_apply_mat4(ob, mat, true, true);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Depth Buffer Utilities
+ * \{ */
+
+float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2])
+{
+       ViewDepths *vd = vc->rv3d->depths;
+
+       int x = mval[0];
+       int y = mval[1];
+
+       if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) {
+               return vd->depths[y * vd->w + x];
+       }
+       else {
+               BLI_assert(1.0 <= vd->depth_range[1]);
+               return 1.0f;
+       }
+}
+
+bool ED_view3d_depth_read_cached_normal(
+        const ViewContext *vc, const bglMats *mats, const int mval[2],
+        float r_normal[3])
+{
+       /* Note: we could support passing in a radius.
+        * For now just read 9 pixels. */
+
+       /* pixels surrounding */
+       bool  depths_valid[9] = {false};
+       float coords[9][3] = {{0}};
+
+       ARegion *ar = vc->ar;
+       const ViewDepths *depths = vc->rv3d->depths;
+
+       for (int x = 0, i = 0; x < 2; x++) {
+               for (int y = 0; y < 2; y++) {
+                       const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
+
+                       const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs);
+                       if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
+                               if (ED_view3d_depth_unproject(ar, mats, mval_ofs, depth, coords[i])) {
+                                       depths_valid[i] = true;
+                               }
+                       }
+                       i++;
+               }
+       }
+
+       const int edges[2][6][2] = {
+           /* x edges */
+           {{0, 1}, {1, 2},
+            {3, 4}, {4, 5},
+            {6, 7}, {7, 8}},
+           /* y edges */
+           {{0, 3}, {3, 6},
+            {1, 4}, {4, 7},
+            {2, 5}, {5, 8}},
+       };
+
+       float cross[2][3] = {{0.0f}};
+
+       for (int i = 0; i < 6; i++) {
+               for (int axis = 0; axis < 2; axis++) {
+                       if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
+                               float delta[3];
+                               sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
+                               add_v3_v3(cross[axis], delta);
+                       }
+               }
+       }
+
+       cross_v3_v3v3(r_normal, cross[0], cross[1]);
+
+       if (normalize_v3(r_normal) != 0.0f) {
+               return true;
+       }
+       else {
+               return false;
+       }
+}
+
+bool ED_view3d_depth_unproject(
+        const ARegion *ar, const bglMats *mats,
+        const int mval[2], const double depth,
+        float r_location_world[3])
+{
+       double p[3];
+       if (gluUnProject(
+               (double)ar->winrct.xmin + mval[0] + 0.5,
+               (double)ar->winrct.ymin + mval[1] + 0.5,
+               depth, mats->modelview, mats->projection, (const GLint *)mats->viewport,
+               &p[0], &p[1], &p[2]))
+       {
+               copy_v3fl_v3db(r_location_world, p);
+               return true;
+       }
+       return false;
+}
+
+void ED_view3d_depth_tag_update(RegionView3D *rv3d)
+{
+       if (rv3d->depths)
+               rv3d->depths->damaged = true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Background Image Utilities
+ * \{ */
+
+BGpic *ED_view3d_background_image_new(View3D *v3d)
+{
+       BGpic *bgpic = MEM_callocN(sizeof(BGpic), "Background Image");
+
+       bgpic->rotation = 0.0f;
+       bgpic->size = 5.0f;
+       bgpic->blend = 0.5f;
+       bgpic->iuser.fie_ima = 2;
+       bgpic->iuser.ok = 1;
+       bgpic->view = 0; /* 0 for all */
+       bgpic->flag |= V3D_BGPIC_EXPANDED;
+
+       BLI_addtail(&v3d->bgpicbase, bgpic);
+
+       return bgpic;
+}
+
+void ED_view3d_background_image_remove(View3D *v3d, BGpic *bgpic)
+{
+       BLI_remlink(&v3d->bgpicbase, bgpic);
+
+       MEM_freeN(bgpic);
+}
+
+void ED_view3d_background_image_clear(View3D *v3d)
+{
+       BGpic *bgpic = v3d->bgpicbase.first;
+
+       while (bgpic) {
+               BGpic *next_bgpic = bgpic->next;
+
+               ED_view3d_background_image_remove(v3d, bgpic);
+
+               bgpic = next_bgpic;
+       }
+}
+
+/** \} */
index bb8279b9877d69fc1e8b155d42bd205e4a3b8d2a..7dfc465286df89b6e72c12871b7804c7221c7764 100644 (file)
@@ -28,7 +28,6 @@
  *  \ingroup spview3d
  */
 
-
 #include "DNA_camera_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
@@ -39,7 +38,6 @@
 #include "BLI_rect.h"
 #include "BLI_utildefines.h"
 
-#include "BKE_anim.h"
 #include "BKE_action.h"
 #include "BKE_camera.h"
 #include "BKE_context.h"
 #include "BKE_main.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
-#include "BKE_screen.h"
 
 #include "BIF_gl.h"
-#include "BIF_glutil.h"
 
 #include "UI_resources.h"
 
@@ -62,8 +58,6 @@
 #include "WM_types.h"
 
 #include "ED_screen.h"
-#include "ED_armature.h"
-
 
 #ifdef WITH_GAMEENGINE
 #  include "BLI_listbase.h"
@@ -74,7 +68,6 @@
 #  include "BL_System.h"
 #endif
 
-
 #include "view3d_intern.h"  /* own include */
 
 /* use this call when executing an operator,
@@ -105,23 +98,6 @@ void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
        }
 }
 
-float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d)
-{
-       if (v3d && v3d->localvd) return v3d->cursor;
-       else return scene->cursor;
-}
-
-Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
-{
-       /* establish the camera object, so we can default to view mapping if anything is wrong with it */
-       if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
-               return v3d->camera->data;
-       }
-       else {
-               return NULL;
-       }
-}
-
 /* ****************** smooth view operator ****************** */
 /* This operator is one of the 'timer refresh' ones like animation playback */
 
@@ -715,289 +691,6 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
 
 /* ********************************** */
 
-void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip)
-{
-       int val;
-
-       for (val = 0; val < 4; val++) {
-               normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
-               if (UNLIKELY(is_flip)) {
-                       negate_v3(clip[val]);
-               }
-
-               clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]);
-       }
-}
-
-void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, const rcti *rect)
-{
-       float modelview[4][4];
-       double xs, ys, p[3];
-       int val, flip_sign, a;
-
-       /* near zero floating point values can give issues with gluUnProject
-        * in side view on some implementations */
-       if (fabs(mats->modelview[0]) < 1e-6) mats->modelview[0] = 0.0;
-       if (fabs(mats->modelview[5]) < 1e-6) mats->modelview[5] = 0.0;
-
-       /* Set up viewport so that gluUnProject will give correct values */
-       mats->viewport[0] = 0;
-       mats->viewport[1] = 0;
-
-       /* four clipping planes and bounding volume */
-       /* first do the bounding volume */
-       for (val = 0; val < 4; val++) {
-               xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax;
-               ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax;
-
-               gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
-               copy_v3fl_v3db(bb->vec[val], p);
-
-               gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
-               copy_v3fl_v3db(bb->vec[4 + val], p);
-       }
-
-       /* verify if we have negative scale. doing the transform before cross
-        * product flips the sign of the vector compared to doing cross product
-        * before transform then, so we correct for that. */
-       for (a = 0; a < 16; a++)
-               ((float *)modelview)[a] = mats->modelview[a];
-       flip_sign = is_negative_m4(modelview);
-
-       ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
-}
-
-static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
-{
-       int a, flag = -1, fl;
-
-       for (a = 0; a < 8; a++) {
-               float vec[4], min, max;
-               copy_v3_v3(vec, bb->vec[a]);
-               vec[3] = 1.0;
-               mul_m4_v4(persmatob, vec);
-               max = vec[3];
-               min = -vec[3];
-
-               fl = 0;
-               if (vec[0] < min) fl += 1;
-               if (vec[0] > max) fl += 2;
-               if (vec[1] < min) fl += 4;
-               if (vec[1] > max) fl += 8;
-               if (vec[2] < min) fl += 16;
-               if (vec[2] > max) fl += 32;
-
-               flag &= fl;
-               if (flag == 0) return true;
-       }
-
-       return false;
-}
-
-bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
-{
-       /* return 1: draw */
-
-       float persmatob[4][4];
-
-       if (bb == NULL) return true;
-       if (bb->flag & BOUNDBOX_DISABLED) return true;
-
-       mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat);
-
-       return view3d_boundbox_clip_m4(bb, persmatob);
-}
-
-bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
-{
-       if (bb == NULL) return true;
-       if (bb->flag & BOUNDBOX_DISABLED) return true;
-
-       return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
-}
-
-/* -------------------------------------------------------------------- */
-
-/** \name Depth Utilities
- * \{ */
-
-float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2])
-{
-       ViewDepths *vd = vc->rv3d->depths;
-               
-       int x = mval[0];
-       int y = mval[1];
-
-       if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) {
-               return vd->depths[y * vd->w + x];
-       }
-       else {
-               BLI_assert(1.0 <= vd->depth_range[1]);
-               return 1.0f;
-       }
-}
-
-bool ED_view3d_depth_read_cached_normal(
-        const ViewContext *vc, const bglMats *mats, const int mval[2],
-        float r_normal[3])
-{
-       /* Note: we could support passing in a radius.
-        * For now just read 9 pixels. */
-
-       /* pixels surrounding */
-       bool  depths_valid[9] = {false};
-       float coords[9][3] = {{0}};
-
-       ARegion *ar = vc->ar;
-       const ViewDepths *depths = vc->rv3d->depths;
-
-       for (int x = 0, i = 0; x < 2; x++) {
-               for (int y = 0; y < 2; y++) {
-                       const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
-
-                       const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs);
-                       if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
-                               if (ED_view3d_depth_unproject(ar, mats, mval_ofs, depth, coords[i])) {
-                                       depths_valid[i] = true;
-                               }
-                       }
-                       i++;
-               }
-       }
-
-       const int edges[2][6][2] = {
-           /* x edges */
-           {{0, 1}, {1, 2},
-            {3, 4}, {4, 5},
-            {6, 7}, {7, 8}},
-           /* y edges */
-           {{0, 3}, {3, 6},
-            {1, 4}, {4, 7},
-            {2, 5}, {5, 8}},
-       };
-
-       float cross[2][3] = {{0.0f}};
-
-       for (int i = 0; i < 6; i++) {
-               for (int axis = 0; axis < 2; axis++) {
-                       if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
-                               float delta[3];
-                               sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
-                               add_v3_v3(cross[axis], delta);
-                       }
-               }
-       }
-
-       cross_v3_v3v3(r_normal, cross[0], cross[1]);
-
-       if (normalize_v3(r_normal) != 0.0f) {
-               return true;
-       }
-       else {
-               return false;
-       }
-}
-
-bool ED_view3d_depth_unproject(
-        const ARegion *ar, const bglMats *mats,
-        const int mval[2], const double depth,
-        float r_location_world[3])
-{
-       double p[3];
-       if (gluUnProject(
-               (double)ar->winrct.xmin + mval[0] + 0.5,
-               (double)ar->winrct.ymin + mval[1] + 0.5,
-               depth, mats->modelview, mats->projection, (const GLint *)mats->viewport,
-               &p[0], &p[1], &p[2]))
-       {
-               copy_v3fl_v3db(r_location_world, p);
-               return true;
-       }
-       return false;
-}
-
-/** \} */
-
-void ED_view3d_depth_tag_update(RegionView3D *rv3d)
-{
-       if (rv3d->depths)
-               rv3d->depths->damaged = true;
-}
-
-void ED_view3d_dist_range_get(
-        const View3D *v3d,
-        float r_dist_range[2])
-{
-       r_dist_range[0] = v3d->grid * 0.001f;
-       r_dist_range[1] = v3d->far * 10.0f;
-}
-
-/* copies logic of get_view3d_viewplane(), keep in sync */
-bool ED_view3d_clip_range_get(
-        const View3D *v3d, const RegionView3D *rv3d,
-        float *r_clipsta, float *r_clipend,
-        const bool use_ortho_factor)
-{
-       CameraParams params;
-
-       BKE_camera_params_init(&params);
-       BKE_camera_params_from_view3d(&params, v3d, rv3d);
-
-       if (use_ortho_factor && params.is_ortho) {
-               const float fac = 2.0f / (params.clipend - params.clipsta);
-               params.clipsta *= fac;
-               params.clipend *= fac;
-       }
-
-       if (r_clipsta) *r_clipsta = params.clipsta;
-       if (r_clipend) *r_clipend = params.clipend;
-
-       return params.is_ortho;
-}
-
-bool ED_view3d_viewplane_get(
-        const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
-        rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
-{
-       CameraParams params;
-
-       BKE_camera_params_init(&params);
-       BKE_camera_params_from_view3d(&params, v3d, rv3d);
-       BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
-
-       if (r_viewplane) *r_viewplane = params.viewplane;
-       if (r_clipsta) *r_clipsta = params.clipsta;
-       if (r_clipend) *r_clipend = params.clipend;
-       if (r_pixsize) *r_pixsize = params.viewdx;
-       
-       return params.is_ortho;
-}
-
-/**
- * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727]
- */
-void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
-{
-       float viewdist;
-
-       if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
-               return;
-       }
-
-       viewdist = rv3d->dist;
-
-       /* special exception for ortho camera (viewdist isnt used for perspective cameras) */
-       if (dist != 0.0f) {
-               if (rv3d->persp == RV3D_CAMOB) {
-                       if (rv3d->is_persp == false) {
-                               viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1]));
-                       }
-               }
-       }
-
-       bglPolygonOffset(viewdist, dist);
-}
-
 /**
  * \param rect optional for picking (can be NULL).
  */
@@ -1050,73 +743,6 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
        mat4_normalized_to_quat(rv3d->viewquat, rv3d->viewmat);
 }
 
-static float view3d_quat_axis[6][4] = {
-       {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f},    /* RV3D_VIEW_FRONT */
-       {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2},   /* RV3D_VIEW_BACK */
-       {0.5f, -0.5f, 0.5f, 0.5f},              /* RV3D_VIEW_LEFT */
-       {0.5f, -0.5f, -0.5f, -0.5f},            /* RV3D_VIEW_RIGHT */
-       {1.0f, 0.0f, 0.0f, 0.0f},               /* RV3D_VIEW_TOP */
-       {0.0f, -1.0f, 0.0f, 0.0f},              /* RV3D_VIEW_BOTTOM */
-};
-
-
-bool ED_view3d_quat_from_axis_view(const char view, float quat[4])
-{
-       if (RV3D_VIEW_IS_AXIS(view)) {
-               copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]);
-               return true;
-       }
-       else {
-               return false;
-       }
-}
-
-char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon)
-{
-       /* quat values are all unit length */
-
-       char view;
-
-       for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
-               if (fabsf(angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT])) < epsilon) {
-                       return view;
-               }
-       }
-
-       return RV3D_VIEW_USER;
-}
-
-char ED_view3d_lock_view_from_index(int index)
-{
-       switch (index) {
-               case 0:  return RV3D_VIEW_FRONT;
-               case 1:  return RV3D_VIEW_TOP;
-               case 2:  return RV3D_VIEW_RIGHT;
-               default: return RV3D_VIEW_USER;
-       }
-
-}
-
-char ED_view3d_axis_view_opposite(char view)
-{
-       switch (view) {
-               case RV3D_VIEW_FRONT:   return RV3D_VIEW_BACK;
-               case RV3D_VIEW_BACK:    return RV3D_VIEW_FRONT;
-               case RV3D_VIEW_LEFT:    return RV3D_VIEW_RIGHT;
-               case RV3D_VIEW_RIGHT:   return RV3D_VIEW_LEFT;
-               case RV3D_VIEW_TOP:     return RV3D_VIEW_BOTTOM;
-               case RV3D_VIEW_BOTTOM:  return RV3D_VIEW_TOP;
-       }
-
-       return RV3D_VIEW_USER;
-}
-
-
-bool ED_view3d_lock(RegionView3D *rv3d)
-{
-       return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat);
-}
-
 /**
  * Sets #RegionView3D.viewmat
  *
@@ -1784,33 +1410,6 @@ static int game_engine_poll(bContext *C)
        return 1;
 }
 
-bool ED_view3d_context_activate(bContext *C)
-{
-       bScreen *sc = CTX_wm_screen(C);
-       ScrArea *sa = CTX_wm_area(C);
-       ARegion *ar;
-
-       /* sa can be NULL when called from python */
-       if (sa == NULL || sa->spacetype != SPACE_VIEW3D) {
-               sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0);
-       }
-
-       if (sa == NULL) {
-               return false;
-       }
-       
-       ar = BKE_area_find_region_active_win(sa);
-       if (ar == NULL) {
-               return false;
-       }
-       
-       /* bad context switch .. */
-       CTX_wm_area_set(C, sa);
-       CTX_wm_region_set(C, ar);
-
-       return true;
-}
-
 static int game_engine_exec(bContext *C, wmOperator *op)
 {
 #ifdef WITH_GAMEENGINE
@@ -1912,157 +1511,3 @@ void VIEW3D_OT_game_start(wmOperatorType *ot)
        
        ot->poll = game_engine_poll;
 }
-
-/* ************************************** */
-
-float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
-{
-       return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
-}
-
-float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
-{
-       return radius * (1.0f / tanf(angle / 2.0f));
-}
-
-float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
-{
-       return radius / (DEFAULT_SENSOR_WIDTH / lens);
-}
-
-/**
- * Return a new RegionView3D.dist value to fit the \a radius.
- *
- * \note Depth isn't taken into account, this will fit a flat plane exactly,
- * but points towards the view (with a perspective projection),
- * may be within the radius but outside the view. eg:
- *
- * <pre>
- *           +
- * pt --> + /^ radius
- *         / |
- *        /  |
- * view  +   +
- *        \  |
- *         \ |
- *          \|
- *           +
- * </pre>
- *
- * \param ar  Can be NULL if \a use_aspect is false.
- * \param persp  Allow the caller to tell what kind of perspective to use (ortho/view/camera)
- * \param use_aspect  Increase the distance to account for non 1:1 view aspect.
- * \param radius  The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN).
- */
-float ED_view3d_radius_to_dist(
-        const View3D *v3d, const ARegion *ar,
-        const char persp, const bool use_aspect,
-        const float radius)
-{
-       float dist;
-
-       BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB));
-       BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
-
-       if (persp == RV3D_ORTHO) {
-               dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
-       }
-       else {
-               float lens, sensor_size, zoom;
-               float angle;
-
-               if (persp == RV3D_CAMOB) {
-                       CameraParams params;
-                       BKE_camera_params_init(&params);
-                       params.clipsta = v3d->near;
-                       params.clipend = v3d->far;
-                       BKE_camera_params_from_object(&params, v3d->camera);
-
-                       lens = params.lens;
-                       sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
-
-                       /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */
-                       zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB;
-               }
-               else {
-                       lens = v3d->lens;
-                       sensor_size = DEFAULT_SENSOR_WIDTH;
-                       zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
-               }
-
-               angle = focallength_to_fov(lens, sensor_size);
-
-               /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */
-               angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
-
-               dist = ED_view3d_radius_to_dist_persp(angle, radius);
-       }
-
-       if (use_aspect) {
-               const RegionView3D *rv3d = ar->regiondata;
-
-               float winx, winy;
-
-               if (persp == RV3D_CAMOB) {
-                       /* camera frame x/y in pixels */
-                       winx = ar->winx / rv3d->viewcamtexcofac[0];
-                       winy = ar->winy / rv3d->viewcamtexcofac[1];
-               }
-               else {
-                       winx = ar->winx;
-                       winy = ar->winy;
-               }
-
-               if (winx && winy) {
-                       float aspect = winx / winy;
-                       if (aspect < 1.0f) {
-                               aspect = 1.0f / aspect;
-                       }
-                       dist *= aspect;
-               }
-       }
-
-       return dist;
-}
-
-/* view matrix properties utilities */
-
-/* unused */
-#if 0
-void ED_view3d_operator_properties_viewmat(wmOperatorType *ot)
-{
-       PropertyRNA *prop;
-
-       prop = RNA_def_int(ot->srna, "region_width", 0, 0, INT_MAX, "Region Width", "", 0, INT_MAX);
-       RNA_def_property_flag(prop, PROP_HIDDEN);
-
-       prop = RNA_def_int(ot->srna, "region_height", 0, 0, INT_MAX, "Region height", "", 0, INT_MAX);
-       RNA_def_property_flag(prop, PROP_HIDDEN);
-
-       prop = RNA_def_float_matrix(ot->srna, "perspective_matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Perspective Matrix", 0.0f, 0.0f);
-       RNA_def_property_flag(prop, PROP_HIDDEN);
-}
-
-void ED_view3d_operator_properties_viewmat_set(bContext *C, wmOperator *op)
-{
-       ARegion *ar = CTX_wm_region(C);
-       RegionView3D *rv3d = ED_view3d_context_rv3d(C);
-
-       if (!RNA_struct_property_is_set(op->ptr, "region_width"))
-               RNA_int_set(op->ptr, "region_width", ar->winx);
-
-       if (!RNA_struct_property_is_set(op->ptr, "region_height"))
-               RNA_int_set(op->ptr, "region_height", ar->winy);
-
-       if (!RNA_struct_property_is_set(op->ptr, "perspective_matrix"))
-               RNA_float_set_array(op->ptr, "perspective_matrix", (float *)rv3d->persmat);
-}
-
-void ED_view3d_operator_properties_viewmat_get(wmOperator *op, int *winx, int *winy, float persmat[4][4])
-{
-       *winx = RNA_int_get(op->ptr, "region_width");
-       *winy = RNA_int_get(op->ptr, "region_height");
-
-       RNA_float_get_array(op->ptr, "perspective_matrix", (float *)persmat);
-}
-#endif