Merge remote-tracking branch 'origin/master' into blender2.8
authorDalai Felinto <dfelinto@gmail.com>
Wed, 10 May 2017 15:03:27 +0000 (17:03 +0200)
committerDalai Felinto <dfelinto@gmail.com>
Wed, 10 May 2017 15:03:27 +0000 (17:03 +0200)
1  2 
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c

index 980f243b23e5155faa458ec0c5b2a13d52322d2f,d42c57e7d8e220b070440c6fc6652f3f6798e1a4..9c18d5d90a0e5128eda4c3f7f12bc156603ba56d
  #include "view3d_intern.h"  /* own include */
  
  /* prototypes */
 -static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d);
 -static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect);
 -static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
 -                                            float winmat[4][4], const char *viewname);
 -
 -/* handy utility for drawing shapes in the viewport for arbitrary code.
 - * could add lines and points too */
 -// #define DEBUG_DRAW
 -#ifdef DEBUG_DRAW
 -static void bl_debug_draw(void);
 -/* add these locally when using these functions for testing */
 -extern void bl_debug_draw_quad_clear(void);
 -extern void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]);
 -extern void bl_debug_draw_edge_add(const float v0[3], const float v1[3]);
 -extern void bl_debug_color_set(const unsigned int col);
 -#endif
 +static void draw_all_objects(const bContext *C, ARegion *ar, const bool only_depth, const bool use_depth);
- static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d);
  
 -void circf(float x, float y, float rad)
 -{
 -      GLUquadricObj *qobj = gluNewQuadric(); 
 -      
 -      gluQuadricDrawStyle(qobj, GLU_FILL); 
 -      
 -      glPushMatrix(); 
 -      
 -      glTranslatef(x, y, 0.0);
 -      
 -      gluDisk(qobj, 0.0,  rad, 32, 1);
 -      
 -      glPopMatrix(); 
 -      
 -      gluDeleteQuadric(qobj);
 -}
 +typedef struct DrawData {
 +      rcti border_rect;
 +      bool render_border;
 +      bool clip_border;
 +      bool is_render;
 +      GPUViewport *viewport;
 +} DrawData;
  
 -void circ(float x, float y, float rad)
 +static void view3d_draw_data_init(const bContext *C, ARegion *ar, RegionView3D *rv3d, DrawData *draw_data)
  {
 -      GLUquadricObj *qobj = gluNewQuadric(); 
 -      
 -      gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); 
 -      
 -      glPushMatrix(); 
 -      
 -      glTranslatef(x, y, 0.0);
 -      
 -      gluDisk(qobj, 0.0,  rad, 32, 1);
 -      
 -      glPopMatrix(); 
 -      
 -      gluDeleteQuadric(qobj);
 -}
 -
 +      Scene *scene = CTX_data_scene(C);
 +      View3D *v3d = CTX_wm_view3d(C);
  
 -/* ********* custom clipping *********** */
 +      draw_data->is_render = (v3d->drawtype == OB_RENDER);
  
 -static void view3d_draw_clipping(RegionView3D *rv3d)
 -{
 -      BoundBox *bb = rv3d->clipbb;
 -
 -      if (bb) {
 -              const unsigned int clipping_index[6][4] = {
 -                      {0, 1, 2, 3},
 -                      {0, 4, 5, 1},
 -                      {4, 7, 6, 5},
 -                      {7, 3, 2, 6},
 -                      {1, 5, 6, 2},
 -                      {7, 4, 0, 3}
 -              };
 -
 -              /* fill in zero alpha for rendering & re-projection [#31530] */
 -              unsigned char col[4];
 -              UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col);
 -              glColor4ubv(col);
 -
 -              glEnable(GL_BLEND);
 -              glEnableClientState(GL_VERTEX_ARRAY);
 -              glVertexPointer(3, GL_FLOAT, 0, bb->vec);
 -              glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index);
 -              glDisableClientState(GL_VERTEX_ARRAY);
 -              glDisable(GL_BLEND);
 -      }
 -}
 +      draw_data->render_border = ED_view3d_calc_render_border(scene, v3d, ar, &draw_data->border_rect);
 +      draw_data->clip_border = (draw_data->render_border && !BLI_rcti_compare(&ar->drawrct, &draw_data->border_rect));
  
 -void ED_view3d_clipping_set(RegionView3D *rv3d)
 -{
 -      double plane[4];
 -      const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6;
 -      unsigned int a;
 -
 -      for (a = 0; a < tot; a++) {
 -              copy_v4db_v4fl(plane, rv3d->clip[a]);
 -              glClipPlane(GL_CLIP_PLANE0 + a, plane);
 -              glEnable(GL_CLIP_PLANE0 + a);
 -      }
 +      draw_data->viewport = rv3d->viewport;
  }
  
 -/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */
 -void ED_view3d_clipping_disable(void)
 -{
 -      unsigned int a;
 +/* ******************** general functions ***************** */
  
 -      for (a = 0; a < 6; a++) {
 -              glDisable(GL_CLIP_PLANE0 + a);
 -      }
 -}
 -void ED_view3d_clipping_enable(void)
 +static bool use_depth_doit(Scene *scene, View3D *v3d)
  {
 -      unsigned int a;
 +      if (v3d->drawtype > OB_WIRE)
 +              return true;
  
 -      for (a = 0; a < 6; a++) {
 -              glEnable(GL_CLIP_PLANE0 + a);
 +      /* special case (depth for wire color) */
 +      if (v3d->drawtype <= OB_WIRE) {
 +              if (scene->obedit && scene->obedit->type == OB_MESH) {
 +                      Mesh *me = scene->obedit->data;
 +                      if (me->drawflag & ME_DRAWEIGHT) {
 +                              return true;
 +                      }
 +              }
        }
 +      return false;
  }
  
 -static bool view3d_clipping_test(const float co[3], const float clip[6][4])
 +static bool use_depth(const bContext *C)
  {
 -      if (plane_point_side_v3(clip[0], co) > 0.0f)
 -              if (plane_point_side_v3(clip[1], co) > 0.0f)
 -                      if (plane_point_side_v3(clip[2], co) > 0.0f)
 -                              if (plane_point_side_v3(clip[3], co) > 0.0f)
 -                                      return false;
 -
 -      return true;
 +      View3D *v3d = CTX_wm_view3d(C);
 +      Scene *scene = CTX_data_scene(C);
 +      return use_depth_doit(scene, v3d);
  }
  
 -/* for 'local' ED_view3d_clipping_local must run first
 - * then all comparisons can be done in localspace */
 -bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
 +/**
 + * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
 + */
 +void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect)
  {
 -      return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
 -}
 +      RegionView3D *rv3d = ar->regiondata;
  
 -/* ********* end custom clipping *********** */
  
 +      /* setup window matrices */
 +      if (winmat)
 +              copy_m4_m4(rv3d->winmat, winmat);
 +      else
 +              view3d_winmatrix_set(ar, v3d, rect);
  
 -static void drawgrid_draw(ARegion *ar, double wx, double wy, double x, double y, double dx)
 -{     
 -      double verts[2][2];
 +      /* setup view matrix */
 +      if (viewmat)
 +              copy_m4_m4(rv3d->viewmat, viewmat);
 +      else
 +              view3d_viewmatrix_set(scene, v3d, rv3d);  /* note: calls BKE_object_where_is_calc for camera... */
  
 -      x += (wx);
 -      y += (wy);
 +      /* update utility matrices */
 +      mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
 +      invert_m4_m4(rv3d->persinv, rv3d->persmat);
 +      invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
  
 -      /* set fixed 'Y' */
 -      verts[0][1] = 0.0f;
 -      verts[1][1] = (double)ar->winy;
 +      /* calculate GLSL view dependent values */
  
 -      /* iter over 'X' */
 -      verts[0][0] = verts[1][0] = x - dx * floor(x / dx);
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glVertexPointer(2, GL_DOUBLE, 0, verts);
 +      /* store window coordinates scaling/offset */
 +      if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
 +              rctf cameraborder;
 +              ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false);
 +              rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder);
 +              rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder);
  
 -      while (verts[0][0] < ar->winx) {
 -              glDrawArrays(GL_LINES, 0, 2);
 -              verts[0][0] = verts[1][0] = verts[0][0] + dx;
 +              rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx;
 +              rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy;
 +      }
 +      else {
 +              rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
 +              rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
        }
  
 -      /* set fixed 'X' */
 -      verts[0][0] = 0.0f;
 -      verts[1][0] = (double)ar->winx;
 +      /* calculate pixelsize factor once, is used for lamps and obcenters */
 +      {
 +              /* note:  '1.0f / len_v3(v1)'  replaced  'len_v3(rv3d->viewmat[0])'
 +               * because of float point precision problems at large values [#23908] */
 +              float v1[3], v2[3];
 +              float len_px, len_sc;
  
 -      /* iter over 'Y' */
 -      verts[0][1] = verts[1][1] = y - dx * floor(y / dx);
 -      while (verts[0][1] < ar->winy) {
 -              glDrawArrays(GL_LINES, 0, 2);
 -              verts[0][1] = verts[1][1] = verts[0][1] + dx;
 -      }
 +              v1[0] = rv3d->persmat[0][0];
 +              v1[1] = rv3d->persmat[1][0];
 +              v1[2] = rv3d->persmat[2][0];
  
 -      glDisableClientState(GL_VERTEX_ARRAY);
 -}
 +              v2[0] = rv3d->persmat[0][1];
 +              v2[1] = rv3d->persmat[1][1];
 +              v2[2] = rv3d->persmat[2][1];
  
 -#define GRID_MIN_PX_D   6.0
 -#define GRID_MIN_PX_F 6.0f
 +              len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
 +              len_sc = (float)MAX2(ar->winx, ar->winy);
  
 -static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit)
 +              rv3d->pixsize = len_px / len_sc;
 +      }
 +}
 +
 +static void view3d_main_region_setup_view(
 +        Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect)
  {
 -      /* extern short bgpicmode; */
        RegionView3D *rv3d = ar->regiondata;
 -      double wx, wy, x, y, fw, fx, fy, dx;
 -      double vec4[4];
 -      unsigned char col[3], col2[3];
  
 -      fx = rv3d->persmat[3][0];
 -      fy = rv3d->persmat[3][1];
 -      fw = rv3d->persmat[3][3];
 +      ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat, rect);
  
 -      wx = (ar->winx / 2.0); /* because of rounding errors, grid at wrong location */
 -      wy = (ar->winy / 2.0);
 +      /* set for opengl */
 +      gpuLoadProjectionMatrix(rv3d->winmat);
 +      gpuLoadMatrix(rv3d->viewmat);
 +}
  
 -      x = (wx) * fx / fw;
 -      y = (wy) * fy / fw;
 +static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d)
 +{
 +      if ((scene->r.scemode & R_MULTIVIEW) == 0) {
 +              return false;
 +      }
  
 -      vec4[0] = vec4[1] = v3d->grid;
 +      if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) {
 +              return false;
 +      }
  
 -      vec4[2] = 0.0;
 -      vec4[3] = 1.0;
 -      mul_m4_v4d(rv3d->persmat, vec4);
 -      fx = vec4[0];
 -      fy = vec4[1];
 -      fw = vec4[3];
 +      switch (v3d->stereo3d_camera) {
 +              case STEREO_MONO_ID:
 +                      return false;
 +                      break;
 +              case STEREO_3D_ID:
 +                      /* win will be NULL when calling this from the selection or draw loop. */
 +                      if ((win == NULL) || (WM_stereo3d_enabled(win, true) == false)) {
 +                              return false;
 +                      }
 +                      if (((scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) != 0) &&
 +                          !BKE_scene_multiview_is_stereo3d(&scene->r))
 +                      {
 +                              return false;
 +                      }
 +                      break;
 +              /* We always need the stereo calculation for left and right cameras. */
 +              case STEREO_LEFT_ID:
 +              case STEREO_RIGHT_ID:
 +              default:
 +                      break;
 +      }
 +      return true;
 +}
  
 -      dx = fabs(x - (wx) * fx / fw);
 -      if (dx == 0) dx = fabs(y - (wy) * fy / fw);
 -      
 -      glLineWidth(1.0f);
  
 -      glDepthMask(GL_FALSE);     /* disable write in zbuffer */
 +/* setup the view and win matrices for the multiview cameras
 + *
 + * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called
 + * we have no winmatrix (i.e., projection matrix) defined at that time.
 + * Since the camera and the camera shift are needed for the winmat calculation
 + * we do a small hack to replace it temporarily so we don't need to change the
 + * view3d)main_region_setup_view() code to account for that.
 + */
 +static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect)
 +{
 +      bool is_left;
 +      const char *names[2] = { STEREO_LEFT_NAME, STEREO_RIGHT_NAME };
 +      const char *viewname;
  
 -      /* check zoom out */
 -      UI_ThemeColor(TH_GRID);
 -      
 -      if (unit->system) {
 -              /* Use GRID_MIN_PX * 2 for units because very very small grid
 -               * items are less useful when dealing with units */
 -              const void *usys;
 -              int len, i;
 -              double dx_scalar;
 -              float blend_fac;
 +      /* show only left or right camera */
 +      if (v3d->stereo3d_camera != STEREO_3D_ID)
 +              v3d->multiview_eye = v3d->stereo3d_camera;
  
 -              bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len);
 +      is_left = v3d->multiview_eye == STEREO_LEFT_ID;
 +      viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID];
  
 -              if (usys) {
 -                      i = len;
 -                      while (i--) {
 -                              double scalar = bUnit_GetScaler(usys, i);
 +      /* update the viewport matrices with the new camera */
 +      if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
 +              Camera *data;
 +              float viewmat[4][4];
 +              float shiftx;
  
 -                              dx_scalar = dx * scalar / (double)unit->scale_length;
 -                              if (dx_scalar < (GRID_MIN_PX_D * 2.0))
 -                                      continue;
 +              data = (Camera *)v3d->camera->data;
 +              shiftx = data->shiftx;
  
 -                              /* Store the smallest drawn grid size units name so users know how big each grid cell is */
 -                              if (*grid_unit == NULL) {
 -                                      *grid_unit = bUnit_GetNameDisplay(usys, i);
 -                                      rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length);
 -                              }
 -                              blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar);
 +              BLI_lock_thread(LOCK_VIEW3D);
 +              data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
  
 -                              /* tweak to have the fade a bit nicer */
 -                              blend_fac = (blend_fac * blend_fac) * 2.0f;
 -                              CLAMP(blend_fac, 0.3f, 1.0f);
 +              BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
 +              view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect);
 +
 +              data->shiftx = shiftx;
 +              BLI_unlock_thread(LOCK_VIEW3D);
 +      }
 +      else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
 +              float viewmat[4][4];
 +              Object *view_ob = v3d->camera;
 +              Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
  
 +              BLI_lock_thread(LOCK_VIEW3D);
 +              v3d->camera = camera;
  
 -                              UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, blend_fac);
 +              BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
 +              view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect);
  
 -                              drawgrid_draw(ar, wx, wy, x, y, dx_scalar);
 -                      }
 -              }
 +              v3d->camera = view_ob;
 +              BLI_unlock_thread(LOCK_VIEW3D);
 +      }
 +}
 +
 +/**
 + * Set the correct matrices
 + */
 +void ED_view3d_draw_setup_view(
 +        wmWindow *win, Scene *scene, ARegion *ar, View3D *v3d,
 +        float viewmat[4][4], float winmat[4][4], const rcti *rect)
 +{
 +      RegionView3D *rv3d = ar->regiondata;
 +
 +      /* Setup the view matrix. */
 +      if (view3d_stereo3d_active(win, scene, v3d, rv3d)) {
 +              view3d_stereo3d_setup(scene, v3d, ar, rect);
        }
        else {
 -              const double sublines    = v3d->gridsubdiv;
 -              const float  sublines_fl = v3d->gridsubdiv;
 +              view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, rect);
 +      }
 +}
  
 -              if (dx < GRID_MIN_PX_D) {
 -                      rv3d->gridview *= sublines_fl;
 -                      dx *= sublines;
 +/* ******************** debug ***************** */
  
 -                      if (dx < GRID_MIN_PX_D) {
 -                              rv3d->gridview *= sublines_fl;
 -                              dx *= sublines;
 +#define VIEW3D_DRAW_DEBUG 1
 +/* TODO: expand scope of this flag so UI reflects the underlying code */
  
 -                              if (dx < GRID_MIN_PX_D) {
 -                                      rv3d->gridview *= sublines_fl;
 -                                      dx *= sublines;
 -                                      if (dx < GRID_MIN_PX_D) {
 -                                              /* pass */
 -                                      }
 -                                      else {
 -                                              UI_ThemeColor(TH_GRID);
 -                                              drawgrid_draw(ar, wx, wy, x, y, dx);
 -                                      }
 -                              }
 -                              else {  /* start blending out */
 -                                      UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
 -                                      drawgrid_draw(ar, wx, wy, x, y, dx);
 +#if VIEW3D_DRAW_DEBUG
  
 -                                      UI_ThemeColor(TH_GRID);
 -                                      drawgrid_draw(ar, wx, wy, x, y, sublines * dx);
 -                              }
 -                      }
 -                      else {  /* start blending out (GRID_MIN_PX < dx < (GRID_MIN_PX * 10)) */
 -                              UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
 -                              drawgrid_draw(ar, wx, wy, x, y, dx);
 +static void view3d_draw_debug_store_depth(ARegion *UNUSED(ar), DrawData *draw_data)
 +{
 +      GPUViewport *viewport = draw_data->viewport;
 +      GLint viewport_size[4];
 +      glGetIntegerv(GL_VIEWPORT, viewport_size);
  
 -                              UI_ThemeColor(TH_GRID);
 -                              drawgrid_draw(ar, wx, wy, x, y, sublines * dx);
 -                      }
 -              }
 -              else {
 -                      if (dx > (GRID_MIN_PX_D * 10.0)) {  /* start blending in */
 -                              rv3d->gridview /= sublines_fl;
 -                              dx /= sublines;
 -                              if (dx > (GRID_MIN_PX_D * 10.0)) {  /* start blending in */
 -                                      rv3d->gridview /= sublines_fl;
 -                                      dx /= sublines;
 -                                      if (dx > (GRID_MIN_PX_D * 10.0)) {
 -                                              UI_ThemeColor(TH_GRID);
 -                                              drawgrid_draw(ar, wx, wy, x, y, dx);
 -                                      }
 -                                      else {
 -                                              UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
 -                                              drawgrid_draw(ar, wx, wy, x, y, dx);
 -                                              UI_ThemeColor(TH_GRID);
 -                                              drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
 -                                      }
 -                              }
 -                              else {
 -                                      UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
 -                                      drawgrid_draw(ar, wx, wy, x, y, dx);
 -                                      UI_ThemeColor(TH_GRID);
 -                                      drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
 -                              }
 -                      }
 -                      else {
 -                              UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
 -                              drawgrid_draw(ar, wx, wy, x, y, dx);
 -                              UI_ThemeColor(TH_GRID);
 -                              drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
 -                      }
 +      const int x = viewport_size[0];
 +      const int y = viewport_size[1];
 +      const int w = viewport_size[2];
 +      const int h = viewport_size[3];
 +
 +      if (GPU_viewport_debug_depth_is_valid(viewport)) {
 +              if ((GPU_viewport_debug_depth_width(viewport) != w) ||
 +                  (GPU_viewport_debug_depth_height(viewport) != h))
 +              {
 +                      GPU_viewport_debug_depth_free(viewport);
                }
        }
  
index 1b8300487efd9cf58ada12efd2ea0044afd169df,88315927b421582e1ff36eac3af33031dda2b5ec..6f2b3d761bf54dfe2bd8056f6487f7a33a6e7b5f
@@@ -1171,8 -1172,8 +1171,8 @@@ int view3d_opengl_select
  
        G.f |= G_PICKSEL;
  
-       ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, &rect);
+       ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, NULL, NULL, &rect);
 -
 +      
        if (v3d->drawtype > OB_WIRE) {
                v3d->zbuf = true;
                glEnable(GL_DEPTH_TEST);
index 425ae9979ae5e96b9b00217da4830f2e480d1e62,0000000000000000000000000000000000000000..cfc393c30b314bfdeed415f27862ce3c45fba4ad
mode 100644,000000..100644
--- /dev/null
@@@ -1,771 -1,0 +1,769 @@@
-       extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rcti *rect);
 +/*
 + * ***** 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 blender/windowmanager/manipulators/intern/wm_manipulatormap.c
 + *  \ingroup wm
 + */
 +
 +#include <string.h>
 +
 +#include "BKE_context.h"
 +
 +#include "BLI_listbase.h"
 +#include "BLI_math.h"
 +#include "BLI_string.h"
 +#include "BLI_ghash.h"
 +
 +#include "DNA_manipulator_types.h"
 +
 +#include "ED_screen.h"
 +#include "ED_view3d.h"
 +
 +#include "GPU_glew.h"
 +#include "GPU_matrix.h"
 +#include "GPU_select.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +#include "wm_event_system.h"
 +
 +/* own includes */
 +#include "wm_manipulator_wmapi.h"
 +#include "wm_manipulator_intern.h"
 +
 +/**
 + * Store all manipulator-maps here. Anyone who wants to register a manipulator for a certain
 + * area type can query the manipulator-map to do so.
 + */
 +static ListBase manipulatormaptypes = {NULL, NULL};
 +
 +/**
 + * Manipulator-map update tagging.
 + */
 +enum eManipulatorMapUpdateFlags {
 +      /* Tag manipulator-map for refresh. */
 +      MANIPULATORMAP_REFRESH = (1 << 0),
 +};
 +
 +
 +/* -------------------------------------------------------------------- */
 +/** \name wmManipulatorMap
 + *
 + * \{ */
 +
 +/**
 + * Creates a manipulator-map with all registered manipulators for that type
 + */
 +wmManipulatorMap *WM_manipulatormap_new_from_type(const struct wmManipulatorMapType_Params *mmap_params)
 +{
 +      wmManipulatorMapType *mmaptype = WM_manipulatormaptype_ensure(mmap_params);
 +      wmManipulatorMap *mmap;
 +
 +      mmap = MEM_callocN(sizeof(wmManipulatorMap), "ManipulatorMap");
 +      mmap->type = mmaptype;
 +      mmap->update_flag = MANIPULATORMAP_REFRESH;
 +
 +      /* create all manipulator-groups for this manipulator-map. We may create an empty one
 +       * too in anticipation of manipulators from operators etc */
 +      for (wmManipulatorGroupType *mgrouptype = mmaptype->manipulator_grouptypes.first;
 +           mgrouptype;
 +           mgrouptype = mgrouptype->next)
 +      {
 +              wmManipulatorGroup *mgroup = wm_manipulatorgroup_new_from_type(mgrouptype);
 +              BLI_addtail(&mmap->manipulator_groups, mgroup);
 +      }
 +
 +      return mmap;
 +}
 +
 +void wm_manipulatormap_selected_delete(wmManipulatorMap *mmap)
 +{
 +      MEM_SAFE_FREE(mmap->mmap_context.selected_manipulator);
 +      mmap->mmap_context.tot_selected = 0;
 +}
 +
 +void wm_manipulatormap_delete(wmManipulatorMap *mmap)
 +{
 +      if (!mmap)
 +              return;
 +
 +      for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first, *mgroup_next; mgroup; mgroup = mgroup_next) {
 +              mgroup_next = mgroup->next;
 +              wm_manipulatorgroup_free(NULL, mmap, mgroup);
 +      }
 +      BLI_assert(BLI_listbase_is_empty(&mmap->manipulator_groups));
 +
 +      wm_manipulatormap_selected_delete(mmap);
 +
 +      MEM_freeN(mmap);
 +}
 +
 +/**
 + * Creates and returns idname hash table for (visible) manipulators in \a mmap
 + *
 + * \param poll  Polling function for excluding manipulators.
 + * \param data  Custom data passed to \a poll
 + */
 +static GHash *WM_manipulatormap_manipulator_hash_new(
 +        const bContext *C, wmManipulatorMap *mmap,
 +        bool (*poll)(const wmManipulator *, void *),
 +        void *data, const bool include_hidden)
 +{
 +      GHash *hash = BLI_ghash_str_new(__func__);
 +
 +      /* collect manipulators */
 +      for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
 +              if (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type)) {
 +                      for (wmManipulator *manipulator = mgroup->manipulators.first;
 +                           manipulator;
 +                           manipulator = manipulator->next)
 +                      {
 +                              if ((include_hidden || (manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) &&
 +                                  (!poll || poll(manipulator, data)))
 +                              {
 +                                      BLI_ghash_insert(hash, manipulator->idname, manipulator);
 +                              }
 +                      }
 +              }
 +      }
 +
 +      return hash;
 +}
 +
 +void WM_manipulatormap_tag_refresh(wmManipulatorMap *mmap)
 +{
 +      if (mmap) {
 +              mmap->update_flag |= MANIPULATORMAP_REFRESH;
 +      }
 +}
 +
 +static void manipulatormap_tag_updated(wmManipulatorMap *mmap)
 +{
 +      mmap->update_flag = 0;
 +}
 +
 +static bool manipulator_prepare_drawing(
 +        wmManipulatorMap *mmap, wmManipulator *manipulator,
 +        const bContext *C, ListBase *draw_manipulators)
 +{
 +      if (!wm_manipulator_is_visible(manipulator)) {
 +              /* skip */
 +      }
 +      else {
 +              wm_manipulator_update(manipulator, C, (mmap->update_flag & MANIPULATORMAP_REFRESH) != 0);
 +              BLI_addhead(draw_manipulators, BLI_genericNodeN(manipulator));
 +              return true;
 +      }
 +
 +      return false;
 +}
 +
 +/**
 + * Update manipulators of \a mmap to prepare for drawing. Adds all manipulators that
 + * should be drawn to list \a draw_manipulators, note that added items need freeing.
 + */
 +static void manipulatormap_prepare_drawing(
 +        wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators, const int drawstep)
 +{
 +      if (!mmap || BLI_listbase_is_empty(&mmap->manipulator_groups))
 +              return;
 +      wmManipulator *active_manipulator = mmap->mmap_context.active_manipulator;
 +
 +      /* only active manipulator needs updating */
 +      if (active_manipulator) {
 +              if (manipulator_prepare_drawing(mmap, active_manipulator, C, draw_manipulators)) {
 +                      manipulatormap_tag_updated(mmap);
 +              }
 +              /* don't draw any other manipulators */
 +              return;
 +      }
 +
 +      for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
 +              /* check group visibility - drawstep first to avoid unnecessary call of group poll callback */
 +              if (!wm_manipulatorgroup_is_visible_in_drawstep(mgroup, drawstep) ||
 +                  !wm_manipulatorgroup_is_visible(mgroup, C))
 +              {
 +                      continue;
 +              }
 +
 +              /* needs to be initialized on first draw */
 +              wm_manipulatorgroup_ensure_initialized(mgroup, C);
 +              /* update data if needed */
 +              /* XXX weak: Manipulator-group may skip refreshing if it's invisible (map gets untagged nevertheless) */
 +              if (mmap->update_flag & MANIPULATORMAP_REFRESH && mgroup->type->refresh) {
 +                      mgroup->type->refresh(C, mgroup);
 +              }
 +              /* prepare drawing */
 +              if (mgroup->type->draw_prepare) {
 +                      mgroup->type->draw_prepare(C, mgroup);
 +              }
 +
 +              for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) {
 +                      manipulator_prepare_drawing(mmap, manipulator, C, draw_manipulators);
 +              }
 +      }
 +
 +      manipulatormap_tag_updated(mmap);
 +}
 +
 +/**
 + * Draw all visible manipulators in \a mmap.
 + * Uses global draw_manipulators listbase.
 + */
 +static void manipulators_draw_list(const wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators)
 +{
 +      if (!mmap)
 +              return;
 +      BLI_assert(!BLI_listbase_is_empty(&mmap->manipulator_groups));
 +
 +      const bool draw_multisample = (U.ogl_multisamples != USER_MULTISAMPLE_NONE);
 +
 +      /* TODO this will need it own shader probably? don't think it can be handled from that point though. */
 +/*    const bool use_lighting = (U.manipulator_flag & V3D_SHADED_MANIPULATORS) != 0; */
 +
 +      /* enable multisampling */
 +      if (draw_multisample) {
 +              glEnable(GL_MULTISAMPLE);
 +      }
 +
 +      /* draw_manipulators contains all visible manipulators - draw them */
 +      for (LinkData *link = draw_manipulators->first, *link_next; link; link = link_next) {
 +              wmManipulator *manipulator = link->data;
 +              link_next = link->next;
 +
 +              manipulator->draw(C, manipulator);
 +              /* free/remove manipulator link after drawing */
 +              BLI_freelinkN(draw_manipulators, link);
 +      }
 +
 +      if (draw_multisample) {
 +              glDisable(GL_MULTISAMPLE);
 +      }
 +}
 +
 +void WM_manipulatormap_draw(wmManipulatorMap *mmap, const bContext *C, const int drawstep)
 +{
 +      ListBase draw_manipulators = {NULL};
 +
 +      manipulatormap_prepare_drawing(mmap, C, &draw_manipulators, drawstep);
 +      manipulators_draw_list(mmap, C, &draw_manipulators);
 +      BLI_assert(BLI_listbase_is_empty(&draw_manipulators));
 +}
 +
 +static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible_manipulators)
 +{
 +      int selectionbase = 0;
 +      wmManipulator *manipulator;
 +
 +      for (LinkData *link = visible_manipulators->first; link; link = link->next) {
 +              manipulator = link->data;
 +              /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected manipulator part id */
 +              manipulator->render_3d_intersection(C, manipulator, selectionbase << 8);
 +
 +              selectionbase++;
 +      }
 +}
 +
 +static int manipulator_find_intersected_3D_intern(
 +        ListBase *visible_manipulators, const bContext *C, const int co[2],
 +        const float hotspot)
 +{
 +      ScrArea *sa = CTX_wm_area(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      View3D *v3d = sa->spacedata.first;
 +      rcti rect;
 +      GLuint buffer[64];      // max 4 items per select, so large enuf
 +      short hits;
 +      const bool do_passes = GPU_select_query_check_active();
 +
 +      rect.xmin = co[0] - hotspot;
 +      rect.xmax = co[0] + hotspot;
 +      rect.ymin = co[1] - hotspot;
 +      rect.ymax = co[1] + hotspot;
 +
 +      ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, &rect);
 +
 +      if (do_passes)
 +              GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
 +      else
 +              GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_ALL, 0);
 +      /* do the drawing */
 +      manipulator_find_active_3D_loop(C, visible_manipulators);
 +
 +      hits = GPU_select_end();
 +
 +      if (do_passes) {
 +              GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
 +              manipulator_find_active_3D_loop(C, visible_manipulators);
 +              GPU_select_end();
 +      }
 +
 +      ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, NULL);
 +
 +      return hits > 0 ? buffer[3] : -1;
 +}
 +
 +/**
 + * Try to find a 3D manipulator at screen-space coordinate \a co. Uses OpenGL picking.
 + */
 +static wmManipulator *manipulator_find_intersected_3D(
 +        bContext *C, const int co[2], ListBase *visible_manipulators,
 +        unsigned char *part)
 +{
 +      wmManipulator *result = NULL;
 +      const float hotspot = 14.0f;
 +      int ret;
 +
 +      *part = 0;
 +      /* set up view matrices */
 +      view3d_operator_needs_opengl(C);
 +
 +      ret = manipulator_find_intersected_3D_intern(visible_manipulators, C, co, 0.5f * hotspot);
 +
 +      if (ret != -1) {
 +              LinkData *link;
 +              int retsec;
 +              retsec = manipulator_find_intersected_3D_intern(visible_manipulators, C, co, 0.2f * hotspot);
 +
 +              if (retsec != -1)
 +                      ret = retsec;
 +
 +              link = BLI_findlink(visible_manipulators, ret >> 8);
 +              *part = ret & 255;
 +              result = link->data;
 +      }
 +
 +      return result;
 +}
 +
 +/**
 + * Try to find a manipulator under the mouse position. 2D intersections have priority over
 + * 3D ones (could check for smallest screen-space distance but not needed right now).
 + */
 +wmManipulator *wm_manipulatormap_find_highlighted_manipulator(
 +        wmManipulatorMap *mmap, bContext *C, const wmEvent *event,
 +        unsigned char *part)
 +{
 +      wmManipulator *manipulator = NULL;
 +      ListBase visible_3d_manipulators = {NULL};
 +
 +      for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
 +              if (wm_manipulatorgroup_is_visible(mgroup, C)) {
 +                      if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) {
 +                              wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators);
 +                      }
 +                      else if ((manipulator = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, part))) {
 +                              break;
 +                      }
 +              }
 +      }
 +
 +      if (!BLI_listbase_is_empty(&visible_3d_manipulators)) {
 +              manipulator = manipulator_find_intersected_3D(C, event->mval, &visible_3d_manipulators, part);
 +              BLI_freelistN(&visible_3d_manipulators);
 +      }
 +
 +      return manipulator;
 +}
 +
 +void WM_manipulatormap_add_handlers(ARegion *ar, wmManipulatorMap *mmap)
 +{
 +      wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "manipulator handler");
 +
 +      BLI_assert(mmap == ar->manipulator_map);
 +      handler->manipulator_map = mmap;
 +      BLI_addtail(&ar->handlers, handler);
 +}
 +
 +void wm_manipulatormaps_handled_modal_update(
 +        bContext *C, wmEvent *event, wmEventHandler *handler,
 +        const wmOperatorType *ot)
 +{
 +      const bool modal_running = (handler->op != NULL);
 +
 +      /* happens on render or when joining areas */
 +      if (!handler->op_region || !handler->op_region->manipulator_map)
 +              return;
 +
 +      /* hide operator manipulators */
 +      if (!modal_running && ot->mgrouptype) {
 +              ot->mgrouptype->op = NULL;
 +      }
 +
 +      wmManipulatorMap *mmap = handler->op_region->manipulator_map;
 +      wmManipulator *manipulator = wm_manipulatormap_get_active_manipulator(mmap);
 +      ScrArea *area = CTX_wm_area(C);
 +      ARegion *region = CTX_wm_region(C);
 +
 +      wm_manipulatormap_handler_context(C, handler);
 +
 +      /* regular update for running operator */
 +      if (modal_running) {
 +              if (manipulator && manipulator->handler && manipulator->opname &&
 +                  STREQ(manipulator->opname, handler->op->idname))
 +              {
 +                      manipulator->handler(C, event, manipulator, 0);
 +              }
 +      }
 +      /* operator not running anymore */
 +      else {
 +              wm_manipulatormap_set_highlighted_manipulator(mmap, C, NULL, 0);
 +              wm_manipulatormap_set_active_manipulator(mmap, C, event, NULL);
 +      }
 +
 +      /* restore the area */
 +      CTX_wm_area_set(C, area);
 +      CTX_wm_region_set(C, region);
 +}
 +
 +/**
 + * Deselect all selected manipulators in \a mmap.
 + * \return if selection has changed.
 + */
 +bool wm_manipulatormap_deselect_all(wmManipulatorMap *mmap, wmManipulator ***sel)
 +{
 +      if (*sel == NULL || mmap->mmap_context.tot_selected == 0)
 +              return false;
 +
 +      for (int i = 0; i < mmap->mmap_context.tot_selected; i++) {
 +              (*sel)[i]->state &= ~WM_MANIPULATOR_SELECTED;
 +              (*sel)[i] = NULL;
 +      }
 +      wm_manipulatormap_selected_delete(mmap);
 +
 +      /* always return true, we already checked
 +       * if there's anything to deselect */
 +      return true;
 +}
 +
 +BLI_INLINE bool manipulator_selectable_poll(const wmManipulator *manipulator, void *UNUSED(data))
 +{
 +      return (manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECTABLE);
 +}
 +
 +/**
 + * Select all selectable manipulators in \a mmap.
 + * \return if selection has changed.
 + */
 +static bool wm_manipulatormap_select_all_intern(
 +        bContext *C, wmManipulatorMap *mmap, wmManipulator ***sel,
 +        const int action)
 +{
 +      /* GHash is used here to avoid having to loop over all manipulators twice (once to
 +       * get tot_sel for allocating, once for actually selecting). Instead we collect
 +       * selectable manipulators in hash table and use this to get tot_sel and do selection */
 +
 +      GHash *hash = WM_manipulatormap_manipulator_hash_new(C, mmap, manipulator_selectable_poll, NULL, true);
 +      GHashIterator gh_iter;
 +      int i, *tot_sel = &mmap->mmap_context.tot_selected;
 +      bool changed = false;
 +
 +      *tot_sel = BLI_ghash_size(hash);
 +      *sel = MEM_reallocN(*sel, sizeof(**sel) * (*tot_sel));
 +
 +      GHASH_ITER_INDEX (gh_iter, hash, i) {
 +              wmManipulator *manipulator_iter = BLI_ghashIterator_getValue(&gh_iter);
 +
 +              if ((manipulator_iter->state & WM_MANIPULATOR_SELECTED) == 0) {
 +                      changed = true;
 +              }
 +              manipulator_iter->state |= WM_MANIPULATOR_SELECTED;
 +              if (manipulator_iter->select) {
 +                      manipulator_iter->select(C, manipulator_iter, action);
 +              }
 +              (*sel)[i] = manipulator_iter;
 +              BLI_assert(i < (*tot_sel));
 +      }
 +      /* highlight first manipulator */
 +      wm_manipulatormap_set_highlighted_manipulator(mmap, C, (*sel)[0], (*sel)[0]->highlighted_part);
 +
 +      BLI_ghash_free(hash, NULL, NULL);
 +      return changed;
 +}
 +
 +/**
 + * Select/Deselect all selectable manipulators in \a mmap.
 + * \return if selection has changed.
 + *
 + * TODO select all by type
 + */
 +bool WM_manipulatormap_select_all(bContext *C, wmManipulatorMap *mmap, const int action)
 +{
 +      wmManipulator ***sel = &mmap->mmap_context.selected_manipulator;
 +      bool changed = false;
 +
 +      switch (action) {
 +              case SEL_SELECT:
 +                      changed = wm_manipulatormap_select_all_intern(C, mmap, sel, action);
 +                      break;
 +              case SEL_DESELECT:
 +                      changed = wm_manipulatormap_deselect_all(mmap, sel);
 +                      break;
 +              default:
 +                      BLI_assert(0);
 +                      break;
 +      }
 +
 +      if (changed)
 +              WM_event_add_mousemove(C);
 +
 +      return changed;
 +}
 +
 +/**
 + * Prepare context for manipulator handling (but only if area/region is
 + * part of screen). Version of #wm_handler_op_context for manipulators.
 + */
 +void wm_manipulatormap_handler_context(bContext *C, wmEventHandler *handler)
 +{
 +      bScreen *screen = CTX_wm_screen(C);
 +
 +      if (screen) {
 +              if (handler->op_area == NULL) {
 +                      /* do nothing in this context */
 +              }
 +              else {
 +                      ScrArea *sa;
 +
 +                      for (sa = screen->areabase.first; sa; sa = sa->next)
 +                              if (sa == handler->op_area)
 +                                      break;
 +                      if (sa == NULL) {
 +                              /* when changing screen layouts with running modal handlers (like render display), this
 +                               * is not an error to print */
 +                              if (handler->manipulator_map == NULL)
 +                                      printf("internal error: modal manipulator-map handler has invalid area\n");
 +                      }
 +                      else {
 +                              ARegion *ar;
 +                              CTX_wm_area_set(C, sa);
 +                              for (ar = sa->regionbase.first; ar; ar = ar->next)
 +                                      if (ar == handler->op_region)
 +                                              break;
 +                              /* XXX no warning print here, after full-area and back regions are remade */
 +                              if (ar)
 +                                      CTX_wm_region_set(C, ar);
 +                      }
 +              }
 +      }
 +}
 +
 +bool WM_manipulatormap_cursor_set(const wmManipulatorMap *mmap, wmWindow *win)
 +{
 +      for (; mmap; mmap = mmap->next) {
 +              wmManipulator *manipulator = mmap->mmap_context.highlighted_manipulator;
 +              if (manipulator && manipulator->get_cursor) {
 +                      WM_cursor_set(win, manipulator->get_cursor(manipulator));
 +                      return true;
 +              }
 +      }
 +
 +      return false;
 +}
 +
 +void wm_manipulatormap_set_highlighted_manipulator(
 +        wmManipulatorMap *mmap, const bContext *C, wmManipulator *manipulator,
 +        unsigned char part)
 +{
 +      if ((manipulator != mmap->mmap_context.highlighted_manipulator) ||
 +          (manipulator && part != manipulator->highlighted_part))
 +      {
 +              if (mmap->mmap_context.highlighted_manipulator) {
 +                      mmap->mmap_context.highlighted_manipulator->state &= ~WM_MANIPULATOR_HIGHLIGHT;
 +                      mmap->mmap_context.highlighted_manipulator->highlighted_part = 0;
 +              }
 +
 +              mmap->mmap_context.highlighted_manipulator = manipulator;
 +
 +              if (manipulator) {
 +                      manipulator->state |= WM_MANIPULATOR_HIGHLIGHT;
 +                      manipulator->highlighted_part = part;
 +
 +                      if (C && manipulator->get_cursor) {
 +                              wmWindow *win = CTX_wm_window(C);
 +                              WM_cursor_set(win, manipulator->get_cursor(manipulator));
 +                      }
 +              }
 +              else {
 +                      if (C) {
 +                              wmWindow *win = CTX_wm_window(C);
 +                              WM_cursor_set(win, CURSOR_STD);
 +                      }
 +              }
 +
 +              /* tag the region for redraw */
 +              if (C) {
 +                      ARegion *ar = CTX_wm_region(C);
 +                      ED_region_tag_redraw(ar);
 +              }
 +      }
 +}
 +
 +wmManipulator *wm_manipulatormap_get_highlighted_manipulator(wmManipulatorMap *mmap)
 +{
 +      return mmap->mmap_context.highlighted_manipulator;
 +}
 +
 +void wm_manipulatormap_set_active_manipulator(
 +        wmManipulatorMap *mmap, bContext *C, const wmEvent *event, wmManipulator *manipulator)
 +{
 +      if (manipulator && C) {
 +              manipulator->state |= WM_MANIPULATOR_ACTIVE;
 +              mmap->mmap_context.active_manipulator = manipulator;
 +
 +              if (manipulator->opname) {
 +                      wmOperatorType *ot = WM_operatortype_find(manipulator->opname, 0);
 +
 +                      if (ot) {
 +                              /* first activate the manipulator itself */
 +                              if (manipulator->invoke && manipulator->handler) {
 +                                      manipulator->invoke(C, event, manipulator);
 +                              }
 +
 +                              WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &manipulator->opptr);
 +
 +                              /* we failed to hook the manipulator to the operator handler or operator was cancelled, return */
 +                              if (!mmap->mmap_context.active_manipulator) {
 +                                      manipulator->state &= ~WM_MANIPULATOR_ACTIVE;
 +                                      /* first activate the manipulator itself */
 +                                      if (manipulator->interaction_data) {
 +                                              MEM_freeN(manipulator->interaction_data);
 +                                              manipulator->interaction_data = NULL;
 +                                      }
 +                              }
 +                              return;
 +                      }
 +                      else {
 +                              printf("Manipulator error: operator not found");
 +                              mmap->mmap_context.active_manipulator = NULL;
 +                              return;
 +                      }
 +              }
 +              else {
 +                      if (manipulator->invoke && manipulator->handler) {
 +                              manipulator->invoke(C, event, manipulator);
 +                      }
 +              }
 +              WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
 +      }
 +      else {
 +              manipulator = mmap->mmap_context.active_manipulator;
 +
 +
 +              /* deactivate, manipulator but first take care of some stuff */
 +              if (manipulator) {
 +                      manipulator->state &= ~WM_MANIPULATOR_ACTIVE;
 +                      /* first activate the manipulator itself */
 +                      if (manipulator->interaction_data) {
 +                              MEM_freeN(manipulator->interaction_data);
 +                              manipulator->interaction_data = NULL;
 +                      }
 +              }
 +              mmap->mmap_context.active_manipulator = NULL;
 +
 +              if (C) {
 +                      WM_cursor_grab_disable(CTX_wm_window(C), NULL);
 +                      ED_region_tag_redraw(CTX_wm_region(C));
 +                      WM_event_add_mousemove(C);
 +              }
 +      }
 +}
 +
 +wmManipulator *wm_manipulatormap_get_active_manipulator(wmManipulatorMap *mmap)
 +{
 +      return mmap->mmap_context.active_manipulator;
 +}
 +
 +/** \} */ /* wmManipulatorMap */
 +
 +
 +/* -------------------------------------------------------------------- */
 +/** \name wmManipulatorMapType
 + *
 + * \{ */
 +
 +wmManipulatorMapType *WM_manipulatormaptype_find(
 +        const struct wmManipulatorMapType_Params *mmap_params)
 +{
 +      for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) {
 +              if (mmaptype->spaceid == mmap_params->spaceid &&
 +                  mmaptype->regionid == mmap_params->regionid &&
 +                  STREQ(mmaptype->idname, mmap_params->idname))
 +              {
 +                      return mmaptype;
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +wmManipulatorMapType *WM_manipulatormaptype_ensure(
 +        const struct wmManipulatorMapType_Params *mmap_params)
 +{
 +      wmManipulatorMapType *mmaptype = WM_manipulatormaptype_find(mmap_params);
 +
 +      if (mmaptype) {
 +              return mmaptype;
 +      }
 +
 +      mmaptype = MEM_callocN(sizeof(wmManipulatorMapType), "manipulatortype list");
 +      mmaptype->spaceid = mmap_params->spaceid;
 +      mmaptype->regionid = mmap_params->regionid;
 +      BLI_strncpy(mmaptype->idname, mmap_params->idname, sizeof(mmaptype->idname));
 +      BLI_addhead(&manipulatormaptypes, mmaptype);
 +
 +      return mmaptype;
 +}
 +
 +void wm_manipulatormaptypes_free(void)
 +{
 +      for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) {
 +              BLI_freelistN(&mmaptype->manipulator_grouptypes);
 +      }
 +      BLI_freelistN(&manipulatormaptypes);
 +}
 +
 +/**
 + * Initialize keymaps for all existing manipulator-groups
 + */
 +void wm_manipulators_keymap(wmKeyConfig *keyconf)
 +{
 +      wmManipulatorMapType *mmaptype;
 +      wmManipulatorGroupType *mgrouptype;
 +
 +      /* we add this item-less keymap once and use it to group manipulator-group keymaps into it */
 +      WM_keymap_find(keyconf, "Manipulators", 0, 0);
 +
 +      for (mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) {
 +              for (mgrouptype = mmaptype->manipulator_grouptypes.first; mgrouptype; mgrouptype = mgrouptype->next) {
 +                      wm_manipulatorgrouptype_keymap_init(mgrouptype, keyconf);
 +              }
 +      }
 +}
 +
 +/** \} */ /* wmManipulatorMapType */
 +