Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Thu, 20 Sep 2018 02:46:04 +0000 (12:46 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 20 Sep 2018 02:51:16 +0000 (12:51 +1000)
1  2 
source/blender/editors/curve/editcurve_paint.c
source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
source/blender/editors/include/ED_view3d.h
source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
source/blender/editors/space_view3d/view3d_project.c

index b249af1c8b6c716b45c2df1a6e74b87340249326,7472a0c89570f4e52015b40c5ad77b3aeca5e070..ad128b91c5afa642dfe88278e1389d4ea6bef9f7
  
  #include "BKE_context.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_fcurve.h"
  #include "BKE_main.h"
  #include "BKE_report.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "WM_api.h"
  #include "WM_types.h"
  
  #include "ED_curve.h"
  
  #include "BIF_gl.h"
 -#include "BIF_glutil.h"
 +
 +#include "GPU_batch.h"
 +#include "GPU_batch_presets.h"
 +#include "GPU_immediate.h"
 +#include "GPU_immediate_util.h"
 +#include "GPU_matrix.h"
 +#include "GPU_state.h"
  
  #include "curve_intern.h"
  
@@@ -96,8 -89,6 +96,8 @@@ struct StrokeElem 
  };
  
  struct CurveDrawData {
 +      Depsgraph *depsgraph;
 +
        short init_event_type;
        short curve_type;
  
        } prev;
  
        ViewContext vc;
 -      bglMats mats;
        enum {
                CURVE_DRAW_IDLE = 0,
                CURVE_DRAW_PAINTING = 1,
@@@ -202,12 -194,7 +202,7 @@@ static bool stroke_elem_project
        /* project to 'location_world' */
        if (cdd->project.use_plane) {
                /* get the view vector to 'location' */
-               float ray_origin[3], ray_direction[3];
-               ED_view3d_win_to_ray(ar, mval_fl, ray_origin, ray_direction);
-               float lambda;
-               if (isect_ray_plane_v3(ray_origin, ray_direction, cdd->project.plane, &lambda, true)) {
-                       madd_v3_v3v3fl(r_location_world, ray_origin, ray_direction, lambda);
+               if (ED_view3d_win_to_3d_on_plane(ar, cdd->project.plane, mval_fl, true, r_location_world)) {
                        if (r_normal_world) {
                                zero_v3(r_normal_world);
                        }
                {
                        const double depth = (double)ED_view3d_depth_read_cached(&cdd->vc, mval_i);
                        if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
 -                              if (ED_view3d_depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) {
 +                              if (ED_view3d_depth_unproject(ar, mval_i, depth, r_location_world)) {
                                        is_location_world_set = true;
                                        if (r_normal_world) {
                                                zero_v3(r_normal_world);
                                        if (surface_offset != 0.0f) {
                                                const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius;
                                                float normal[3];
 -                                              if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, mval_i, normal)) {
 +                                              if (ED_view3d_depth_read_cached_normal(&cdd->vc, mval_i, normal)) {
                                                        madd_v3_v3fl(r_location_world, normal, offset * surface_offset);
                                                        if (r_normal_world) {
                                                                copy_v3_v3(r_normal_world, normal);
@@@ -373,46 -360,43 +368,46 @@@ static void curve_draw_stroke_3d(const 
                return;
        }
  
 -      View3D *v3d = cdd->vc.v3d;
        Object *obedit = cdd->vc.obedit;
        Curve *cu = obedit->data;
  
 -      UI_ThemeColor(TH_WIRE);
 -
        if (cu->ext2 > 0.0f) {
 -              GLUquadricObj *qobj = gluNewQuadric();
 -
 -              gluQuadricDrawStyle(qobj, GLU_FILL);
 -
                BLI_mempool_iter iter;
                const struct StrokeElem *selem;
  
                const float  location_zero[3] = {0};
                const float *location_prev = location_zero;
  
 +              float color[3];
 +              UI_GetThemeColor3fv(TH_WIRE, color);
 +
 +              GPUBatch *sphere = GPU_batch_preset_sphere(0);
 +              GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
 +              GPU_batch_uniform_3fv(sphere, "color", color);
 +
                /* scale to edit-mode space */
 -              glPushMatrix();
 -              glMultMatrixf(obedit->obmat);
 +              GPU_matrix_push();
 +              GPU_matrix_mul(obedit->obmat);
  
                BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
                for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
 -                      glTranslatef(
 +                      GPU_matrix_translate_3f(
                                selem->location_local[0] - location_prev[0],
                                selem->location_local[1] - location_prev[1],
                                selem->location_local[2] - location_prev[2]);
                        location_prev = selem->location_local;
 +
                        const float radius = stroke_elem_radius(cdd, selem);
 -                      gluSphere(qobj, radius, 12, 8);
 +
 +                      GPU_matrix_push();
 +                      GPU_matrix_scale_1f(radius);
 +                      GPU_batch_draw(sphere);
 +                      GPU_matrix_pop();
  
                        location_prev = selem->location_local;
                }
  
 -              glPopMatrix();
 -
 -              gluDeleteQuadric(qobj);
 +              GPU_matrix_pop();
        }
  
        if (stroke_len > 1) {
                }
  
                {
 -                      glEnable(GL_BLEND);
 -                      glEnable(GL_LINE_SMOOTH);
 -
 -                      glEnableClientState(GL_VERTEX_ARRAY);
 -                      glVertexPointer(3, GL_FLOAT, 0, coord_array);
 -
 -                      cpack(0x0);
 -                      glLineWidth(3.0f);
 -                      glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
 -
 -                      if (v3d->zbuf)
 -                              glDisable(GL_DEPTH_TEST);
 +                      GPUVertFormat *format = immVertexFormat();
 +                      uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
 +                      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +
 +                      GPU_depth_test(false);
 +                      GPU_blend(true);
 +                      GPU_line_smooth(true);
 +                      GPU_line_width(3.0f);
 +
 +                      imm_cpack(0x0);
 +                      immBegin(GPU_PRIM_LINE_STRIP, stroke_len);
 +                      for (int i = 0; i < stroke_len; i++) {
 +                              immVertex3fv(pos, coord_array[i]);
 +                      }
 +                      immEnd();
  
 -                      cpack(0xffffffff);
 -                      glLineWidth(1.0f);
 -                      glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
 +                      GPU_line_width(1.0f);
  
 -                      if (v3d->zbuf)
 -                              glEnable(GL_DEPTH_TEST);
 +                      imm_cpack(0xffffffff);
 +                      immBegin(GPU_PRIM_LINE_STRIP, stroke_len);
 +                      for (int i = 0; i < stroke_len; i++) {
 +                              immVertex3fv(pos, coord_array[i]);
 +                      }
 +                      immEnd();
  
 -                      glDisableClientState(GL_VERTEX_ARRAY);
 +                      /* Reset defaults */
 +                      GPU_depth_test(true);
 +                      GPU_blend(false);
 +                      GPU_line_smooth(false);
  
 -                      glDisable(GL_BLEND);
 -                      glDisable(GL_LINE_SMOOTH);
 +                      immUnbindProgram();
                }
  
                MEM_freeN(coord_array);
@@@ -549,7 -526,7 +544,7 @@@ static void curve_draw_event_add_first(
                         CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW,
                         CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE))
                {
 -                      if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, event->mval, normal)) {
 +                      if (ED_view3d_depth_read_cached_normal(&cdd->vc, event->mval, normal)) {
                                if (cps->surface_plane == CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW) {
                                        float cross_a[3], cross_b[3];
                                        cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal);
@@@ -598,8 -575,6 +593,8 @@@ static bool curve_draw_init(bContext *C
  
        struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
  
 +      cdd->depsgraph = CTX_data_depsgraph(C);
 +
        if (is_invoke) {
                ED_view3d_viewcontext_init(C, &cdd->vc);
                if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
        }
        else {
                cdd->vc.bmain = CTX_data_main(C);
 +              cdd->vc.depsgraph = CTX_data_depsgraph(C);
                cdd->vc.scene = CTX_data_scene(C);
 +              cdd->vc.view_layer = CTX_data_view_layer(C);
                cdd->vc.obedit = CTX_data_edit_object(C);
        }
  
@@@ -705,7 -678,7 +700,7 @@@ static void curve_draw_exec_precalc(wmO
                        const struct StrokeElem *selem, *selem_first, *selem_last;
  
                        BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
 -                      selem_first = BLI_mempool_iterstep(&iter);
 +                      selem_first = selem_last = BLI_mempool_iterstep(&iter);
                        for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
                                selem_last = selem;
                        }
@@@ -782,7 -755,7 +777,7 @@@ static int curve_draw_exec(bContext *C
        struct CurveDrawData *cdd = op->customdata;
  
        const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
 -      Object *obedit = cdd->vc.scene->obedit;
 +      Object *obedit = cdd->vc.obedit;
        Curve *cu = obedit->data;
        ListBase *nurblist = object_editcurve_get(obedit);
  
        cu->actvert = nu->pntsu - 1;
  
        WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
 -      DAG_id_tag_update(obedit->data, 0);
 +      DEG_id_tag_update(obedit->data, 0);
  
        curve_draw_exit(op);
  
@@@ -1094,12 -1067,14 +1089,12 @@@ static int curve_draw_invoke(bContext *
                }
                else {
                        if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) &&
 -                          (v3d->drawtype > OB_WIRE))
 +                          (v3d->shading.type > OB_WIRE))
                        {
 -                              view3d_get_transformation(cdd->vc.ar, cdd->vc.rv3d, NULL, &cdd->mats);
 -
                                /* needed or else the draw matrix can be incorrect */
                                view3d_operator_needs_opengl(C);
  
 -                              ED_view3d_autodist_init(cdd->vc.bmain, cdd->vc.scene, cdd->vc.ar, cdd->vc.v3d, 0);
 +                              ED_view3d_autodist_init(cdd->vc.depsgraph, cdd->vc.ar, cdd->vc.v3d, 0);
  
                                if (cdd->vc.rv3d->depths) {
                                        cdd->vc.rv3d->depths->damaged = true;
  
                        /* use view plane (when set or as fallback when surface can't be found) */
                        if (cdd->project.use_depth == false) {
 -                              plane_co = ED_view3d_cursor3d_get(cdd->vc.scene, v3d);
 +                              plane_co = ED_view3d_cursor3d_get(cdd->vc.scene, v3d)->location;
                                plane_no = rv3d->viewinv[2];
                                cdd->project.use_plane = true;
                        }
index 6b1a76c47eefcb0599f06d2bfbd7574357c8f46d,0000000000000000000000000000000000000000..a6252cd55bdd07ac1743fe5be2949efd37934ddb
mode 100644,000000..100644
--- /dev/null
@@@ -1,513 -1,0 +1,513 @@@
-       if (!ED_view3d_win_to_3d_on_plane(ar, dial_plane, inter->init.mval, proj_mval_init_rel)) {
 +/*
 + * ***** 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) 2014 Blender Foundation.
 + * All rights reserved.
 + *
 + * Contributor(s): Blender Foundation
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file dial3d_gizmo.c
 + *  \ingroup edgizmolib
 + *
 + * \name Dial Gizmo
 + *
 + * 3D Gizmo
 + *
 + * \brief Circle shaped gizmo for circular interaction.
 + * Currently no own handling, use with operator only.
 + *
 + * - `matrix[0]` is derived from Y and Z.
 + * - `matrix[1]` is 'up' when DialGizmo.use_start_y_axis is set.
 + * - `matrix[2]` is the axis the dial rotates around (all dials).
 + */
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "BLI_math.h"
 +
 +#include "BKE_context.h"
 +
 +#include "BIF_gl.h"
 +#include "BIF_glutil.h"
 +
 +#include "GPU_immediate.h"
 +#include "GPU_immediate_util.h"
 +#include "GPU_matrix.h"
 +#include "GPU_select.h"
 +#include "GPU_state.h"
 +
 +#include "RNA_access.h"
 +#include "RNA_define.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "ED_screen.h"
 +#include "ED_view3d.h"
 +#include "ED_gizmo_library.h"
 +
 +/* own includes */
 +#include "../gizmo_geometry.h"
 +#include "../gizmo_library_intern.h"
 +
 +/* To use custom dials exported to geom_dial_gizmo.c */
 +// #define USE_GIZMO_CUSTOM_DIAL
 +
 +static int gizmo_dial_modal(
 +        bContext *C, wmGizmo *gz, const wmEvent *event,
 +        eWM_GizmoFlagTweak tweak_flag);
 +
 +typedef struct DialInteraction {
 +      struct {
 +              float mval[2];
 +              /* Only for when using properties. */
 +              float prop_angle;
 +      } init;
 +      struct {
 +              /* Cache the last angle to detect rotations bigger than -/+ PI. */
 +              eWM_GizmoFlagTweak tweak_flag;
 +              float angle;
 +      } prev;
 +
 +      /* Number of full rotations. */
 +      int rotations;
 +
 +      /* Final output values, used for drawing. */
 +      struct {
 +              float angle_ofs;
 +              float angle_delta;
 +      } output;
 +} DialInteraction;
 +
 +#define DIAL_WIDTH       1.0f
 +#define DIAL_RESOLUTION 48
 +
 +/* Could make option, negative to clip more (don't show when view aligned). */
 +#define DIAL_CLIP_BIAS 0.02
 +
 +/* -------------------------------------------------------------------- */
 +
 +static void dial_geom_draw(
 +        const wmGizmo *gz, const float color[4], const bool select,
 +        float axis_modal_mat[4][4], float clip_plane[4], const float arc_inner_factor)
 +{
 +#ifdef USE_GIZMO_CUSTOM_DIAL
 +      UNUSED_VARS(gz, axis_modal_mat, clip_plane);
 +      wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_dial, select, color);
 +#else
 +      const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
 +      const bool filled = (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_FILL) != 0;
 +
 +      GPU_line_width(gz->line_width);
 +
 +      GPUVertFormat *format = immVertexFormat();
 +      uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
 +
 +      if (clip_plane) {
 +              immBindBuiltinProgram(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR);
 +              float clip_plane_f[4] = {clip_plane[0], clip_plane[1], clip_plane[2], clip_plane[3]};
 +              immUniform4fv("ClipPlane", clip_plane_f);
 +              immUniformMatrix4fv("ModelMatrix", axis_modal_mat);
 +      }
 +      else {
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      }
 +
 +      immUniformColor4fv(color);
 +
 +      if (filled) {
 +              imm_draw_circle_fill_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION);
 +      }
 +      else {
 +              imm_draw_circle_wire_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION);
 +              if (arc_inner_factor != 0.0f) {
 +                      imm_draw_circle_wire_2d(pos, 0, 0, arc_inner_factor, DIAL_RESOLUTION);
 +              }
 +      }
 +
 +      immUnbindProgram();
 +
 +      UNUSED_VARS(select);
 +#endif
 +}
 +
 +/**
 + * Draws a line from (0, 0, 0) to \a co_outer, at \a angle.
 + */
 +static void dial_ghostarc_draw_helpline(
 +        const float angle, const float co_outer[3], const float color[4])
 +{
 +      GPU_matrix_push();
 +      GPU_matrix_rotate_3f(RAD2DEGF(angle), 0.0f, 0.0f, -1.0f);
 +
 +      uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +
 +      immUniformColor4fv(color);
 +
 +      immBegin(GPU_PRIM_LINE_STRIP, 2);
 +      immVertex3f(pos, 0.0f, 0, 0.0f);
 +      immVertex3fv(pos, co_outer);
 +      immEnd();
 +
 +      immUnbindProgram();
 +
 +      GPU_matrix_pop();
 +}
 +
 +static void dial_ghostarc_draw(
 +        const float angle_ofs, const float angle_delta,
 +        const float arc_inner_factor, const float color[4])
 +{
 +      const float width_inner = DIAL_WIDTH;
 +      GPUVertFormat *format = immVertexFormat();
 +      uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +
 +      if (arc_inner_factor != 0.0) {
 +              float color_dark[4] = {0};
 +              color_dark[3] = color[3] / 2;
 +              immUniformColor4fv(color_dark);
 +              imm_draw_disk_partial_fill_2d(
 +                      pos, 0, 0, arc_inner_factor, width_inner, DIAL_RESOLUTION, RAD2DEGF(angle_ofs), RAD2DEGF(M_PI * 2));
 +      }
 +
 +      immUniformColor4fv(color);
 +      imm_draw_disk_partial_fill_2d(
 +              pos, 0, 0, arc_inner_factor, width_inner, DIAL_RESOLUTION, RAD2DEGF(angle_ofs), RAD2DEGF(angle_delta));
 +      immUnbindProgram();
 +}
 +
 +static void dial_ghostarc_get_angles(
 +        const wmGizmo *gz,
 +        const wmEvent *event,
 +        const ARegion *ar,
 +        float mat[4][4], const float co_outer[3],
 +        float *r_start, float *r_delta)
 +{
 +      DialInteraction *inter = gz->interaction_data;
 +      const RegionView3D *rv3d = ar->regiondata;
 +      const float mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin};
 +
 +      /* We might need to invert the direction of the angles. */
 +      float view_vec[3], axis_vec[3];
 +      ED_view3d_global_to_vector(rv3d, gz->matrix_basis[3], view_vec);
 +      normalize_v3_v3(axis_vec, gz->matrix_basis[2]);
 +
 +      float proj_outer_rel[3];
 +      mul_v3_project_m4_v3(proj_outer_rel, mat, co_outer);
 +      sub_v3_v3(proj_outer_rel, gz->matrix_basis[3]);
 +
 +      float proj_mval_new_rel[3];
 +      float proj_mval_init_rel[3];
 +      float dial_plane[4];
 +
 +      plane_from_point_normal_v3(dial_plane, gz->matrix_basis[3], axis_vec);
 +
-       if (!ED_view3d_win_to_3d_on_plane(ar, dial_plane, mval, proj_mval_new_rel)) {
++      if (!ED_view3d_win_to_3d_on_plane(ar, dial_plane, inter->init.mval, false, proj_mval_init_rel)) {
 +              goto fail;
 +      }
 +      sub_v3_v3(proj_mval_init_rel, gz->matrix_basis[3]);
 +
++      if (!ED_view3d_win_to_3d_on_plane(ar, dial_plane, mval, false, proj_mval_new_rel)) {
 +              goto fail;
 +      }
 +      sub_v3_v3(proj_mval_new_rel, gz->matrix_basis[3]);
 +
 +      const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
 +
 +      /* Start direction from mouse or set by user. */
 +      const float *proj_init_rel =
 +              (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y) ?
 +              gz->matrix_basis[1] : proj_mval_init_rel;
 +
 +      /* Return angles. */
 +      const float start = angle_wrap_rad(angle_signed_on_axis_v3v3_v3(proj_outer_rel, proj_init_rel, axis_vec));
 +      const float delta = angle_wrap_rad(angle_signed_on_axis_v3v3_v3(proj_mval_init_rel, proj_mval_new_rel, axis_vec));
 +
 +      /* Change of sign, we passed the 180 degree threshold. This means we need to add a turn
 +       * to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2.
 +       * Logic taken from #BLI_dial_angle */
 +      if ((delta * inter->prev.angle < 0.0f) &&
 +          (fabsf(inter->prev.angle) > (float)M_PI_2))
 +      {
 +              if (inter->prev.angle < 0.0f) {
 +                      inter->rotations--;
 +              }
 +              else {
 +                      inter->rotations++;
 +              }
 +      }
 +      inter->prev.angle = delta;
 +
 +      const bool wrap_angle = RNA_boolean_get(gz->ptr, "wrap_angle");
 +      const double delta_final = (double)delta + ((2 * M_PI) * (double)inter->rotations);
 +      *r_start = start;
 +      *r_delta = (float)(wrap_angle ? fmod(delta_final, 2 * M_PI) : delta_final);
 +      return;
 +
 +      /* If we can't project (unlikely). */
 +fail:
 +      *r_start = 0.0;
 +      *r_delta = 0.0;
 +}
 +
 +static void dial_ghostarc_draw_with_helplines(
 +        const float angle_ofs, const float angle_delta,
 +        const float arc_inner_factor, const float color_helpline[4], const int draw_options)
 +{
 +      /* Coordinate at which the arc drawing will be started. */
 +      const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f};
 +      dial_ghostarc_draw(angle_ofs, angle_delta, arc_inner_factor, (const float[4]){0.8f, 0.8f, 0.8f, 0.4f});
 +      GPU_line_width(1.0f);
 +      dial_ghostarc_draw_helpline(angle_ofs, co_outer, color_helpline);
 +      if (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE) {
 +              GPU_line_width(3.0f);
 +      }
 +      dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer, color_helpline);
 +}
 +
 +static void dial_draw_intern(
 +        const bContext *C, wmGizmo *gz,
 +        const bool select, const bool highlight, float clip_plane[4])
 +{
 +      float matrix_final[4][4];
 +      float color[4];
 +
 +      BLI_assert(CTX_wm_area(C)->spacetype == SPACE_VIEW3D);
 +
 +      gizmo_color_get(gz, highlight, color);
 +
 +      WM_gizmo_calc_matrix_final(gz, matrix_final);
 +
 +      GPU_matrix_push();
 +      GPU_matrix_mul(matrix_final);
 +
 +      /* FIXME(campbell): look into removing this. */
 +      if ((gz->flag & WM_GIZMO_DRAW_VALUE) &&
 +          (gz->state & WM_GIZMO_STATE_MODAL))
 +      {
 +              /* XXX, View3D rotation gizmo doesn't call modal. */
 +              if (!WM_gizmo_target_property_is_valid_any(gz)) {
 +                      wmWindow *win = CTX_wm_window(C);
 +                      gizmo_dial_modal((bContext *)C, gz, win->eventstate, 0);
 +              }
 +      }
 +
 +      GPU_polygon_smooth(false);
 +
 +      const float arc_inner_factor = RNA_float_get(gz->ptr, "arc_inner_factor");
 +      if (select == false) {
 +              float angle_ofs = 0.0f;
 +              float angle_delta = 0.0f;
 +              bool show_ghostarc = false;
 +
 +              /* Draw rotation indicator arc first. */
 +              wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
 +              const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
 +
 +              if (WM_gizmo_target_property_is_valid(gz_prop) &&
 +                  (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE))
 +              {
 +                      angle_ofs = 0.0f;
 +                      angle_delta = WM_gizmo_target_property_float_get(gz, gz_prop);
 +                      show_ghostarc = true;
 +              }
 +              else if ((gz->flag & WM_GIZMO_DRAW_VALUE) &&
 +                       (gz->state & WM_GIZMO_STATE_MODAL))
 +              {
 +                      DialInteraction *inter = gz->interaction_data;
 +                      angle_ofs = inter->output.angle_ofs;
 +                      angle_delta = inter->output.angle_delta;
 +                      show_ghostarc = true;
 +              }
 +
 +              if (show_ghostarc) {
 +                      dial_ghostarc_draw_with_helplines(angle_ofs, angle_delta, arc_inner_factor, color, draw_options);
 +                      if ((draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR) != 0) {
 +                              angle_ofs += M_PI;
 +                              dial_ghostarc_draw_with_helplines(angle_ofs, angle_delta, arc_inner_factor, color, draw_options);
 +                      }
 +              }
 +      }
 +
 +      /* Draw actual dial gizmo. */
 +      dial_geom_draw(gz, color, select, gz->matrix_basis, clip_plane, arc_inner_factor);
 +
 +      GPU_matrix_pop();
 +}
 +
 +static void gizmo_dial_draw_select(const bContext *C, wmGizmo *gz, int select_id)
 +{
 +      float clip_plane_buf[4];
 +      const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
 +      float *clip_plane = (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_CLIP) ? clip_plane_buf : NULL;
 +
 +      if (clip_plane) {
 +              ARegion *ar = CTX_wm_region(C);
 +              RegionView3D *rv3d = ar->regiondata;
 +
 +              copy_v3_v3(clip_plane, rv3d->viewinv[2]);
 +              clip_plane[3] = -dot_v3v3(rv3d->viewinv[2], gz->matrix_basis[3]);
 +              clip_plane[3] += DIAL_CLIP_BIAS * gz->scale_final;
 +              glEnable(GL_CLIP_DISTANCE0);
 +      }
 +
 +      GPU_select_load_id(select_id);
 +      dial_draw_intern(C, gz, true, false, clip_plane);
 +
 +      if (clip_plane) {
 +              glDisable(GL_CLIP_DISTANCE0);
 +      }
 +}
 +
 +static void gizmo_dial_draw(const bContext *C, wmGizmo *gz)
 +{
 +      const bool is_modal = gz->state & WM_GIZMO_STATE_MODAL;
 +      const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
 +      float clip_plane_buf[4];
 +      const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
 +      float *clip_plane = (!is_modal && (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_CLIP)) ? clip_plane_buf : NULL;
 +
 +      if (clip_plane) {
 +              ARegion *ar = CTX_wm_region(C);
 +              RegionView3D *rv3d = ar->regiondata;
 +
 +              copy_v3_v3(clip_plane, rv3d->viewinv[2]);
 +              clip_plane[3] = -dot_v3v3(rv3d->viewinv[2], gz->matrix_basis[3]);
 +              clip_plane[3] += DIAL_CLIP_BIAS * gz->scale_final;
 +
 +              glEnable(GL_CLIP_DISTANCE0);
 +      }
 +
 +      GPU_blend(true);
 +      dial_draw_intern(C, gz, false, is_highlight, clip_plane);
 +      GPU_blend(false);
 +
 +      if (clip_plane) {
 +              glDisable(GL_CLIP_DISTANCE0);
 +      }
 +}
 +
 +static int gizmo_dial_modal(
 +        bContext *C, wmGizmo *gz, const wmEvent *event,
 +        eWM_GizmoFlagTweak tweak_flag)
 +{
 +      DialInteraction *inter = gz->interaction_data;
 +      if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) {
 +              return OPERATOR_RUNNING_MODAL;
 +      }
 +      /* Coordinate at which the arc drawing will be started. */
 +      const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f};
 +      float angle_ofs, angle_delta;
 +
 +      dial_ghostarc_get_angles(
 +              gz, event, CTX_wm_region(C), gz->matrix_basis, co_outer, &angle_ofs, &angle_delta);
 +
 +      if (tweak_flag & WM_GIZMO_TWEAK_SNAP) {
 +              const double snap = DEG2RAD(5);
 +              angle_delta = (float)roundf((double)angle_delta / snap) * snap;
 +      }
 +      if (tweak_flag & WM_GIZMO_TWEAK_PRECISE) {
 +              angle_delta *= 0.1f;
 +      }
 +      inter->output.angle_delta = angle_delta;
 +      inter->output.angle_ofs = angle_ofs;
 +
 +      /* Set the property for the operator and call its modal function. */
 +      wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
 +      if (WM_gizmo_target_property_is_valid(gz_prop)) {
 +              WM_gizmo_target_property_float_set(C, gz, gz_prop, inter->init.prop_angle + angle_delta);
 +      }
 +
 +      inter->prev.tweak_flag = tweak_flag;
 +
 +      return OPERATOR_RUNNING_MODAL;
 +}
 +
 +
 +static void gizmo_dial_setup(wmGizmo *gz)
 +{
 +      const float dir_default[3] = {0.0f, 0.0f, 1.0f};
 +
 +      /* defaults */
 +      copy_v3_v3(gz->matrix_basis[2], dir_default);
 +}
 +
 +static int gizmo_dial_invoke(
 +        bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
 +{
 +      DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__);
 +
 +      inter->init.mval[0] = event->mval[0];
 +      inter->init.mval[1] = event->mval[1];
 +
 +      wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
 +      if (WM_gizmo_target_property_is_valid(gz_prop)) {
 +              inter->init.prop_angle = WM_gizmo_target_property_float_get(gz, gz_prop);
 +      }
 +
 +      gz->interaction_data = inter;
 +
 +      return OPERATOR_RUNNING_MODAL;
 +}
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Dial Gizmo API
 + *
 + * \{ */
 +
 +static void GIZMO_GT_dial_3d(wmGizmoType *gzt)
 +{
 +      /* identifiers */
 +      gzt->idname = "GIZMO_GT_dial_3d";
 +
 +      /* api callbacks */
 +      gzt->draw = gizmo_dial_draw;
 +      gzt->draw_select = gizmo_dial_draw_select;
 +      gzt->setup = gizmo_dial_setup;
 +      gzt->invoke = gizmo_dial_invoke;
 +      gzt->modal = gizmo_dial_modal;
 +
 +      gzt->struct_size = sizeof(wmGizmo);
 +
 +      /* rna */
 +      static EnumPropertyItem rna_enum_draw_options[] = {
 +              {ED_GIZMO_DIAL_DRAW_FLAG_CLIP, "CLIP", 0, "Clipped", ""},
 +              {ED_GIZMO_DIAL_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""},
 +              {ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR, "ANGLE_MIRROR", 0, "Angle Mirror", ""},
 +              {ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y, "ANGLE_START_Y", 0, "Angle Start Y", ""},
 +              {ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE, "ANGLE_VALUE", 0, "Show Angle Value", ""},
 +              {0, NULL, 0, NULL, NULL}
 +      };
 +      RNA_def_enum_flag(gzt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
 +      RNA_def_boolean(gzt->srna, "wrap_angle", true, "Wrap Angle", "");
 +      RNA_def_float_factor(gzt->srna, "arc_inner_factor", 0.0f, 0.0f, 1.0f, "Arc Inner Factor", "", 0.0f, 1.0f);
 +
 +      WM_gizmotype_target_property_def(gzt, "offset", PROP_FLOAT, 1);
 +}
 +
 +void ED_gizmotypes_dial_3d(void)
 +{
 +      WM_gizmotype_append(GIZMO_GT_dial_3d);
 +}
 +
 +/** \} */
index 8e9c1736122062eb27bc62c9ca5e6b8e35993051,c21a6cccb2e9e97ef0dd37e4b0ef0347fe2bdcb8..30daaad3c2cd34b82a3c2cb1cb7fa81ee96e2fab
@@@ -40,8 -40,6 +40,8 @@@ struct BPoint
  struct Base;
  struct BezTriple;
  struct BoundBox;
 +struct Camera;
 +struct Depsgraph;
  struct EditBone;
  struct ImBuf;
  struct MVert;
@@@ -51,15 -49,14 +51,15 @@@ struct Nurb
  struct Object;
  struct RV3DMatrixStore;
  struct RegionView3D;
 +struct RenderEngineType;
  struct Scene;
 +struct ViewLayer;
  struct ScrArea;
  struct View3D;
  struct ViewContext;
  struct bContext;
  struct bPoseChannel;
  struct bScreen;
 -struct bglMats;
  struct rctf;
  struct rcti;
  struct wmOperator;
@@@ -69,16 -66,12 +69,16 @@@ struct wmWindowManager
  struct GPUFX;
  struct GPUOffScreen;
  struct GPUFXSettings;
 +struct GPUViewport;
 +struct WorkSpace;
  enum eGPUFXFlags;
  
  /* for derivedmesh drawing callbacks, for view3d_select, .... */
  typedef struct ViewContext {
        struct Main *bmain;
 +      struct Depsgraph *depsgraph;
        struct Scene *scene;
 +      struct ViewLayer *view_layer;
        struct Object *obact;
        struct Object *obedit;
        struct ARegion *ar;
@@@ -98,41 -91,17 +98,41 @@@ typedef struct ViewDepths 
        bool damaged;
  } ViewDepths;
  
 -float *ED_view3d_cursor3d_get(struct Scene *scene, struct View3D *v3d);
 -void   ED_view3d_cursor3d_position(struct bContext *C, const int mval[2], float cursor_co[3]);
 -void   ED_view3d_cursor3d_update(struct bContext *C, const int mval[2]);
 +
 +/* Rotate 3D cursor on placement. */
 +enum eV3DCursorOrient {
 +      V3D_CURSOR_ORIENT_NONE = 0,
 +      V3D_CURSOR_ORIENT_VIEW,
 +      V3D_CURSOR_ORIENT_XFORM,
 +      V3D_CURSOR_ORIENT_GEOM,
 +};
 +
 +struct View3DCursor *ED_view3d_cursor3d_get(struct Scene *scene, struct View3D *v3d);
 +void ED_view3d_cursor3d_calc_mat3(const struct Scene *scene, const struct View3D *v3d, float mat[3][3]);
 +void ED_view3d_cursor3d_calc_mat4(const struct Scene *scene, const struct View3D *v3d, float mat[4][4]);
 +void ED_view3d_cursor3d_position(
 +        struct bContext *C, const int mval[2],
 +        const bool use_depth,
 +        float cursor_co[3]);
 +void ED_view3d_cursor3d_position_rotation(
 +        struct bContext *C, const int mval[2],
 +        const bool use_depth, enum eV3DCursorOrient orientation,
 +        float cursor_co[3], float cursor_quat[4]);
 +void ED_view3d_cursor3d_update(
 +        struct bContext *C, const int mval[2],
 +        const bool use_depth, enum eV3DCursorOrient orientation);
  
  struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
  
  void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist);
 -void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist);
 +void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], float *dist);
  
 -void ED_view3d_from_object(struct Object *ob, float ofs[3], float quat[4], float *dist, float *lens);
 -void ED_view3d_to_object(struct Object *ob, const float ofs[3], const float quat[4], const float dist);
 +void ED_view3d_from_object(
 +        const struct Object *ob,
 +        float ofs[3], float quat[4], float *dist, float *lens);
 +void ED_view3d_to_object(
 +        const struct Depsgraph *depsgraph, struct Object *ob,
 +        const float ofs[3], const float quat[4], const float dist);
  
  void ED_view3d_lastview_store(struct RegionView3D *rv3d);
  
  void  ED_view3d_depth_update(struct ARegion *ar);
  float ED_view3d_depth_read_cached(const struct ViewContext *vc, const int mval[2]);
  bool  ED_view3d_depth_read_cached_normal(
 -        const ViewContext *vc, const struct bglMats *mats, const int mval[2],
 +        const ViewContext *vc, const int mval[2],
          float r_normal[3]);
  bool ED_view3d_depth_unproject(
 -        const struct ARegion *ar, const struct bglMats *mats,
 +        const struct ARegion *ar,
          const int mval[2], const double depth,
          float r_location_world[3]);
  void  ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
@@@ -253,11 -222,9 +253,11 @@@ float ED_view3d_pixel_size_no_ui_scale(
  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_clipped(
 +        struct Depsgraph *depsgraph,
          const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
          float ray_start[3], float ray_normal[3], const bool do_clip);
  bool ED_view3d_win_to_ray_clipped_ex(
 +        struct Depsgraph *depsgraph,
          const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
          float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
  void ED_view3d_win_to_ray(
@@@ -274,24 -241,21 +274,24 @@@ void ED_view3d_win_to_3d_int
          float r_out[3]);
  bool ED_view3d_win_to_3d_on_plane(
          const struct ARegion *ar,
-         const float plane[4], const float mval[2],
+         const float plane[4], const float mval[2], const bool do_clip,
          float r_out[3]);
  bool ED_view3d_win_to_3d_on_plane_int(
          const struct ARegion *ar,
-         const float plane[4], const int mval[2],
+         const float plane[4], const int mval[2], const bool do_clip,
          float r_out[3]);
  void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac);
  void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]);
  void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]);
  bool ED_view3d_win_to_segment_clipped(
 +        struct Depsgraph *depsgraph,
          const struct ARegion *ar, struct View3D *v3d, const float mval[2],
          float r_ray_start[3], float r_ray_end[3], const bool do_clip);
  void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
  void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, float obmat[4][4], float pmat[4][4]);
 -void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, const float y, const float z);
 +
 +void ED_view3d_project(const struct ARegion *ar, const float world[3], float region[3]);
 +bool ED_view3d_unproject(const struct ARegion *ar, float regionx, float regiony, float regionz, float world[3]);
  
  /* end */
  
@@@ -300,34 -264,28 +300,34 @@@ void ED_view3d_dist_range_get
          const struct View3D *v3d,
          float r_dist_range[2]);
  bool ED_view3d_clip_range_get(
 +        struct Depsgraph *depsgraph,
          const struct View3D *v3d, const struct RegionView3D *rv3d,
          float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
  bool ED_view3d_viewplane_get(
 +        struct Depsgraph *depsgraph,
          const struct View3D *v3d, const struct RegionView3D *rv3d, int winxi, int winyi,
          struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize);
  
  void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
  
  void ED_view3d_calc_camera_border(
 -        const struct Scene *scene, const struct ARegion *ar,
 +        const struct Scene *scene, struct Depsgraph *depsgraph,
 +        const struct ARegion *ar,
          const struct View3D *v3d, const struct RegionView3D *rv3d,
          struct rctf *r_viewborder, const bool no_shift);
  void ED_view3d_calc_camera_border_size(
 -        const struct Scene *scene, const struct ARegion *ar,
 +        const struct Scene *scene, struct Depsgraph *depsgraph,
 +        const struct ARegion *ar,
          const struct View3D *v3d, const struct RegionView3D *rv3d,
          float r_size[2]);
  bool ED_view3d_calc_render_border(
 -        const struct Scene *scene, const struct View3D *v3d,
 -        const struct ARegion *ar, struct rcti *rect);
 +        const struct Scene *scene, struct Depsgraph *depsgraph,
 +        struct View3D *v3d,
 +        struct ARegion *ar, struct rcti *rect);
  
  void ED_view3d_clipping_calc_from_boundbox(float clip[6][4], const struct BoundBox *clipbb, const bool is_flip);
 -void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect);
 +void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4],
 +        const struct ARegion *ar, const struct Object *ob, const struct rcti *rect);
  void ED_view3d_clipping_local(struct RegionView3D *rv3d, float mat[4][4]);
  bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], const bool is_local);
  void ED_view3d_clipping_set(struct RegionView3D *rv3d);
@@@ -338,32 -296,27 +338,32 @@@ float ED_view3d_radius_to_dist_persp(co
  float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
  float ED_view3d_radius_to_dist(
          const struct View3D *v3d, const struct ARegion *ar,
 +        const struct Depsgraph *depsgraph,
          const char persp, const bool use_aspect,
          const float radius);
  
 -void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][4]);
 +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos);
  
  /* backbuffer select and draw support */
 +void          ED_view3d_backbuf_validate_with_select_mode(struct ViewContext *vc, short select_mode);
  void          ED_view3d_backbuf_validate(struct ViewContext *vc);
 -struct ImBuf *ED_view3d_backbuf_read(struct ViewContext *vc, int xmin, int ymin, int xmax, int ymax);
 +struct ImBuf *ED_view3d_backbuf_read(
 +        struct ViewContext *vc, int xmin, int ymin, int xmax, int ymax);
  unsigned int  ED_view3d_backbuf_sample_rect(
          struct ViewContext *vc, const int mval[2], int size,
          unsigned int min, unsigned int max, float *r_dist);
  int          ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float dist);
 -unsigned int ED_view3d_backbuf_sample(struct ViewContext *vc, int x, int y);
 +unsigned int ED_view3d_backbuf_sample(
 +        struct ViewContext *vc, int x, int y);
  
  bool ED_view3d_autodist(
 -        struct Main *bmain, struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
 +        struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d,
          const int mval[2], float mouse_worldloc[3],
          const bool alphaoverride, const float fallback_depth_pt[3]);
  
  /* only draw so ED_view3d_autodist_simple can be called many times after */
 -void ED_view3d_autodist_init(struct Main *bmain, struct Scene *scene, struct ARegion *ar, struct View3D *v3d, int mode);
 +void ED_view3d_autodist_init(
 +        struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, int mode);
  bool ED_view3d_autodist_simple(struct ARegion *ar, const int mval[2], float mouse_worldloc[3], int margin, float *force_depth);
  bool ED_view3d_autodist_depth(struct ARegion *ar, const int mval[2], int margin, float *depth);
  bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], const int mval_end[2], int margin, float *depth);
@@@ -381,27 -334,20 +381,27 @@@ typedef enum 
        VIEW3D_SELECT_PICK_NEAREST = 2,
  } eV3DSelectMode;
  
 +typedef enum {
 +      /* Don't exclude anything. */
 +      VIEW3D_SELECT_FILTER_NOP = 0,
 +      /* Don't select objects outside the current mode. */
 +      VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK = 1,
 +} eV3DSelectObjectFilter;
 +
  void view3d_opengl_select_cache_begin(void);
  void view3d_opengl_select_cache_end(void);
  
  int view3d_opengl_select(
          struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input,
 -        eV3DSelectMode select_mode);
 +        eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter);
  
  /* view3d_select.c */
  float ED_view3d_select_dist_px(void);
  void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc);
 +void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
  void view3d_operator_needs_opengl(const struct bContext *C);
  void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
  void view3d_opengl_read_pixels(struct ARegion *ar, int x, int y, int w, int h, int format, int type, void *data);
 -void view3d_get_transformation(const struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob, struct bglMats *mats);
  
  /* XXX should move to BLI_math */
  bool edge_inside_circle(const float cent[2], float radius, const float screen_co_a[2], const float screen_co_b[2]);
@@@ -420,58 -366,51 +420,58 @@@ void ED_view3d_check_mats_rv3d(struct R
  #  define ED_view3d_clear_mats_rv3d(rv3d) (void)(rv3d)
  #  define ED_view3d_check_mats_rv3d(rv3d) (void)(rv3d)
  #endif
 -int ED_view3d_scene_layer_set(int lay, const bool *values, int *active);
 +int ED_view3d_view_layer_set(int lay, const bool *values, int *active);
  
  struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d);
  void                    ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat);
  
 +void  ED_draw_object_facemap(
 +        struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, const float col[4], const int facemap);
 +
 +struct RenderEngineType *ED_view3d_engine_type(struct Scene *scene, int drawtype);
 +
  bool ED_view3d_context_activate(struct bContext *C);
 -void ED_view3d_draw_offscreen_init(struct Main *bmain, struct Scene *scene, struct View3D *v3d);
  void ED_view3d_draw_offscreen(
 -        struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
 -        float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
 -        struct GPUFX *fx, struct GPUFXSettings *fx_settings,
 -        struct GPUOffScreen *ofs);
 +        struct Depsgraph *depsgraph, struct Scene *scene,
 +        int drawtype,
 +        struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
 +        float winmat[4][4], bool do_sky, bool is_persp, const char *viewname,
 +        struct GPUFXSettings *fx_settings,
 +        struct GPUOffScreen *ofs, struct GPUViewport *viewport);
  void ED_view3d_draw_setup_view(
 -        struct wmWindow *win, struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
 +        struct wmWindow *win, struct Depsgraph *depsgraph, struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
          float viewmat[4][4], float winmat[4][4], const struct rcti *rect);
  
  enum {
        V3D_OFSDRAW_NONE             = (0),
  
 -      V3D_OFSDRAW_USE_BACKGROUND   = (1 << 0),
 -      V3D_OFSDRAW_USE_FULL_SAMPLE  = (1 << 1),
 +      V3D_OFSDRAW_USE_FULL_SAMPLE  = (1 << 0),
  
        /* Only works with ED_view3d_draw_offscreen_imbuf_simple(). */
 -      V3D_OFSDRAW_USE_GPENCIL      = (1 << 2),
 +      V3D_OFSDRAW_USE_GPENCIL      = (1 << 1),
        V3D_OFSDRAW_USE_SOLID_TEX    = (1 << 2),
        V3D_OFSDRAW_USE_CAMERA_DOF   = (1 << 3),
  };
  
  struct ImBuf *ED_view3d_draw_offscreen_imbuf(
 -        struct Main *bmain, struct Scene *scene,
 -        struct View3D *v3d, struct ARegion *ar, int sizex, int sizey,
 -        unsigned int flag, unsigned int draw_flags,
 +        struct Depsgraph *depsgraph, struct Scene *scene,
 +        int drawtype,
 +        struct View3D *v3d, struct ARegion *ar,
 +        int sizex, int sizey, unsigned int flag, unsigned int draw_flags,
          int alpha_mode, int samples, const char *viewname,
 -        struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
 +        struct GPUOffScreen *ofs, char err_out[256]);
  struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
 -        struct Main *bmain, struct Scene *scene,
 +        struct Depsgraph *depsgraph, struct Scene *scene,
 +        int drawtype,
          struct Object *camera, int width, int height,
 -        unsigned int flag, unsigned int draw_flags, int drawtype, int alpha_mode,
 +        unsigned int flag, unsigned int draw_flags, int alpha_mode,
          int samples, const char *viewname,
 -        struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
 +        struct GPUOffScreen *ofs, char err_out[256]);
  
  struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
  void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);
  void ED_view3d_update_viewmat(
 -        struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
 +        struct Depsgraph *depsgraph, struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
          float viewmat[4][4], float winmat[4][4], const struct rcti *rect);
  bool ED_view3d_quat_from_axis_view(const char view, float quat[4]);
  char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon);
@@@ -480,28 -419,20 +480,28 @@@ char ED_view3d_axis_view_opposite(char 
  bool ED_view3d_lock(struct RegionView3D *rv3d);
  
  uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d);
 -uint64_t ED_view3d_screen_datamask(const struct bScreen *screen);
 +uint64_t ED_view3d_screen_datamask(const struct Scene *scene, 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);
 +void ED_view3d_persp_switch_from_camera(
 +        const struct Depsgraph *depsgraph,
 +        struct View3D *v3d, struct RegionView3D *rv3d, const char persp);
 +bool ED_view3d_persp_ensure(
 +        const struct Depsgraph *depsgraph,
 +        struct View3D *v3d, struct ARegion *ar);
  
  
  /* camera lock functions */
  bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
  /* copy the camera to the view before starting a view transformation */
 -void ED_view3d_camera_lock_init_ex(struct View3D *v3d, struct RegionView3D *rv3d, const bool calc_dist);
 -void ED_view3d_camera_lock_init(struct View3D *v3d, struct RegionView3D *rv3d);
 +void ED_view3d_camera_lock_init_ex(
 +        const struct Depsgraph *depsgraph,
 +        struct View3D *v3d, struct RegionView3D *rv3d, const bool calc_dist);
 +void ED_view3d_camera_lock_init(const struct Depsgraph *depsgraph, struct View3D *v3d, struct RegionView3D *rv3d);
  /* copy the view to the camera, return true if */
 -bool ED_view3d_camera_lock_sync(struct View3D *v3d, struct RegionView3D *rv3d);
 +bool ED_view3d_camera_lock_sync(
 +        const struct Depsgraph *depsgraph,
 +        struct View3D *v3d, struct RegionView3D *rv3d);
  
  bool ED_view3d_camera_autokey(
          struct Scene *scene, struct ID *id_key,
@@@ -512,6 -443,10 +512,6 @@@ bool ED_view3d_camera_lock_autokey
  
  void ED_view3d_lock_clear(struct View3D *v3d);
  
 -struct BGpic *ED_view3d_background_image_new(struct View3D *v3d);
 -void ED_view3d_background_image_remove(struct View3D *v3d, struct BGpic *bgpic);
 -void ED_view3d_background_image_clear(struct View3D *v3d);
 -
  #define VIEW3D_MARGIN 1.4f
  #define VIEW3D_DIST_FALLBACK 1.0f
  
@@@ -536,15 -471,8 +536,15 @@@ void ED_view3d_stop_render_preview(stru
  void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa);
  
  #define V3D_IS_ZBUF(v3d) \
 -      (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE))
 +      (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->shading.type > OB_WIRE))
  
  void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id);
  
 +/* view3d_draw_legacy.c */
 +/* Try avoid using these more move out of legacy. */
 +void ED_view3d_draw_bgpic_test(
 +        struct Scene *scene, struct Depsgraph *depsgraph,
 +        struct ARegion *ar, struct View3D *v3d,
 +        const bool do_foreground, const bool do_camera_frame);
 +
  #endif /* __ED_VIEW3D_H__ */
index 038a45650bf6aed6db0bc725ea6c3f98e0103531,0000000000000000000000000000000000000000..e8f29d9a9b26880feeacf04e57290356bc9f9541
mode 100644,000000..100644
--- /dev/null
@@@ -1,683 -1,0 +1,683 @@@
-               if (UNLIKELY(!ED_view3d_win_to_3d_on_plane_int(ar, plane, mval, cursor_co))) {
 +/*
 + * ***** 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.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/editors/mesh/editmesh_extrude_spin_gizmo.c
 + *  \ingroup edmesh
 + */
 +
 +#include "BLI_math.h"
 +
 +#include "BKE_context.h"
 +
 +#include "RNA_access.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +#include "WM_message.h"
 +
 +#include "ED_gizmo_utils.h"
 +#include "ED_screen.h"
 +#include "ED_view3d.h"
 +
 +#include "UI_resources.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "mesh_intern.h"  /* own include */
 +
 +#include "ED_transform.h"
 +
 +#include "ED_gizmo_library.h"
 +#include "ED_undo.h"
 +
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Spin Tool Gizmo
 + * \{ */
 +
 +typedef struct GizmoGroupData_SpinInit {
 +      struct {
 +              wmGizmo *xyz_view[4];
 +      } gizmos;
 +
 +      /* Only for view orientation. */
 +      struct {
 +              float viewinv_m3[3][3];
 +      } prev;
 +
 +      /* We could store more vars here! */
 +      struct {
 +              wmOperatorType *ot_spin;
 +      } data;
 +} GizmoGroupData_SpinInit;
 +
 +static void gizmo_mesh_spin_init_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
 +{
 +      /* alpha values for normal/highlighted states */
 +      const float alpha = 0.6f;
 +      const float alpha_hi = 1.0f;
 +
 +      GizmoGroupData_SpinInit *ggd = MEM_callocN(sizeof(*ggd), __func__);
 +      gzgroup->customdata = ggd;
 +      const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
 +
 +      for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.xyz_view); i++) {
 +              wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
 +              UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
 +              WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true);
 +              ggd->gizmos.xyz_view[i] = gz;
 +      }
 +
 +      for (int i = 0; i < 3; i++) {
 +              wmGizmo *gz = ggd->gizmos.xyz_view[i];
 +              RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
 +              WM_gizmo_set_line_width(gz, 3.0f);
 +              float color[4];
 +              UI_GetThemeColor3fv(TH_AXIS_X + i, color);
 +              color[3] = alpha;
 +              WM_gizmo_set_color(gz, color);
 +              color[3] = alpha_hi;
 +              WM_gizmo_set_color_highlight(gz, color);
 +      }
 +
 +      {
 +              wmGizmo *gz = ggd->gizmos.xyz_view[3];
 +              WM_gizmo_set_line_width(gz, 2.0f);
 +              float color[4];
 +              copy_v3_fl(color, 1.0f);
 +              color[3] = alpha;
 +              WM_gizmo_set_color(gz, color);
 +              color[3] = alpha_hi;
 +              WM_gizmo_set_color_highlight(gz, color);
 +      }
 +
 +      WM_gizmo_set_scale(ggd->gizmos.xyz_view[3], 1.2f);
 +
 +      ggd->data.ot_spin = WM_operatortype_find("MESH_OT_spin", true);
 +}
 +
 +static void gizmo_mesh_spin_init_refresh(const bContext *C, wmGizmoGroup *gzgroup);
 +
 +static void gizmo_mesh_spin_init_refresh_axis_orientation(
 +        wmGizmoGroup *gzgroup,
 +        int axis_index, const float axis_vec[3])
 +{
 +      GizmoGroupData_SpinInit *ggd = gzgroup->customdata;
 +      wmGizmo *gz = ggd->gizmos.xyz_view[axis_index];
 +      WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis_vec);
 +
 +      PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ggd->data.ot_spin, NULL);
 +      RNA_float_set_array(ptr, "axis", axis_vec);
 +}
 +
 +
 +static void gizmo_mesh_spin_init_draw_prepare(
 +        const bContext *C, wmGizmoGroup *gzgroup)
 +{
 +      GizmoGroupData_SpinInit *ggd = gzgroup->customdata;
 +      RegionView3D *rv3d = CTX_wm_region_view3d(C);
 +      float viewinv_m3[3][3];
 +      copy_m3_m4(viewinv_m3, rv3d->viewinv);
 +
 +      {
 +              Scene *scene = CTX_data_scene(C);
 +              switch (scene->orientation_type) {
 +                      case V3D_MANIP_VIEW:
 +                      {
 +                              if (!equals_m3m3(viewinv_m3, ggd->prev.viewinv_m3)) {
 +                                      /* Take care calling refresh from draw_prepare,
 +                                       * this should be OK because it's only adjusting the cage orientation. */
 +                                      gizmo_mesh_spin_init_refresh(C, gzgroup);
 +                              }
 +                              break;
 +                      }
 +              }
 +      }
 +
 +      /* Refresh handled above when using view orientation. */
 +      if (!equals_m3m3(viewinv_m3, ggd->prev.viewinv_m3)) {
 +              gizmo_mesh_spin_init_refresh_axis_orientation(gzgroup, 3, rv3d->viewinv[2]);
 +              copy_m3_m4(ggd->prev.viewinv_m3, rv3d->viewinv);
 +      }
 +}
 +
 +static void gizmo_mesh_spin_init_refresh(const bContext *C, wmGizmoGroup *gzgroup)
 +{
 +      GizmoGroupData_SpinInit *ggd = gzgroup->customdata;
 +      RegionView3D *rv3d = ED_view3d_context_rv3d((bContext *)C);
 +
 +      {
 +              Scene *scene = CTX_data_scene(C);
 +              View3D *v3d = CTX_wm_view3d(C);
 +              const View3DCursor *cursor = ED_view3d_cursor3d_get(scene, v3d);
 +              for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.xyz_view); i++) {
 +                      wmGizmo *gz = ggd->gizmos.xyz_view[i];
 +                      WM_gizmo_set_matrix_location(gz, cursor->location);
 +              }
 +      }
 +
 +      float mat[3][3];
 +      ED_transform_calc_orientation_from_type(C, mat);
 +      for (int i = 0; i < 3; i++) {
 +              gizmo_mesh_spin_init_refresh_axis_orientation(gzgroup, i, mat[i]);
 +      }
 +
 +      {
 +              gizmo_mesh_spin_init_refresh_axis_orientation(gzgroup, 3, rv3d->viewinv[2]);
 +      }
 +
 +      /* Needed to test view orientation changes. */
 +      copy_m3_m4(ggd->prev.viewinv_m3, rv3d->viewinv);
 +}
 +
 +
 +static void gizmo_mesh_spin_init_message_subscribe(
 +        const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      ARegion *ar = CTX_wm_region(C);
 +
 +      /* Subscribe to view properties */
 +      wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
 +              .owner = ar,
 +              .user_data = gzgroup->parent_gzmap,
 +              .notify = WM_gizmo_do_msg_notify_tag_refresh,
 +      };
 +
 +      PointerRNA scene_ptr;
 +      RNA_id_pointer_create(&scene->id, &scene_ptr);
 +
 +      {
 +              extern PropertyRNA rna_Scene_transform_orientation;
 +              extern PropertyRNA rna_Scene_cursor_location;
 +              const PropertyRNA *props[] = {
 +                      &rna_Scene_transform_orientation,
 +                      &rna_Scene_cursor_location,
 +              };
 +              for (int i = 0; i < ARRAY_SIZE(props); i++) {
 +                      WM_msg_subscribe_rna(mbus, &scene_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
 +              }
 +      }
 +}
 +
 +void MESH_GGT_spin(struct wmGizmoGroupType *gzgt)
 +{
 +      gzgt->name = "Mesh Spin Init";
 +      gzgt->idname = "MESH_GGT_spin";
 +
 +      gzgt->flag = WM_GIZMOGROUPTYPE_3D;
 +
 +      gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
 +      gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
 +
 +      gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
 +      gzgt->setup = gizmo_mesh_spin_init_setup;
 +      gzgt->refresh = gizmo_mesh_spin_init_refresh;
 +      gzgt->message_subscribe = gizmo_mesh_spin_init_message_subscribe;
 +      gzgt->draw_prepare = gizmo_mesh_spin_init_draw_prepare;
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Spin Redo Gizmo
 + * \{ */
 +
 +/**
 + * Don't show these for now, because they overlay the tools #MESH_GGT_spin_redo gizmos.
 + * this means we cant rotate the currently running gizmo.
 + */
 +// #define USE_EXTRA_CONTROLS
 +/**
 + * Orient the dial so the 'arc' starts where the mouse cursor is,
 + * this is simply to keep the gizmo displaying where the cursor starts.
 + * It's not needed for practical functionality.
 + */
 +#define USE_ANGLE_Z_ORIENT
 +
 +typedef struct GizmoGroupData_SpinRedo {
 +      /* Arrow to change plane depth. */
 +      struct wmGizmo *translate_z;
 +      /* Translate XYZ */
 +      struct wmGizmo *translate_c;
 +      /* For grabbing the gizmo and moving freely. */
 +      struct wmGizmo *rotate_c;
 +      /* Spin angle */
 +      struct wmGizmo *angle_z;
 +
 +      /* We could store more vars here! */
 +      struct {
 +              bContext *context;
 +              wmOperatorType *ot;
 +              wmOperator *op;
 +              PropertyRNA *prop_axis_co;
 +              PropertyRNA *prop_axis_no;
 +              PropertyRNA *prop_angle;
 +
 +              float rotate_axis[3];
 +              float rotate_up[3];
 +#ifdef USE_ANGLE_Z_ORIENT
 +              float orient_axis[3];
 +#endif
 +      } data;
 +} GizmoGroupData_SpinRedo;
 +
 +/**
 + * XXX. calling redo from property updates is not great.
 + * This is needed because changing the RNA doesn't cause a redo
 + * and we're not using operator UI which does just this.
 + */
 +static void gizmo_spin_exec(GizmoGroupData_SpinRedo *ggd)
 +{
 +      wmOperator *op = ggd->data.op;
 +      if (op == WM_operator_last_redo((bContext *)ggd->data.context)) {
 +              ED_undo_operator_repeat((bContext *)ggd->data.context, op);
 +      }
 +}
 +
 +static void gizmo_mesh_spin_redo_update_from_op(GizmoGroupData_SpinRedo *ggd)
 +{
 +      wmOperator *op = ggd->data.op;
 +
 +      float plane_co[3], plane_no[3];
 +
 +      RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co);
 +      RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no);
 +
 +      WM_gizmo_set_matrix_location(ggd->translate_z, plane_co);
 +      WM_gizmo_set_matrix_location(ggd->rotate_c, plane_co);
 +      WM_gizmo_set_matrix_location(ggd->angle_z, plane_co);
 +      /* translate_c location comes from the property. */
 +
 +      WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_z, plane_no);
 +#ifdef USE_ANGLE_Z_ORIENT
 +      {
 +              float plane_tan[3];
 +              project_plane_normalized_v3_v3v3(plane_tan, ggd->data.orient_axis, plane_no);
 +              if (normalize_v3(plane_tan) != 0.0f) {
 +                      WM_gizmo_set_matrix_rotation_from_yz_axis(ggd->angle_z, plane_tan, plane_no);
 +              }
 +              else {
 +                      WM_gizmo_set_matrix_rotation_from_z_axis(ggd->angle_z, plane_no);
 +              }
 +      }
 +#else
 +      WM_gizmo_set_matrix_rotation_from_z_axis(ggd->angle_z, plane_no);
 +#endif
 +
 +      WM_gizmo_set_scale(ggd->translate_c, 0.2);
 +
 +      WM_gizmo_set_scale(ggd->angle_z, 2.0f);
 +      WM_gizmo_set_line_width(ggd->angle_z, 1.0f);
 +
 +      RegionView3D *rv3d = ED_view3d_context_rv3d(ggd->data.context);
 +      if (rv3d) {
 +              normalize_v3_v3(ggd->data.rotate_axis, rv3d->viewinv[2]);
 +              normalize_v3_v3(ggd->data.rotate_up, rv3d->viewinv[1]);
 +
 +              /* ensure its orthogonal */
 +              project_plane_normalized_v3_v3v3(ggd->data.rotate_up, ggd->data.rotate_up, ggd->data.rotate_axis);
 +              normalize_v3(ggd->data.rotate_up);
 +
 +              WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_c, plane_no);
 +              WM_gizmo_set_matrix_rotation_from_yz_axis(ggd->rotate_c, plane_no, ggd->data.rotate_axis);
 +
 +              /* show the axis instead of mouse cursor */
 +              RNA_enum_set(ggd->rotate_c->ptr, "draw_options",
 +                           ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR |
 +                           ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y);
 +
 +      }
 +}
 +
 +/* depth callbacks */
 +static void gizmo_spin_prop_depth_get(
 +        const wmGizmo *gz, wmGizmoProperty *gz_prop,
 +        void *value_p)
 +{
 +      GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
 +      wmOperator *op = ggd->data.op;
 +      float *value = value_p;
 +
 +      BLI_assert(gz_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(gz_prop);
 +
 +      float plane_co[3], plane_no[3];
 +      RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co);
 +      RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no);
 +
 +      value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]);
 +}
 +
 +static void gizmo_spin_prop_depth_set(
 +        const wmGizmo *gz, wmGizmoProperty *gz_prop,
 +        const void *value_p)
 +{
 +      GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
 +      wmOperator *op = ggd->data.op;
 +      const float *value = value_p;
 +
 +      BLI_assert(gz_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(gz_prop);
 +
 +      float plane_co[3], plane[4];
 +      RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co);
 +      RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane);
 +      normalize_v3(plane);
 +
 +      plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]);
 +
 +      /* Keep our location, may be offset simply to be inside the viewport. */
 +      closest_to_plane_normalized_v3(plane_co, plane, plane_co);
 +
 +      RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_co, plane_co);
 +
 +      gizmo_spin_exec(ggd);
 +}
 +
 +/* translate callbacks */
 +static void gizmo_spin_prop_translate_get(
 +        const wmGizmo *gz, wmGizmoProperty *gz_prop,
 +        void *value_p)
 +{
 +      GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
 +      wmOperator *op = ggd->data.op;
 +      float *value = value_p;
 +
 +      BLI_assert(gz_prop->type->array_length == 3);
 +      UNUSED_VARS_NDEBUG(gz_prop);
 +
 +      RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, value);
 +}
 +
 +static void gizmo_spin_prop_translate_set(
 +        const wmGizmo *gz, wmGizmoProperty *gz_prop,
 +        const void *value)
 +{
 +      GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
 +      wmOperator *op = ggd->data.op;
 +
 +      BLI_assert(gz_prop->type->array_length == 3);
 +      UNUSED_VARS_NDEBUG(gz_prop);
 +
 +      RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_co, value);
 +
 +      gizmo_spin_exec(ggd);
 +}
 +
 +/* angle callbacks */
 +static void gizmo_spin_prop_axis_angle_get(
 +        const wmGizmo *gz, wmGizmoProperty *gz_prop,
 +        void *value_p)
 +{
 +      GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
 +      wmOperator *op = ggd->data.op;
 +      float *value = value_p;
 +
 +      BLI_assert(gz_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(gz_prop);
 +
 +      float plane_no[4];
 +      RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no);
 +      normalize_v3(plane_no);
 +
 +      float plane_no_proj[3];
 +      project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis);
 +
 +      if (!is_zero_v3(plane_no_proj)) {
 +              const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis);
 +              value[0] = angle;
 +      }
 +      else {
 +              value[0] = 0.0f;
 +      }
 +}
 +
 +static void gizmo_spin_prop_axis_angle_set(
 +        const wmGizmo *gz, wmGizmoProperty *gz_prop,
 +        const void *value_p)
 +{
 +      GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
 +      wmOperator *op = ggd->data.op;
 +      const float *value = value_p;
 +
 +      BLI_assert(gz_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(gz_prop);
 +
 +      float plane_no[4];
 +      RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no);
 +      normalize_v3(plane_no);
 +
 +      float plane_no_proj[3];
 +      project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis);
 +
 +      if (!is_zero_v3(plane_no_proj)) {
 +              const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis);
 +              const float angle_delta = angle - angle_compat_rad(value[0], angle);
 +              if (angle_delta != 0.0f) {
 +                      float mat[3][3];
 +                      axis_angle_normalized_to_mat3(mat, ggd->data.rotate_axis, angle_delta);
 +                      mul_m3_v3(mat, plane_no);
 +
 +                      /* re-normalize - seems acceptable */
 +                      RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_no, plane_no);
 +
 +                      gizmo_spin_exec(ggd);
 +              }
 +      }
 +}
 +
 +/* angle callbacks */
 +static void gizmo_spin_prop_angle_get(
 +        const wmGizmo *gz, wmGizmoProperty *gz_prop,
 +        void *value_p)
 +{
 +      GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
 +      wmOperator *op = ggd->data.op;
 +      float *value = value_p;
 +
 +      BLI_assert(gz_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(gz_prop);
 +      value[0] = RNA_property_float_get(op->ptr, ggd->data.prop_angle);
 +}
 +
 +static void gizmo_spin_prop_angle_set(
 +        const wmGizmo *gz, wmGizmoProperty *gz_prop,
 +        const void *value_p)
 +{
 +      GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
 +      wmOperator *op = ggd->data.op;
 +      BLI_assert(gz_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(gz_prop);
 +      const float *value = value_p;
 +      RNA_property_float_set(op->ptr, ggd->data.prop_angle, value[0]);
 +
 +      gizmo_spin_exec(ggd);
 +}
 +
 +static bool gizmo_mesh_spin_redo_poll(const bContext *C, wmGizmoGroupType *gzgt)
 +{
 +      return ED_gizmo_poll_or_unlink_delayed_from_operator(C, gzgt, "MESH_OT_spin");
 +}
 +
 +
 +static void gizmo_mesh_spin_redo_modal_from_setup(
 +        const bContext *C, wmGizmoGroup *gzgroup)
 +{
 +      /* Start off dragging. */
 +      GizmoGroupData_SpinRedo *ggd = gzgroup->customdata;
 +      wmWindow *win = CTX_wm_window(C);
 +      wmGizmo *gz = ggd->angle_z;
 +      wmGizmoMap *gzmap = gzgroup->parent_gzmap;
 +
 +
 +#ifdef USE_ANGLE_Z_ORIENT
 +      {
 +              wmOperator *op = ggd->data.op;
 +              View3D *v3d = CTX_wm_view3d(C);
 +              ARegion *ar = CTX_wm_region(C);
 +              const wmEvent *event = win->eventstate;
 +              float plane_co[3], plane_no[3];
 +              RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co);
 +              RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no);
 +              float cursor_co[3];
 +              const int mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin};
 +              float plane[4];
 +              plane_from_point_normal_v3(plane, plane_co, plane_no);
++              if (UNLIKELY(!ED_view3d_win_to_3d_on_plane_int(ar, plane, mval, false, cursor_co))) {
 +                      ED_view3d_win_to_3d_int(v3d, ar, plane, mval, cursor_co);
 +              }
 +              sub_v3_v3v3(ggd->data.orient_axis, cursor_co, plane_co);
 +              normalize_v3(ggd->data.orient_axis);
 +      }
 +#endif
 +
 +      WM_gizmo_modal_set_from_setup(
 +              gzmap, (bContext *)C, gz, 0, win->eventstate);
 +}
 +
 +static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup)
 +{
 +      wmOperatorType *ot = WM_operatortype_find("MESH_OT_spin", true);
 +      wmOperator *op = WM_operator_last_redo(C);
 +
 +      if ((op == NULL) || (op->type != ot)) {
 +              return;
 +      }
 +
 +      GizmoGroupData_SpinRedo *ggd = MEM_callocN(sizeof(*ggd), __func__);
 +      gzgroup->customdata = ggd;
 +
 +      const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
 +      const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
 +      const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
 +
 +      ggd->translate_z = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
 +      ggd->translate_c = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL);
 +      ggd->rotate_c = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
 +      ggd->angle_z = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
 +
 +      UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_z->color);
 +      UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_c->color);
 +      UI_GetThemeColor3fv(TH_GIZMO_SECONDARY, ggd->rotate_c->color);
 +      copy_v3_v3(ggd->angle_z->color, ggd->angle_z->color_hi);
 +      ggd->angle_z->color[3] = 0.5f;
 +
 +      RNA_enum_set(ggd->translate_z->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL);
 +      RNA_enum_set(ggd->translate_c->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D);
 +
 +      RNA_boolean_set(ggd->angle_z->ptr, "wrap_angle", false);
 +      RNA_enum_set(ggd->angle_z->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
 +      RNA_float_set(ggd->angle_z->ptr, "arc_inner_factor", 0.9f);
 +
 +      WM_gizmo_set_flag(ggd->translate_c, WM_GIZMO_DRAW_VALUE, true);
 +      WM_gizmo_set_flag(ggd->rotate_c, WM_GIZMO_DRAW_VALUE, true);
 +      WM_gizmo_set_flag(ggd->angle_z, WM_GIZMO_DRAW_VALUE, true);
 +
 +      WM_gizmo_set_scale(ggd->rotate_c, 0.8f);
 +
 +      {
 +              ggd->data.context = (bContext *)C;
 +              ggd->data.ot = ot;
 +              ggd->data.op = op;
 +              ggd->data.prop_axis_co = RNA_struct_type_find_property(ot->srna, "center");
 +              ggd->data.prop_axis_no = RNA_struct_type_find_property(ot->srna, "axis");
 +              ggd->data.prop_angle = RNA_struct_type_find_property(ot->srna, "angle");
 +      }
 +
 +      gizmo_mesh_spin_redo_update_from_op(ggd);
 +
 +      /* Setup property callbacks */
 +      {
 +              WM_gizmo_target_property_def_func(
 +                      ggd->translate_z, "offset",
 +                      &(const struct wmGizmoPropertyFnParams) {
 +                          .value_get_fn = gizmo_spin_prop_depth_get,
 +                          .value_set_fn = gizmo_spin_prop_depth_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = NULL,
 +                      });
 +
 +              WM_gizmo_target_property_def_func(
 +                      ggd->translate_c, "offset",
 +                      &(const struct wmGizmoPropertyFnParams) {
 +                          .value_get_fn = gizmo_spin_prop_translate_get,
 +                          .value_set_fn = gizmo_spin_prop_translate_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = NULL,
 +                      });
 +
 +              WM_gizmo_target_property_def_func(
 +                      ggd->rotate_c, "offset",
 +                      &(const struct wmGizmoPropertyFnParams) {
 +                          .value_get_fn = gizmo_spin_prop_axis_angle_get,
 +                          .value_set_fn = gizmo_spin_prop_axis_angle_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = NULL,
 +                      });
 +
 +              WM_gizmo_target_property_def_func(
 +                      ggd->angle_z, "offset",
 +                      &(const struct wmGizmoPropertyFnParams) {
 +                          .value_get_fn = gizmo_spin_prop_angle_get,
 +                          .value_set_fn = gizmo_spin_prop_angle_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = NULL,
 +                      });
 +
 +      }
 +
 +#ifndef USE_EXTRA_CONTROLS
 +      /* Disable for now. */
 +      WM_gizmo_set_flag(ggd->translate_z, WM_GIZMO_HIDDEN, true);
 +      WM_gizmo_set_flag(ggd->translate_c, WM_GIZMO_HIDDEN, true);
 +      WM_gizmo_set_flag(ggd->rotate_c, WM_GIZMO_HIDDEN, true);
 +#endif
 +
 +      /* Become modal as soon as it's started. */
 +      gizmo_mesh_spin_redo_modal_from_setup(C, gzgroup);
 +}
 +
 +static void gizmo_mesh_spin_redo_draw_prepare(
 +        const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
 +{
 +      GizmoGroupData_SpinRedo *ggd = gzgroup->customdata;
 +      if (ggd->data.op->next) {
 +              ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context);
 +      }
 +      gizmo_mesh_spin_redo_update_from_op(ggd);
 +}
 +
 +void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt)
 +{
 +      gzgt->name = "Mesh Spin Redo";
 +      gzgt->idname = "MESH_GGT_spin_redo";
 +
 +      gzgt->flag = WM_GIZMOGROUPTYPE_3D;
 +
 +      gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
 +      gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
 +
 +      gzgt->poll = gizmo_mesh_spin_redo_poll;
 +      gzgt->setup = gizmo_mesh_spin_redo_setup;
 +      gzgt->draw_prepare = gizmo_mesh_spin_redo_draw_prepare;
 +}
 +
 +/** \} */
index 6e8b7c281cec1d762ac645267969adf6d1149cd6,3cc0857c8a79c745d649817d7da072556cfe5f63..116f4af34e57b3c3da493b570e2b00c41048f559
  
  #include "BLI_sys_types.h"  /* int64_t */
  
 -#include "BIF_gl.h"  /* bglMats */
 -#include "BIF_glutil.h"  /* bglMats */
 -
  #include "BLI_math_vector.h"
  
  #include "BKE_camera.h"
  #include "BKE_screen.h"
  
 +#include "GPU_matrix.h"
 +
  #include "ED_view3d.h"  /* own include */
  
  #define BL_NEAR_CLIP 0.001
@@@ -314,7 -315,6 +314,7 @@@ float ED_view3d_calc_zfac(const RegionV
  }
  
  static void view3d_win_to_ray_segment(
 +        struct Depsgraph *depsgraph,
          const ARegion *ar, const View3D *v3d, const float mval[2],
          float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
  {
                start_offset = -end_offset;
        }
        else {
 -              ED_view3d_clip_range_get(v3d, rv3d, &start_offset, &end_offset, false);
 +              ED_view3d_clip_range_get(depsgraph, v3d, rv3d, &start_offset, &end_offset, false);
        }
  
        if (r_ray_start) {
@@@ -371,13 -371,12 +371,13 @@@ bool ED_view3d_clip_segment(const Regio
   * \return success, false if the ray is totally clipped.
   */
  bool ED_view3d_win_to_ray_clipped_ex(
 +        struct Depsgraph *depsgraph,
          const ARegion *ar, const View3D *v3d, const float mval[2],
          float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip_planes)
  {
        float ray_end[3];
  
 -      view3d_win_to_ray_segment(ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end);
 +      view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end);
  
        /* bounds clipping */
        if (do_clip_planes) {
   * \return success, false if the ray is totally clipped.
   */
  bool ED_view3d_win_to_ray_clipped(
 +        struct Depsgraph *depsgraph,
          const ARegion *ar, const View3D *v3d, const float mval[2],
          float r_ray_start[3], float r_ray_normal[3], const bool do_clip_planes)
  {
 -      return ED_view3d_win_to_ray_clipped_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip_planes);
 +      return ED_view3d_win_to_ray_clipped_ex(depsgraph, ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip_planes);
  }
  
  /**
@@@ -559,14 -557,14 +559,14 @@@ void ED_view3d_win_to_3d_int
  
  bool ED_view3d_win_to_3d_on_plane(
          const ARegion *ar,
-         const float plane[4], const float mval[2],
+         const float plane[4], const float mval[2], const bool do_clip,
          float r_out[3])
  {
        float ray_co[3], ray_no[3];
        ED_view3d_win_to_origin(ar, mval, ray_co);
        ED_view3d_win_to_vector(ar, mval, ray_no);
        float lambda;
-       if (isect_ray_plane_v3(ray_co, ray_no, plane, &lambda, false)) {
+       if (isect_ray_plane_v3(ray_co, ray_no, plane, &lambda, do_clip)) {
                madd_v3_v3v3fl(r_out, ray_co, ray_no, lambda);
                return true;
        }
  
  bool ED_view3d_win_to_3d_on_plane_int(
          const ARegion *ar,
-         const float plane[4], const int mval[2],
+         const float plane[4], const int mval[2], const bool do_clip,
          float r_out[3])
  {
        const float mval_fl[2] = {mval[0], mval[1]};
-       return ED_view3d_win_to_3d_on_plane(ar, plane, mval_fl, r_out);
+       return ED_view3d_win_to_3d_on_plane(ar, plane, mval_fl, do_clip, r_out);
  }
  
  /**
@@@ -679,11 -677,10 +679,11 @@@ void ED_view3d_win_to_vector(const AReg
   * \return success, false if the segment is totally clipped.
   */
  bool ED_view3d_win_to_segment_clipped(
 +        struct Depsgraph *depsgraph,
          const ARegion *ar, View3D *v3d, const float mval[2],
          float r_ray_start[3], float r_ray_end[3], const bool do_clip_planes)
  {
 -      view3d_win_to_ray_segment(ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end);
 +      view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end);
  
        /* bounds clipping */
        if (do_clip_planes) {
@@@ -713,22 -710,16 +713,22 @@@ void ED_view3d_ob_project_mat_get_from_
  }
  
  /**
 - * Uses window coordinates (x,y) and depth component z to find a point in
 - * modelspace */
 -void ED_view3d_unproject(bglMats *mats, float out[3], const float x, const float y, const float z)
 + * Convert between region relative coordinates (x,y) and depth component z and
 + * a point in world space. */
 +void ED_view3d_project(const struct ARegion *ar, const float world[3], float region[3])
  {
 -      double ux, uy, uz;
 +      // viewport is set up to make coordinates relative to the region, not window
 +      RegionView3D *rv3d = ar->regiondata;
 +      int viewport[4] = {0, 0, ar->winx, ar->winy};
  
 -      gluUnProject(x, y, z, mats->modelview, mats->projection,
 -                   (GLint *)mats->viewport, &ux, &uy, &uz);
 +      GPU_matrix_project(world, rv3d->viewmat, rv3d->winmat, viewport, region);
 +}
 +
 +bool ED_view3d_unproject(const struct ARegion *ar, float regionx, float regiony, float regionz, float world[3])
 +{
 +      RegionView3D *rv3d = ar->regiondata;
 +      int viewport[4] = {0, 0, ar->winx, ar->winy};
 +      float region[3] = {regionx, regiony, regionz};
  
 -      out[0] = ux;
 -      out[1] = uy;
 -      out[2] = uz;
 +      return GPU_matrix_unproject(region, rv3d->viewmat, rv3d->winmat, viewport, world);
  }