Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Fri, 16 Mar 2018 14:36:36 +0000 (01:36 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 16 Mar 2018 14:43:19 +0000 (01:43 +1100)
1  2 
source/blender/editors/mesh/CMakeLists.txt
source/blender/editors/mesh/editface.c
source/blender/editors/mesh/editmesh_add.c
source/blender/editors/mesh/editmesh_extrude.c
source/blender/editors/mesh/editmesh_path.c
source/blender/editors/mesh/editmesh_utils.c
source/blender/editors/mesh/mesh_mirror.c
source/blender/editors/mesh/meshtools.c

index a21fc2fffdefb67dc52bcea58fa9f93ee3d6ac1d,22cb28f0b1b84caa6026814a30972a7778f5f3f6..292b28c772caf3e5461186c90f6fc5be8fb4bb40
  
  /* ********* add primitive operators ************* */
  
- static Object *make_prim_init(bContext *C, const char *idname,
-                               const float loc[3], const float rot[3], const unsigned int layer,
-                               MakePrimitiveData *r_creation_data)
 +typedef struct MakePrimitiveData {
 +      float mat[4][4];
 +      bool was_editmode;
 +} MakePrimitiveData;
 +
 -        float *dia, float mat[4][4],
 -        bool *was_editmode, const float loc[3], const float rot[3], const unsigned int layer)
+ static Object *make_prim_init(
+         bContext *C, const char *idname,
++        const float loc[3], const float rot[3], const unsigned int layer,
++        MakePrimitiveData *r_creation_data)
  {
        Object *obedit = CTX_data_edit_object(C);
  
index 18320ec65f575e2e95c5d445cc3d99b761b64106,2c98f05bd27c0b15d4a815fe4a433da3fcca0d9f..aee9785ea83bdfcd76d47623803d03fd6691bd72
  #include "ED_transform.h"
  #include "ED_view3d.h"
  
 +#include "UI_resources.h"
 +
 +#include "MEM_guardedalloc.h"
 +
  #include "mesh_intern.h"  /* own include */
  
 +#define USE_MANIPULATOR
 +
 +#ifdef USE_MANIPULATOR
 +#include "ED_manipulator_library.h"
 +#include "ED_util.h"
 +#endif
 +
+ /* -------------------------------------------------------------------- */
+ /** \name Extrude Internal Utilities
+  * \{ */
  static void edbm_extrude_edge_exclude_mirror(
          Object *obedit, BMEditMesh *em,
          const char hflag,
@@@ -806,385 -824,14 +852,384 @@@ void MESH_OT_spin(wmOperatorType *ot
                             "Center", "Center in global view space", -1e4f, 1e4f);
        RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
  
 +#ifdef USE_MANIPULATOR
 +      WM_manipulatorgrouptype_append(MESH_WGT_spin);
 +#endif
  }
  
 -/** \} */
 +
 +#ifdef USE_MANIPULATOR
  
  /* -------------------------------------------------------------------- */
- /** \name Spin Manipulator
+ /** \name Screw Operator
   * \{ */
  
 +typedef struct ManipulatorSpinGroup {
 +      /* Arrow to change plane depth. */
 +      struct wmManipulator *translate_z;
 +      /* Translate XYZ */
 +      struct wmManipulator *translate_c;
 +      /* For grabbing the manipulator and moving freely. */
 +      struct wmManipulator *rotate_c;
 +      /* Spin angle */
 +      struct wmManipulator *angle_z;
 +
 +      /* We could store more vars here! */
 +      struct {
 +              bContext *context;
 +              wmOperator *op;
 +              PropertyRNA *prop_axis_co;
 +              PropertyRNA *prop_axis_no;
 +              PropertyRNA *prop_angle;
 +
 +              float rotate_axis[3];
 +              float rotate_up[3];
 +      } data;
 +} ManipulatorSpinGroup;
 +
 +/**
 + * 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 manipulator_spin_exec(ManipulatorSpinGroup *man)
 +{
 +      wmOperator *op = man->data.op;
 +      if (op == WM_operator_last_redo((bContext *)man->data.context)) {
 +              ED_undo_operator_repeat((bContext *)man->data.context, op);
 +      }
 +}
 +
 +static void manipulator_mesh_spin_update_from_op(ManipulatorSpinGroup *man)
 +{
 +      wmOperator *op = man->data.op;
 +
 +      float plane_co[3], plane_no[3];
 +
 +      RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co);
 +      RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no);
 +
 +      WM_manipulator_set_matrix_location(man->translate_z, plane_co);
 +      WM_manipulator_set_matrix_location(man->rotate_c, plane_co);
 +      WM_manipulator_set_matrix_location(man->angle_z, plane_co);
 +      /* translate_c location comes from the property. */
 +
 +      WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_z, plane_no);
 +      WM_manipulator_set_matrix_rotation_from_z_axis(man->angle_z, plane_no);
 +
 +      WM_manipulator_set_scale(man->translate_c, 0.2);
 +
 +      RegionView3D *rv3d = ED_view3d_context_rv3d(man->data.context);
 +      if (rv3d) {
 +              normalize_v3_v3(man->data.rotate_axis, rv3d->viewinv[2]);
 +              normalize_v3_v3(man->data.rotate_up, rv3d->viewinv[1]);
 +
 +              /* ensure its orthogonal */
 +              project_plane_normalized_v3_v3v3(man->data.rotate_up, man->data.rotate_up, man->data.rotate_axis);
 +              normalize_v3(man->data.rotate_up);
 +
 +              WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_c, plane_no);
 +              WM_manipulator_set_matrix_rotation_from_yz_axis(man->rotate_c, plane_no, man->data.rotate_axis);
 +
 +              /* show the axis instead of mouse cursor */
 +              RNA_enum_set(man->rotate_c->ptr, "draw_options",
 +                           ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR |
 +                           ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y);
 +
 +      }
 +}
 +
 +/* depth callbacks */
 +static void manipulator_spin_prop_depth_get(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        void *value_p)
 +{
 +      ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
 +      wmOperator *op = man->data.op;
 +      float *value = value_p;
 +
 +      BLI_assert(mpr_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(mpr_prop);
 +
 +      float plane_co[3], plane_no[3];
 +      RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co);
 +      RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no);
 +
 +      value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, mpr->matrix_basis[3]);
 +}
 +
 +static void manipulator_spin_prop_depth_set(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        const void *value_p)
 +{
 +      ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
 +      wmOperator *op = man->data.op;
 +      const float *value = value_p;
 +
 +      BLI_assert(mpr_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(mpr_prop);
 +
 +      float plane_co[3], plane[4];
 +      RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co);
 +      RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane);
 +      normalize_v3(plane);
 +
 +      plane[3] = -value[0] - dot_v3v3(plane, mpr->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, man->data.prop_axis_co, plane_co);
 +
 +      manipulator_spin_exec(man);
 +}
 +
 +/* translate callbacks */
 +static void manipulator_spin_prop_translate_get(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        void *value_p)
 +{
 +      ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
 +      wmOperator *op = man->data.op;
 +      float *value = value_p;
 +
 +      BLI_assert(mpr_prop->type->array_length == 3);
 +      UNUSED_VARS_NDEBUG(mpr_prop);
 +
 +      RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, value);
 +}
 +
 +static void manipulator_spin_prop_translate_set(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        const void *value)
 +{
 +      ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
 +      wmOperator *op = man->data.op;
 +
 +      BLI_assert(mpr_prop->type->array_length == 3);
 +      UNUSED_VARS_NDEBUG(mpr_prop);
 +
 +      RNA_property_float_set_array(op->ptr, man->data.prop_axis_co, value);
 +
 +      manipulator_spin_exec(man);
 +}
 +
 +/* angle callbacks */
 +static void manipulator_spin_prop_axis_angle_get(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        void *value_p)
 +{
 +      ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
 +      wmOperator *op = man->data.op;
 +      float *value = value_p;
 +
 +      BLI_assert(mpr_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(mpr_prop);
 +
 +      float plane_no[4];
 +      RNA_property_float_get_array(op->ptr, man->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, man->data.rotate_axis);
 +
 +      if (!is_zero_v3(plane_no_proj)) {
 +              const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis);
 +              value[0] = angle;
 +      }
 +      else {
 +              value[0] = 0.0f;
 +      }
 +}
 +
 +static void manipulator_spin_prop_axis_angle_set(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        const void *value_p)
 +{
 +      ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
 +      wmOperator *op = man->data.op;
 +      const float *value = value_p;
 +
 +      BLI_assert(mpr_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(mpr_prop);
 +
 +      float plane_no[4];
 +      RNA_property_float_get_array(op->ptr, man->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, man->data.rotate_axis);
 +
 +      if (!is_zero_v3(plane_no_proj)) {
 +              const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->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, man->data.rotate_axis, angle_delta);
 +                      mul_m3_v3(mat, plane_no);
 +
 +                      /* re-normalize - seems acceptable */
 +                      RNA_property_float_set_array(op->ptr, man->data.prop_axis_no, plane_no);
 +
 +                      manipulator_spin_exec(man);
 +              }
 +      }
 +}
 +
 +/* angle callbacks */
 +static void manipulator_spin_prop_angle_get(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        void *value_p)
 +{
 +      ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
 +      wmOperator *op = man->data.op;
 +      float *value = value_p;
 +
 +      BLI_assert(mpr_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(mpr_prop);
 +      value[0] = RNA_property_float_get(op->ptr, man->data.prop_angle);
 +}
 +
 +static void manipulator_spin_prop_angle_set(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        const void *value_p)
 +{
 +      ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
 +      wmOperator *op = man->data.op;
 +      BLI_assert(mpr_prop->type->array_length == 1);
 +      UNUSED_VARS_NDEBUG(mpr_prop);
 +      const float *value = value_p;
 +      RNA_property_float_set(op->ptr, man->data.prop_angle, value[0]);
 +
 +      manipulator_spin_exec(man);
 +}
 +
 +static bool manipulator_mesh_spin_poll(const bContext *C, wmManipulatorGroupType *wgt)
 +{
 +      wmOperator *op = WM_operator_last_redo(C);
 +      if (op == NULL || !STREQ(op->type->idname, "MESH_OT_spin")) {
 +              WM_manipulator_group_type_unlink_delayed_ptr(wgt);
 +              return false;
 +      }
 +      return true;
 +}
 +
 +static void manipulator_mesh_spin_setup(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      wmOperator *op = WM_operator_last_redo(C);
 +
 +      if (op == NULL || !STREQ(op->type->idname, "MESH_OT_spin")) {
 +              return;
 +      }
 +
 +      struct ManipulatorSpinGroup *man = MEM_callocN(sizeof(ManipulatorSpinGroup), __func__);
 +      mgroup->customdata = man;
 +
 +      const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
 +      const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", true);
 +      const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true);
 +
 +      man->translate_z = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL);
 +      man->translate_c = WM_manipulator_new_ptr(wt_grab, mgroup, NULL);
 +      man->rotate_c = WM_manipulator_new_ptr(wt_dial, mgroup, NULL);
 +      man->angle_z = WM_manipulator_new_ptr(wt_dial, mgroup, NULL);
 +
 +      UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->translate_z->color);
 +      UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->translate_c->color);
 +      UI_GetThemeColor3fv(TH_MANIPULATOR_SECONDARY, man->rotate_c->color);
 +      UI_GetThemeColor3fv(TH_AXIS_Z, man->angle_z->color);
 +
 +
 +      RNA_enum_set(man->translate_z->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
 +      RNA_enum_set(man->translate_c->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_RING_2D);
 +
 +      WM_manipulator_set_flag(man->translate_c, WM_MANIPULATOR_DRAW_VALUE, true);
 +      WM_manipulator_set_flag(man->rotate_c, WM_MANIPULATOR_DRAW_VALUE, true);
 +      WM_manipulator_set_flag(man->angle_z, WM_MANIPULATOR_DRAW_VALUE, true);
 +
 +      WM_manipulator_set_scale(man->angle_z, 0.5f);
 +
 +      {
 +              man->data.context = (bContext *)C;
 +              man->data.op = op;
 +              man->data.prop_axis_co = RNA_struct_find_property(op->ptr, "center");
 +              man->data.prop_axis_no = RNA_struct_find_property(op->ptr, "axis");
 +              man->data.prop_angle = RNA_struct_find_property(op->ptr, "angle");
 +      }
 +
 +      manipulator_mesh_spin_update_from_op(man);
 +
 +      /* Setup property callbacks */
 +      {
 +              WM_manipulator_target_property_def_func(
 +                      man->translate_z, "offset",
 +                      &(const struct wmManipulatorPropertyFnParams) {
 +                          .value_get_fn = manipulator_spin_prop_depth_get,
 +                          .value_set_fn = manipulator_spin_prop_depth_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = NULL,
 +                      });
 +
 +              WM_manipulator_target_property_def_func(
 +                      man->translate_c, "offset",
 +                      &(const struct wmManipulatorPropertyFnParams) {
 +                          .value_get_fn = manipulator_spin_prop_translate_get,
 +                          .value_set_fn = manipulator_spin_prop_translate_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = NULL,
 +                      });
 +
 +              WM_manipulator_target_property_def_func(
 +                      man->rotate_c, "offset",
 +                      &(const struct wmManipulatorPropertyFnParams) {
 +                          .value_get_fn = manipulator_spin_prop_axis_angle_get,
 +                          .value_set_fn = manipulator_spin_prop_axis_angle_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = NULL,
 +                      });
 +
 +              WM_manipulator_target_property_def_func(
 +                      man->angle_z, "offset",
 +                      &(const struct wmManipulatorPropertyFnParams) {
 +                          .value_get_fn = manipulator_spin_prop_angle_get,
 +                          .value_set_fn = manipulator_spin_prop_angle_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = NULL,
 +                      });
 +
 +      }
 +}
 +
 +static void manipulator_mesh_spin_draw_prepare(
 +        const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
 +{
 +      ManipulatorSpinGroup *man = mgroup->customdata;
 +      if (man->data.op->next) {
 +              man->data.op = WM_operator_last_redo((bContext *)man->data.context);
 +      }
 +      manipulator_mesh_spin_update_from_op(man);
 +}
 +
 +static void MESH_WGT_spin(struct wmManipulatorGroupType *wgt)
 +{
 +      wgt->name = "Mesh Spin";
 +      wgt->idname = "MESH_WGT_spin";
 +
 +      wgt->flag = WM_MANIPULATORGROUPTYPE_3D;
 +
 +      wgt->mmap_params.spaceid = SPACE_VIEW3D;
 +      wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
 +
 +      wgt->poll = manipulator_mesh_spin_poll;
 +      wgt->setup = manipulator_mesh_spin_setup;
 +      wgt->draw_prepare = manipulator_mesh_spin_draw_prepare;
 +}
 +
 +/** \} */
 +
 +#endif  /* USE_MANIPULATOR */
 +
 +
  static int edbm_screw_exec(bContext *C, wmOperator *op)
  {
        Object *obedit = CTX_data_edit_object(C);
index 795c7b6aa530b1bae943364c5393d3e121dbd5f7,bf5a7e3a053c7e79b07ae58c01a2d59fa8e5ab75..2ae48bee09592dbc9a0a373f091687bb89868bad
  #include "bmesh.h"
  #include "bmesh_tools.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "mesh_intern.h"  /* own include */
  
+ /* -------------------------------------------------------------------- */
+ /** \name Path Select Struct & Properties
+  * \{ */
  struct PathSelectParams {
        bool track_active;  /* ensure the active element is the last selected item (handy for picking) */
        bool use_topology_distance;
@@@ -538,13 -547,14 +546,14 @@@ static void mouse_mesh_shortest_path_fa
        EDBM_update_generic(em, false, false);
  }
  
+ /** \} */
  
  /* -------------------------------------------------------------------- */
- /* Main Operator for vert/edge/face tag */
+ /** \name Main Operator for vert/edge/face tag
+  * \{ */
  
  static bool edbm_shortest_path_pick_ex(
 -        Scene *scene, const struct PathSelectParams *op_params,
 +        Scene *scene, Object *obedit, const struct PathSelectParams *op_params,
          BMElem *ele_src, BMElem *ele_dst)
  {
  
index 70ee162753778c027328c380c44cd202cc84f640,d25304cef89580300327141a056a0974bc03c4d0..312dc000a2b58adcaa2c5c380beeabd90e55ffd1
@@@ -592,7 -595,8 +595,7 @@@ UvVertMap *BM_uv_vert_map_create
                        newvlist = v;
  
                        efa = BM_face_at_index(bm, v->f);
-                       
 -                      /* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
                        l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex);
                        luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
                        uv = luv->uv;
                        while (iterv) {
                                next = iterv->next;
                                efa = BM_face_at_index(bm, iterv->f);
-                               
 -                              /* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
 -
                                l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
                                luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
                                uv2 = luv->uv;
@@@ -915,12 -919,18 +916,18 @@@ UvElement *BM_uv_element_get(UvElementM
        return NULL;
  }
  
+ /** \} */
+ /* -------------------------------------------------------------------- */
+ /** \name Data Layer Checks
+  * \{ */
  /* last_sel, use em->act_face otherwise get the last selected face in the editselections
   * at the moment, last_sel is mainly useful for making sure the space image dosnt flicker */
 -BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected, MTexPoly **r_tf)
 +BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
  {
        BMFace *efa = NULL;
-       
        if (!EDBM_uv_check(em)) {
                return NULL;
        }
@@@ -1405,10 -1495,12 +1491,12 @@@ bool BMBVH_EdgeVisible(struct BMBVHTre
        float origin[3], invmat[4][4];
        float epsilon = 0.01f;
        float end[3];
-       const float mval_f[2] = {ar->winx / 2.0f,
-                                ar->winy / 2.0f};
+       const float mval_f[2] = {
+               ar->winx / 2.0f,
+               ar->winy / 2.0f,
+       };
  
 -      ED_view3d_win_to_segment(ar, v3d, mval_f, origin, end, false);
 +      ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false);
  
        invert_m4_m4(invmat, obedit->obmat);
        mul_m4_v3(invmat, origin);
index 0000000000000000000000000000000000000000,96b9f054252afc5f6f9fcc2c4f496049782e695c..22bfd8eedeaafc29c976958c6b2d5b1bde2f22bf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,374 +1,377 @@@
 -bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store)
+ /*
+  * ***** 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.
+  *
+  * Contributor(s): Blender Foundation, Campbell Barton
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ /** \file blender/editors/mesh/mesh_mirror.c
+  *  \ingroup edmesh
+  *
+  * Mirror calculation for edit-mode and object mode.
+  */
+ #include "MEM_guardedalloc.h"
+ #include "BLI_math.h"
+ #include "BLI_bitmap.h"
+ #include "DNA_mesh_types.h"
+ #include "DNA_object_types.h"
+ #include "BKE_DerivedMesh.h"
+ #include "BLI_kdtree.h"
+ #include "BKE_editmesh.h"
+ #include "ED_mesh.h"
+ /* -------------------------------------------------------------------- */
+ /** \name Mesh Spatial Mirror API
+  * \{ */
+ #define KD_THRESH      0.00002f
+ static struct { void *tree; } MirrKdStore = {NULL};
+ /* mode is 's' start, or 'e' end, or 'u' use */
+ /* if end, ob can be NULL */
+ int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode)
+ {
+       if (mode == 'u') {        /* use table */
+               if (MirrKdStore.tree == NULL)
+                       ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
+               if (MirrKdStore.tree) {
+                       KDTreeNearest nearest;
+                       const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest);
+                       if (i != -1) {
+                               if (nearest.dist < KD_THRESH) {
+                                       return i;
+                               }
+                       }
+               }
+               return -1;
+       }
+       else if (mode == 's') {   /* start table */
+               Mesh *me = ob->data;
+               const bool use_em = (!dm && em && me->edit_btmesh == em);
+               const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert;
+               if (MirrKdStore.tree) /* happens when entering this call without ending it */
+                       ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e');
+               MirrKdStore.tree = BLI_kdtree_new(totvert);
+               if (use_em) {
+                       BMVert *eve;
+                       BMIter iter;
+                       int i;
+                       /* this needs to be valid for index lookups later (callers need) */
+                       BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+                       BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+                               BLI_kdtree_insert(MirrKdStore.tree, i, eve->co);
+                       }
+               }
+               else {
+                       MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
+                       int i;
+                       
+                       for (i = 0; i < totvert; i++, mvert++) {
+                               BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co);
+                       }
+               }
+               BLI_kdtree_balance(MirrKdStore.tree);
+       }
+       else if (mode == 'e') { /* end table */
+               if (MirrKdStore.tree) {
+                       BLI_kdtree_free(MirrKdStore.tree);
+                       MirrKdStore.tree = NULL;
+               }
+       }
+       else {
+               BLI_assert(0);
+       }
+       return 0;
+ }
+ /** \} */
+ /* -------------------------------------------------------------------- */
+ /** \name Mesh Topology Mirror API
+  * \{ */
+ typedef unsigned int MirrTopoHash_t;
+ typedef struct MirrTopoVert_t {
+       MirrTopoHash_t hash;
+       int v_index;
+ } MirrTopoVert_t;
+ static int mirrtopo_hash_sort(const void *l1, const void *l2)
+ {
+       if      ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1;
+       else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1;
+       return 0;
+ }
+ static int mirrtopo_vert_sort(const void *v1, const void *v2)
+ {
+       if      (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1;
+       else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1;
+       return 0;
+ }
 -          (mesh_topo_store->prev_ob_mode != ob_mode) ||
++bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store)
+ {
++      const bool is_editmode = (me->edit_btmesh != NULL);
+       int totvert;
+       int totedge;
+       if (dm) {
+               totvert = dm->getNumVerts(dm);
+               totedge = dm->getNumEdges(dm);
+       }
+       else if (me->edit_btmesh) {
+               totvert = me->edit_btmesh->bm->totvert;
+               totedge = me->edit_btmesh->bm->totedge;
+       }
+       else {
+               totvert = me->totvert;
+               totedge = me->totedge;
+       }
+       if ((mesh_topo_store->index_lookup == NULL) ||
 -void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
 -                           const bool skip_em_vert_array_init)
++          (mesh_topo_store->prev_is_editmode != is_editmode) ||
+           (totvert != mesh_topo_store->prev_vert_tot) ||
+           (totedge != mesh_topo_store->prev_edge_tot))
+       {
+               return true;
+       }
+       else {
+               return false;
+       }
+ }
 -      mesh_topo_store->prev_ob_mode = ob_mode;
++void ED_mesh_mirrtopo_init(
++        Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store,
++        const bool skip_em_vert_array_init)
+ {
++      const bool is_editmode = (me->edit_btmesh != NULL);
+       MEdge *medge = NULL, *med;
+       BMEditMesh *em = dm ?  NULL : me->edit_btmesh;
+       /* editmode*/
+       BMEdge *eed;
+       BMIter iter;
+       int a, last;
+       int totvert, totedge;
+       int tot_unique = -1, tot_unique_prev = -1;
+       int tot_unique_edges = 0, tot_unique_edges_prev;
+       MirrTopoHash_t *topo_hash = NULL;
+       MirrTopoHash_t *topo_hash_prev = NULL;
+       MirrTopoVert_t *topo_pairs;
+       MirrTopoHash_t  topo_pass = 1;
+       intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */
+       /* reallocate if needed */
+       ED_mesh_mirrtopo_free(mesh_topo_store);
++      mesh_topo_store->prev_is_editmode = is_editmode;
+       if (em) {
+               BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+               totvert = em->bm->totvert;
+       }
+       else {
+               totvert = dm ? dm->getNumVerts(dm) : me->totvert;
+       }
+       topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
+       /* Initialize the vert-edge-user counts used to detect unique topology */
+       if (em) {
+               totedge = me->edit_btmesh->bm->totedge;
+               BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+                       const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
+                       topo_hash[i1]++;
+                       topo_hash[i2]++;
+               }
+       }
+       else {
+               totedge = dm ? dm->getNumEdges(dm) : me->totedge;
+               medge = dm ? dm->getEdgeArray(dm) : me->medge;
+               for (a = 0, med = medge; a < totedge; a++, med++) {
+                       const unsigned int i1 = med->v1, i2 = med->v2;
+                       topo_hash[i1]++;
+                       topo_hash[i2]++;
+               }
+       }
+       topo_hash_prev = MEM_dupallocN(topo_hash);
+       tot_unique_prev = -1;
+       tot_unique_edges_prev = -1;
+       while (1) {
+               /* use the number of edges per vert to give verts unique topology IDs */
+               tot_unique_edges = 0;
+               /* This can make really big numbers, wrapping around here is fine */
+               if (em) {
+                       BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+                               const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
+                               topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
+                               topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
+                               tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
+                       }
+               }
+               else {
+                       for (a = 0, med = medge; a < totedge; a++, med++) {
+                               const unsigned int i1 = med->v1, i2 = med->v2;
+                               topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
+                               topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
+                               tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
+                       }
+               }
+               memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
+               /* sort so we can count unique values */
+               qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort);
+               tot_unique = 1; /* account for skiping the first value */
+               for (a = 1; a < totvert; a++) {
+                       if (topo_hash_prev[a - 1] != topo_hash_prev[a]) {
+                               tot_unique++;
+                       }
+               }
+               if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) {
+                       /* Finish searching for unique values when 1 loop dosnt give a
+                        * higher number of unique values compared to the previous loop */
+                       break;
+               }
+               else {
+                       tot_unique_prev = tot_unique;
+                       tot_unique_edges_prev = tot_unique_edges;
+               }
+               /* Copy the hash calculated this iter, so we can use them next time */
+               memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
+               topo_pass++;
+       }
+       /* Hash/Index pairs are needed for sorting to find index pairs */
+       topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs");
+       /* since we are looping through verts, initialize these values here too */
+       index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup");
+       if (em) {
+               if (skip_em_vert_array_init == false) {
+                       BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+               }
+       }
+       for (a = 0; a < totvert; a++) {
+               topo_pairs[a].hash    = topo_hash[a];
+               topo_pairs[a].v_index = a;
+               /* initialize lookup */
+               index_lookup[a] = -1;
+       }
+       qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort);
+       last = 0;
+       /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
+        * but you cant ever access the last 'a' index of MirrTopoPairs */
+       if (em) {
+               BMVert **vtable = em->bm->vtable;
+               for (a = 1; a <= totvert; a++) {
+                       /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */
+                       if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
+                               const int match_count = a - last;
+                               if (match_count == 2) {
+                                       const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
+                                       index_lookup[j] = (intptr_t)vtable[k];
+                                       index_lookup[k] = (intptr_t)vtable[j];
+                               }
+                               else if (match_count == 1) {
+                                       /* Center vertex. */
+                                       const int j = topo_pairs[a - 1].v_index;
+                                       index_lookup[j] = (intptr_t)vtable[j];
+                               }
+                               last = a;
+                       }
+               }
+       }
+       else {
+               /* same as above, for mesh */
+               for (a = 1; a <= totvert; a++) {
+                       if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
+                               const int match_count = a - last;
+                               if (match_count == 2) {
+                                       const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
+                                       index_lookup[j] = k;
+                                       index_lookup[k] = j;
+                               }
+                               else if (match_count == 1) {
+                                       /* Center vertex. */
+                                       const int j = topo_pairs[a - 1].v_index;
+                                       index_lookup[j] = j;
+                               }
+                               last = a;
+                       }
+               }
+       }
+       MEM_freeN(topo_pairs);
+       topo_pairs = NULL;
+       MEM_freeN(topo_hash);
+       MEM_freeN(topo_hash_prev);
+       mesh_topo_store->index_lookup  = index_lookup;
+       mesh_topo_store->prev_vert_tot = totvert;
+       mesh_topo_store->prev_edge_tot = totedge;
+ }
+ void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
+ {
+       if (mesh_topo_store->index_lookup) {
+               MEM_freeN(mesh_topo_store->index_lookup);
+       }
+       mesh_topo_store->index_lookup  = NULL;
+       mesh_topo_store->prev_vert_tot = -1;
+       mesh_topo_store->prev_edge_tot = -1;
+ }
+ /** \} */
index aebfd46a554309191fa1fc1bd284ddb7241e60bb,73413bcbaad9412d2ae1a574961cda4eda134ccc..2e75276cd8f0bd22903431110ea2112affb55e56
@@@ -47,9 -46,8 +47,7 @@@
  #include "BLI_math.h"
  #include "BLI_blenlib.h"
  
- #include "BLI_kdtree.h"
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_deform.h"
  #include "BKE_DerivedMesh.h"
  #include "BKE_key.h"