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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYimingWu <xp8110@outlook.com>2019-09-04 06:30:16 +0300
committerYimingWu <xp8110@outlook.com>2019-09-04 06:30:16 +0300
commit55a6fc0be3ffa823052aba45bec12c6902e7bd53 (patch)
treefb8cb4e411e22fcb49e443ea4da636660618877f /source/blender/editors/mesh
parentafac2afbfcdb06a2d2655e63d0b8bc35b1aba18e (diff)
parentda25aca2677ec2b566cad1809eebceee22b28b53 (diff)
Merge remote-tracking branch 'origin/master' into soc-2019-npr
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editmesh_automerge.c517
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c13
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c4
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c189
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c206
-rw-r--r--source/blender/editors/mesh/editmesh_select.c191
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c14
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c20
-rw-r--r--source/blender/editors/mesh/mesh_data.c126
-rw-r--r--source/blender/editors/mesh/mesh_intern.h2
-rw-r--r--source/blender/editors/mesh/mesh_ops.c21
12 files changed, 1048 insertions, 256 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 9a779db4812..d7d020ae19d 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
editface.c
editmesh_add.c
editmesh_add_gizmo.c
+ editmesh_automerge.c
editmesh_bevel.c
editmesh_bisect.c
editmesh_extrude.c
diff --git a/source/blender/editors/mesh/editmesh_automerge.c b/source/blender/editors/mesh/editmesh_automerge.c
new file mode 100644
index 00000000000..82f53aafad8
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_automerge.c
@@ -0,0 +1,517 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edmesh
+ *
+ * Utility functions for merging geometry once transform has finished:
+ *
+ * - #EDBM_automerge
+ * - #EDBM_automerge_and_split
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_math.h"
+#include "BLI_sort.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_editmesh.h"
+
+#include "WM_api.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+
+#include "DNA_object_types.h"
+
+#include "DEG_depsgraph.h"
+
+/* use bmesh operator flags for a few operators */
+#define BMO_ELE_TAG 1
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Merge Selection
+ *
+ * Used after transform operations.
+ * \{ */
+
+void EDBM_automerge(Object *obedit, bool update, const char hflag, const float dist)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ int totvert_prev = bm->totvert;
+
+ BMOperator findop, weldop;
+
+ /* Search for doubles among all vertices, but only merge non-VERT_KEEP
+ * vertices into VERT_KEEP vertices. */
+ BMO_op_initf(bm,
+ &findop,
+ BMO_FLAG_DEFAULTS,
+ "find_doubles verts=%av keep_verts=%Hv dist=%f",
+ hflag,
+ dist);
+
+ BMO_op_exec(bm, &findop);
+
+ /* weld the vertices */
+ BMO_op_init(bm, &weldop, BMO_FLAG_DEFAULTS, "weld_verts");
+ BMO_slot_copy(&findop, slots_out, "targetmap.out", &weldop, slots_in, "targetmap");
+ BMO_op_exec(bm, &weldop);
+
+ BMO_op_finish(bm, &findop);
+ BMO_op_finish(bm, &weldop);
+
+ if ((totvert_prev != bm->totvert) && update) {
+ EDBM_update_generic(em, true, true);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Merge & Split Selection
+ *
+ * Used after transform operations.
+ * \{ */
+
+struct EDBMSplitEdge {
+ BMVert *v;
+ BMEdge *e;
+ float lambda;
+};
+
+struct EDBMSplitBestFaceData {
+ BMEdge **edgenet;
+ int edgenet_len;
+
+ /**
+ * Track the range of vertices in edgenet along the faces normal,
+ * find the lowest since it's most likely to be most co-planar with the face.
+ */
+ float best_face_range_on_normal_axis;
+ BMFace *r_best_face;
+};
+
+struct EDBMSplitEdgeData {
+ BMesh *bm;
+
+ BMEdge *r_edge;
+ float r_lambda;
+};
+
+static bool edbm_vert_pair_share_best_splittable_face_cb(BMFace *f,
+ BMLoop *UNUSED(l_a),
+ BMLoop *UNUSED(l_b),
+ void *userdata)
+{
+ struct EDBMSplitBestFaceData *data = userdata;
+ float no[3], min = FLT_MAX, max = -FLT_MAX;
+ copy_v3_v3(no, f->no);
+
+ BMVert *verts[2] = {NULL};
+ BMEdge **e_iter = &data->edgenet[0];
+ for (int i = data->edgenet_len; i--; e_iter++) {
+ BMIter iter;
+ BMVert *v;
+ BM_ITER_ELEM (v, &iter, *e_iter, BM_VERTS_OF_EDGE) {
+ if (!ELEM(v, verts[0], verts[1])) {
+ float dot = dot_v3v3(v->co, no);
+ if (dot < min) {
+ min = dot;
+ }
+ if (dot > max) {
+ max = dot;
+ }
+ }
+ }
+ verts[0] = (*e_iter)->v1;
+ verts[1] = (*e_iter)->v2;
+ }
+
+ const float test_face_range_on_normal_axis = max - min;
+ if (test_face_range_on_normal_axis < data->best_face_range_on_normal_axis) {
+ data->best_face_range_on_normal_axis = test_face_range_on_normal_axis;
+ data->r_best_face = f;
+ }
+
+ return false;
+}
+
+/* find the best splittable face between the two vertices. */
+static bool edbm_vert_pair_share_splittable_face_cb(BMFace *UNUSED(f),
+ BMLoop *l_a,
+ BMLoop *l_b,
+ void *userdata)
+{
+ float(*data)[3] = userdata;
+ float *v_a_co = data[0];
+ float *v_a_b_dir = data[1];
+
+ float lambda;
+ if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_a->prev->v->co, l_a->next->v->co, &lambda)) {
+ if (IN_RANGE(lambda, 0.0f, 1.0f)) {
+ return true;
+ }
+ else if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_b->prev->v->co, l_b->next->v->co, &lambda)) {
+ return IN_RANGE(lambda, 0.0f, 1.0f);
+ }
+ }
+ return false;
+}
+
+static void edbm_automerge_weld_linked_wire_edges_into_linked_faces(BMesh *bm,
+ BMVert *v,
+ BMEdge **r_edgenet[],
+ int *r_edgenet_alloc_len)
+{
+ BMEdge **edgenet = *r_edgenet;
+ int edgenet_alloc_len = *r_edgenet_alloc_len;
+
+ BMIter iter;
+ BMEdge *e;
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ int edgenet_len = 0;
+ BMVert *v_other = v;
+ while (BM_edge_is_wire(e)) {
+ if (edgenet_alloc_len == edgenet_len) {
+ edgenet_alloc_len = (edgenet_alloc_len + 1) * 2;
+ edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet));
+ }
+ edgenet[edgenet_len++] = e;
+ v_other = BM_edge_other_vert(e, v_other);
+ if (v_other == v) {
+ /* Endless loop. */
+ break;
+ }
+
+ BMEdge *e_next = BM_DISK_EDGE_NEXT(e, v_other);
+ if (e_next == e) {
+ /* Vert is wire_endpoint */
+ edgenet_len = 0;
+ break;
+ }
+ e = e_next;
+ }
+
+ BMLoop *dummy;
+ BMFace *best_face;
+ if (edgenet_len == 0) {
+ /* Nothing to do. */
+ continue;
+ }
+ if (edgenet_len == 1) {
+ float data[2][3];
+ copy_v3_v3(data[0], v_other->co);
+ sub_v3_v3v3(data[1], v->co, data[0]);
+ best_face = BM_vert_pair_shared_face_cb(
+ v_other, v, true, edbm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy);
+ }
+ else {
+ struct EDBMSplitBestFaceData data = {
+ .edgenet = edgenet,
+ .edgenet_len = edgenet_len,
+ .best_face_range_on_normal_axis = FLT_MAX,
+ .r_best_face = NULL,
+ };
+ BM_vert_pair_shared_face_cb(
+ v_other, v, true, edbm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy);
+
+ best_face = data.r_best_face;
+ }
+
+ if (best_face) {
+ BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, NULL, NULL);
+ }
+ }
+
+ *r_edgenet = edgenet;
+ *r_edgenet_alloc_len = edgenet_alloc_len;
+}
+
+static void ebbm_automerge_and_split_find_duplicate_cb(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *nearest)
+{
+ struct EDBMSplitEdgeData *data = userdata;
+ BMEdge *e = BM_edge_at_index(data->bm, index);
+ float lambda = line_point_factor_v3_ex(co, e->v1->co, e->v2->co, 0.0f, -1.0f);
+ if (IN_RANGE(lambda, 0.0f, 1.0f)) {
+ float near_co[3];
+ interp_v3_v3v3(near_co, e->v1->co, e->v2->co, lambda);
+ float dist_sq = len_squared_v3v3(near_co, co);
+ if (dist_sq < nearest->dist_sq) {
+ nearest->dist_sq = dist_sq;
+ nearest->index = index;
+
+ data->r_edge = e;
+ data->r_lambda = lambda;
+ }
+ }
+}
+
+static int edbm_automerge_and_split_sort_cmp_by_keys_cb(const void *index1_v,
+ const void *index2_v,
+ void *keys_v)
+{
+ const struct EDBMSplitEdge *cuts = keys_v;
+ const int *index1 = (int *)index1_v;
+ const int *index2 = (int *)index2_v;
+
+ if (cuts[*index1].lambda > cuts[*index2].lambda) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
+}
+
+void EDBM_automerge_and_split(Object *obedit,
+ bool split_edges,
+ bool split_faces,
+ bool update,
+ const char hflag,
+ const float dist)
+{
+ bool ok = false;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMOperator findop, weldop;
+ BMOpSlot *slot_targetmap;
+ BMIter iter;
+ BMVert *v;
+
+ /* tag and count the verts to be tested. */
+ BM_mesh_elem_toolflags_ensure(bm);
+ int verts_len = 0;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, hflag)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ BMO_vert_flag_enable(bm, v, BMO_ELE_TAG);
+ verts_len++;
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+ }
+
+ /* Search for doubles among all vertices, but only merge non-BMO_ELE_TAG
+ * vertices into BMO_ELE_TAG vertices. */
+ BMO_op_initf(bm, &findop, 0, "find_doubles verts=%av keep_verts=%Fv dist=%f", BMO_ELE_TAG, dist);
+ BMO_op_exec(bm, &findop);
+
+ /* Init weld_verts operator to later fill the targetmap. */
+ BMO_op_init(bm, &weldop, 0, "weld_verts");
+ BMO_slot_copy(&findop, slots_out, "targetmap.out", &weldop, slots_in, "targetmap");
+
+ slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap");
+
+ /* Remove duplicate vertices from the split edge test and check and split faces. */
+ GHashIterator gh_iter;
+ GHash *ghash_targetmap = BMO_SLOT_AS_GHASH(slot_targetmap);
+ GHASH_ITER (gh_iter, ghash_targetmap) {
+ v = BLI_ghashIterator_getKey(&gh_iter);
+ BMVert *v_dst = BLI_ghashIterator_getValue(&gh_iter);
+ if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ /* Should this happen? */
+ SWAP(BMVert *, v, v_dst);
+ }
+ BLI_assert(BM_elem_flag_test(v, BM_ELEM_TAG));
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ ok = true;
+ verts_len--;
+ }
+
+ int totedge = bm->totedge;
+ if (totedge == 0 || verts_len == 0) {
+ split_edges = false;
+ }
+
+ if (split_edges) {
+ /* Count and tag edges. */
+ BMEdge *e;
+ int edges_len = 0;
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && !BM_elem_flag_test(e->v1, BM_ELEM_TAG) &&
+ !BM_elem_flag_test(e->v2, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ edges_len++;
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ }
+ }
+
+ if (edges_len) {
+ /* Use `e->head.index` to count intersections. */
+ bm->elem_index_dirty &= ~BM_EDGE;
+
+ /* Create a BVHTree of edges with `dist` as epsilon. */
+ BVHTree *tree_edges = BLI_bvhtree_new(edges_len, dist, 2, 6);
+ int i;
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ float co[2][3];
+ copy_v3_v3(co[0], e->v1->co);
+ copy_v3_v3(co[1], e->v2->co);
+
+ BLI_bvhtree_insert(tree_edges, i, co[0], 2);
+
+ e->head.index = 0;
+ }
+ }
+ BLI_bvhtree_balance(tree_edges);
+
+ struct EDBMSplitEdge *cuts_iter, *cuts;
+
+ /* Store all intersections in this array. */
+ cuts = MEM_mallocN(verts_len * sizeof(*cuts), __func__);
+ cuts_iter = &cuts[0];
+
+ int cuts_len = 0;
+ int cut_edges_len = 0;
+ float dist_sq = SQUARE(dist);
+ struct EDBMSplitEdgeData data = {bm};
+
+ /* Start the search for intersections. */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ float co[3];
+ copy_v3_v3(co, v->co);
+ int e_index = BLI_bvhtree_find_nearest_first(
+ tree_edges, co, dist_sq, ebbm_automerge_and_split_find_duplicate_cb, &data);
+
+ if (e_index != -1) {
+ e = data.r_edge;
+ e->head.index++;
+
+ cuts_iter->v = v;
+ cuts_iter->e = e;
+ cuts_iter->lambda = data.r_lambda;
+ cuts_iter++;
+ cuts_len++;
+
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ cut_edges_len++;
+ }
+ }
+ }
+ }
+ BLI_bvhtree_free(tree_edges);
+
+ if (cuts_len) {
+ /* Map intersections per edge. */
+ union {
+ struct {
+ int cuts_len;
+ int cuts_index[];
+ };
+ int as_int[0];
+ } * e_map_iter, *e_map;
+
+ e_map = MEM_mallocN((cut_edges_len * sizeof(*e_map)) +
+ (cuts_len * sizeof(*(e_map->cuts_index))),
+ __func__);
+
+ int map_len = 0;
+ cuts_iter = &cuts[0];
+ for (i = 0; i < cuts_len; i++, cuts_iter++) {
+ e = cuts_iter->e;
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ int e_cuts_len = e->head.index;
+
+ e_map_iter = (void *)&e_map->as_int[map_len];
+ e_map_iter->cuts_len = e_cuts_len;
+ e_map_iter->cuts_index[0] = i;
+
+ /* Use `e->head.index` to indicate which slot to fill with the `cuts` index. */
+ e->head.index = map_len + 1;
+ map_len += 1 + e_cuts_len;
+ }
+ else {
+ e_map->as_int[++e->head.index] = i;
+ }
+ }
+
+ /* Split Edges and Faces. */
+ for (i = 0; i < map_len;
+ e_map_iter = (void *)&e_map->as_int[i], i += 1 + e_map_iter->cuts_len) {
+
+ /* sort by lambda. */
+ BLI_qsort_r(e_map_iter->cuts_index,
+ e_map_iter->cuts_len,
+ sizeof(*(e_map->cuts_index)),
+ edbm_automerge_and_split_sort_cmp_by_keys_cb,
+ cuts);
+
+ float lambda, lambda_prev = 0.0f;
+ for (int j = 0; j < e_map_iter->cuts_len; j++) {
+ cuts_iter = &cuts[e_map_iter->cuts_index[j]];
+ lambda = (cuts_iter->lambda - lambda_prev) / (1.0f - lambda_prev);
+ lambda_prev = cuts_iter->lambda;
+ v = cuts_iter->v;
+ e = cuts_iter->e;
+
+ BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda);
+
+ BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_new, v);
+ }
+ }
+
+ ok = true;
+ MEM_freeN(e_map);
+ }
+
+ MEM_freeN(cuts);
+ }
+ }
+
+ BMO_op_exec(bm, &weldop);
+
+ BMEdge **edgenet = NULL;
+ int edgenet_alloc_len = 0;
+ if (split_faces) {
+ GHASH_ITER (gh_iter, ghash_targetmap) {
+ v = BLI_ghashIterator_getValue(&gh_iter);
+ BLI_assert(BM_elem_flag_test(v, hflag) || hflag == BM_ELEM_TAG);
+ edbm_automerge_weld_linked_wire_edges_into_linked_faces(bm, v, &edgenet, &edgenet_alloc_len);
+ }
+ }
+
+ if (edgenet) {
+ MEM_freeN(edgenet);
+ }
+
+ BMO_op_finish(bm, &findop);
+ BMO_op_finish(bm, &weldop);
+
+ if (LIKELY(ok) && update) {
+ EDBM_update_generic(em, true, true);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
index 74700e59e99..7155348fed5 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
@@ -1008,8 +1008,17 @@ static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup)
});
}
- /* Become modal as soon as it's started. */
- gizmo_mesh_spin_redo_modal_from_setup(C, gzgroup);
+ wmWindow *win = CTX_wm_window(C);
+ if (win && win->active) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen->active_region) {
+ ARegion *ar = CTX_wm_region(C);
+ if (screen->active_region == ar) {
+ /* 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)
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index bb584094580..61f9dc43c0f 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2658,7 +2658,7 @@ static void knifetool_init_bmbvh(KnifeTool_OpData *kcd)
Object *obedit_eval = (Object *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->em->ob->id);
BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
- kcd->cagecos = (const float(*)[3])BKE_editmesh_vertexCos_get(
+ kcd->cagecos = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
kcd->vc.depsgraph, em_eval, scene_eval, NULL);
kcd->bmbvh = BKE_bmbvh_new_from_editmesh(
@@ -2949,7 +2949,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
case KNF_MODAL_ADD_CUT_CLOSED:
if (kcd->mode == MODE_DRAGGING) {
- /* shouldn't be possible with default key-layout, just incase... */
+ /* Shouldn't be possible with default key-layout, just in case. */
if (kcd->is_drag_hold) {
kcd->is_drag_hold = false;
knifetool_update_mval(kcd, kcd->curr.mval);
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index 088d1672cc9..21c850160dd 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -122,15 +122,160 @@ static bool edbm_preselect_or_active_init_viewcontext(bContext *C,
return ok;
}
+static int edbm_polybuild_transform_at_cursor_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(event))
+{
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ if (!ele_act) {
+ return OPERATOR_CANCELLED;
+ }
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+
+ if (ele_act->head.htype == BM_VERT) {
+ BM_vert_select_set(bm, (BMVert *)ele_act, true);
+ }
+ if (ele_act->head.htype == BM_EDGE) {
+ BM_edge_select_set(bm, (BMEdge *)ele_act, true);
+ }
+ if (ele_act->head.htype == BM_FACE) {
+ BM_face_select_set(bm, (BMFace *)ele_act, true);
+ }
+
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ if (basact != NULL) {
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
+ BM_select_history_store(bm, ele_act);
+ WM_event_add_mousemove(C);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_polybuild_transform_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Transform at Cursor";
+ ot->idname = "MESH_OT_polybuild_transform_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_transform_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
+static int edbm_polybuild_delete_at_cursor_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ bool changed = false;
+
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ if (!ele_act) {
+ return OPERATOR_CANCELLED;
+ }
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ if (ele_act->head.htype == BM_FACE) {
+ BMFace *f_act = (BMFace *)ele_act;
+ EDBM_flag_disable_all(em, BM_ELEM_TAG);
+ BM_elem_flag_enable(f_act, BM_ELEM_TAG);
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_TAG, DEL_FACES)) {
+ return OPERATOR_CANCELLED;
+ }
+ changed = true;
+ }
+ if (ele_act->head.htype == BM_VERT) {
+ BMVert *v_act = (BMVert *)ele_act;
+ if (BM_vert_is_edge_pair(v_act)) {
+ BM_edge_collapse(bm, v_act->e, v_act, true, true);
+ changed = true;
+ }
+ else {
+ EDBM_flag_disable_all(em, BM_ELEM_TAG);
+ BM_elem_flag_enable(v_act, BM_ELEM_TAG);
+
+ if (!EDBM_op_callf(em,
+ op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_TAG,
+ false,
+ false)) {
+ return OPERATOR_CANCELLED;
+ }
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ if (basact != NULL) {
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
+ WM_event_add_mousemove(C);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void MESH_OT_polybuild_delete_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Delete at Cursor";
+ ot->idname = "MESH_OT_polybuild_delete_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_delete_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Face at Cursor
* \{ */
-static int edbm_polybuild_face_at_cursor_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *event)
+static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
float center[3];
bool changed = false;
@@ -168,20 +313,27 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C,
mul_m4_v3(vc.obedit->obmat, center);
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
mul_m4_v3(vc.obedit->imat, center);
-
- BMVert *v_tri[3];
- v_tri[0] = e_act->v1;
- v_tri[1] = e_act->v2;
- v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
- if (e_act->l && e_act->l->v == v_tri[0]) {
- SWAP(BMVert *, v_tri[0], v_tri[1]);
+ if (f_reference->len == 3 && RNA_boolean_get(op->ptr, "create_quads")) {
+ const float fac = line_point_factor_v3(center, e_act->v1->co, e_act->v2->co);
+ BMVert *v_new = BM_edge_split(bm, e_act, e_act->v1, NULL, CLAMPIS(fac, 0.0f, 1.0f));
+ copy_v3_v3(v_new->co, center);
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_new, true);
+ BM_select_history_store(bm, v_new);
+ }
+ else {
+ BMVert *v_tri[3];
+ v_tri[0] = e_act->v1;
+ v_tri[1] = e_act->v2;
+ v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
+ if (e_act->l && e_act->l->v == v_tri[0]) {
+ SWAP(BMVert *, v_tri[0], v_tri[1]);
+ }
+ BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_tri[2], true);
+ BM_select_history_store(bm, v_tri[2]);
}
- // BMFace *f_new =
- BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
-
- edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
- BM_vert_select_set(bm, v_tri[2], true);
- BM_select_history_store(bm, v_tri[2]);
changed = true;
}
else if (ele_act->head.htype == BM_VERT) {
@@ -281,6 +433,11 @@ void MESH_OT_polybuild_face_at_cursor(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_boolean(ot->srna,
+ "create_quads",
+ true,
+ "Create quads",
+ "Automatically split edges in triangles to maintain quad topology");
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
}
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
index a3e684a5493..05c4da68355 100644
--- a/source/blender/editors/mesh/editmesh_preselect_elem.c
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -75,20 +75,49 @@ struct EditMesh_PreSelElem {
float (*verts)[3];
int verts_len;
+
+ float (*preview_tris)[3][3];
+ int preview_tris_len;
+ float (*preview_lines)[2][3];
+ int preview_lines_len;
+
+ eEditMesh_PreSelPreviewAction preview_action;
};
+void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
+ eEditMesh_PreSelPreviewAction action)
+{
+ psel->preview_action = action;
+}
+
+eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel)
+{
+ return psel->preview_action;
+}
+
struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void)
{
struct EditMesh_PreSelElem *psel = MEM_callocN(sizeof(*psel), __func__);
+ psel->preview_action = PRESELECT_ACTION_TRANSFORM;
return psel;
}
void EDBM_preselect_elem_destroy(struct EditMesh_PreSelElem *psel)
{
EDBM_preselect_elem_clear(psel);
+ EDBM_preselect_preview_clear(psel);
MEM_freeN(psel);
}
+void EDBM_preselect_preview_clear(struct EditMesh_PreSelElem *psel)
+{
+ MEM_SAFE_FREE(psel->preview_tris);
+ psel->preview_tris_len = 0;
+
+ MEM_SAFE_FREE(psel->preview_lines);
+ psel->preview_lines_len = 0;
+}
+
void EDBM_preselect_elem_clear(struct EditMesh_PreSelElem *psel)
{
MEM_SAFE_FREE(psel->edges);
@@ -112,9 +141,42 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformColor3ub(255, 0, 255);
+
+ immUniformColor4ub(141, 171, 186, 100);
+ if (psel->preview_action != PRESELECT_ACTION_TRANSFORM) {
+ if (psel->preview_tris_len > 0) {
+ immBegin(GPU_PRIM_TRIS, psel->preview_tris_len * 3);
+
+ for (int i = 0; i < psel->preview_tris_len; i++) {
+ immVertex3fv(pos, psel->preview_tris[i][0]);
+ immVertex3fv(pos, psel->preview_tris[i][1]);
+ immVertex3fv(pos, psel->preview_tris[i][2]);
+ }
+ immEnd();
+ }
+
+ if (psel->preview_lines_len > 0) {
+
+ immUniformColor4ub(3, 161, 252, 200);
+ GPU_line_width(2.0f);
+ immBegin(GPU_PRIM_LINES, psel->preview_lines_len * 2);
+ for (int i = 0; i < psel->preview_lines_len; i++) {
+ immVertex3fv(pos, psel->preview_lines[i][0]);
+ immVertex3fv(pos, psel->preview_lines[i][1]);
+ }
+ immEnd();
+ }
+ }
+
+ if (psel->preview_action == PRESELECT_ACTION_DELETE) {
+ immUniformColor4ub(252, 49, 10, 200);
+ }
+ else {
+ immUniformColor4ub(3, 161, 252, 200);
+ }
if (psel->edges_len > 0) {
+ GPU_line_width(3.0f);
immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
for (int i = 0; i < psel->edges_len; i++) {
@@ -126,7 +188,7 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
}
if (psel->verts_len > 0) {
- GPU_point_size(3.0f);
+ GPU_point_size(4.0f);
immBegin(GPU_PRIM_POINTS, psel->verts_len);
@@ -167,6 +229,122 @@ static void view3d_preselect_mesh_elem_update_from_edge(struct EditMesh_PreSelEl
psel->edges_len = 1;
}
+static void view3d_preselect_update_preview_triangle_from_vert(struct EditMesh_PreSelElem *psel,
+ ViewContext *vc,
+ BMesh *UNUSED(bm),
+ BMVert *eed,
+ const int mval[2])
+{
+ BMVert *v_act = eed;
+ BMEdge *e_pair[2] = {NULL};
+ float center[3];
+
+ if (v_act->e != NULL) {
+ for (uint allow_wire = 0; allow_wire < 2 && (e_pair[1] == NULL); allow_wire++) {
+ int i = 0;
+ BMEdge *e_iter = v_act->e;
+ do {
+ if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) &&
+ (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter))) {
+ if (i == 2) {
+ e_pair[0] = e_pair[1] = NULL;
+ break;
+ }
+ e_pair[i++] = e_iter;
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_act)) != v_act->e);
+ }
+ }
+
+ if (e_pair[1] != NULL) {
+ mul_v3_m4v3(center, vc->obedit->obmat, v_act->co);
+ ED_view3d_win_to_3d_int(vc->v3d, vc->ar, center, mval, center);
+ mul_m4_v3(vc->obedit->imat, center);
+
+ psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris) * 2, __func__);
+ psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 4, __func__);
+
+ copy_v3_v3(psel->preview_tris[0][0], e_pair[0]->v1->co);
+ copy_v3_v3(psel->preview_tris[0][1], e_pair[0]->v2->co);
+ copy_v3_v3(psel->preview_tris[0][2], center);
+
+ copy_v3_v3(psel->preview_tris[1][0], e_pair[1]->v1->co);
+ copy_v3_v3(psel->preview_tris[1][1], e_pair[1]->v2->co);
+ copy_v3_v3(psel->preview_tris[1][2], center);
+
+ copy_v3_v3(psel->preview_lines[0][0], e_pair[0]->v1->co);
+ copy_v3_v3(psel->preview_lines[0][1], e_pair[0]->v2->co);
+
+ copy_v3_v3(psel->preview_lines[1][0], e_pair[1]->v1->co);
+ copy_v3_v3(psel->preview_lines[1][1], e_pair[1]->v2->co);
+
+ copy_v3_v3(psel->preview_lines[2][0], center);
+ if (e_pair[0]->v1 == v_act) {
+ copy_v3_v3(psel->preview_lines[2][1], e_pair[0]->v2->co);
+ }
+ else {
+ copy_v3_v3(psel->preview_lines[2][1], e_pair[0]->v1->co);
+ }
+
+ copy_v3_v3(psel->preview_lines[3][0], center);
+ if (e_pair[1]->v1 == v_act) {
+ copy_v3_v3(psel->preview_lines[3][1], e_pair[1]->v2->co);
+ }
+ else {
+ copy_v3_v3(psel->preview_lines[3][1], e_pair[1]->v1->co);
+ }
+ psel->preview_tris_len = 2;
+ psel->preview_lines_len = 4;
+ }
+}
+
+static void view3d_preselect_update_preview_triangle_from_face(struct EditMesh_PreSelElem *psel,
+ ViewContext *UNUSED(vc),
+ BMesh *UNUSED(bm),
+ BMFace *efa,
+ const int UNUSED(mval[2]))
+{
+ float(*preview_lines)[2][3] = MEM_mallocN(sizeof(*psel->edges) * efa->len, __func__);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ int i = 0;
+ do {
+ vcos_get_pair(&l_iter->e->v1, preview_lines[i++], NULL);
+ } while ((l_iter = l_iter->next) != l_first);
+ psel->preview_lines = preview_lines;
+ psel->preview_lines_len = efa->len;
+}
+
+static void view3d_preselect_update_preview_triangle_from_edge(struct EditMesh_PreSelElem *psel,
+ ViewContext *vc,
+ BMesh *UNUSED(bm),
+ BMEdge *eed,
+ const int mval[2])
+{
+ float center[3];
+ psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris), __func__);
+ psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 3, __func__);
+ mid_v3_v3v3(center, eed->v1->co, eed->v2->co);
+ mul_m4_v3(vc->obedit->obmat, center);
+ ED_view3d_win_to_3d_int(vc->v3d, vc->ar, center, mval, center);
+ mul_m4_v3(vc->obedit->imat, center);
+
+ copy_v3_v3(psel->preview_tris[0][0], eed->v1->co);
+ copy_v3_v3(psel->preview_tris[0][1], eed->v2->co);
+ copy_v3_v3(psel->preview_tris[0][2], center);
+
+ copy_v3_v3(psel->preview_lines[0][0], eed->v1->co);
+ copy_v3_v3(psel->preview_lines[0][1], eed->v2->co);
+
+ copy_v3_v3(psel->preview_lines[1][0], eed->v2->co);
+ copy_v3_v3(psel->preview_lines[1][1], center);
+
+ copy_v3_v3(psel->preview_lines[2][0], center);
+ copy_v3_v3(psel->preview_lines[2][1], eed->v1->co);
+ psel->preview_tris_len = 1;
+ psel->preview_lines_len = 3;
+}
+
static void view3d_preselect_mesh_elem_update_from_face(struct EditMesh_PreSelElem *psel,
BMesh *UNUSED(bm),
BMFace *efa,
@@ -209,4 +387,28 @@ void EDBM_preselect_elem_update_from_single(struct EditMesh_PreSelElem *psel,
}
}
+void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
+ struct ViewContext *vc,
+ struct BMesh *bm,
+ struct BMElem *ele,
+ const int mval[2])
+{
+ EDBM_preselect_preview_clear(psel);
+
+ switch (ele->head.htype) {
+ case BM_VERT:
+ if (EDBM_preselect_action_get(psel) == PRESELECT_ACTION_CREATE) {
+ view3d_preselect_update_preview_triangle_from_vert(psel, vc, bm, (BMVert *)ele, mval);
+ }
+ break;
+ case BM_EDGE:
+ view3d_preselect_update_preview_triangle_from_edge(psel, vc, bm, (BMEdge *)ele, mval);
+ break;
+ case BM_FACE:
+ view3d_preselect_update_preview_triangle_from_face(psel, vc, bm, (BMFace *)ele, mval);
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 94ffd9a34d6..c0bd9e9f14c 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -24,7 +24,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_bitmap.h"
-#include "BLI_bitmap_draw_2d.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
@@ -35,13 +34,9 @@
#include "BKE_context.h"
#include "BKE_report.h"
-#include "BKE_paint.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -67,7 +62,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "DRW_engine.h"
#include "DRW_select_buffer.h"
#include "mesh_intern.h" /* own include */
@@ -172,30 +166,6 @@ void EDBM_select_mirrored(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Select Auto-Merge
- *
- * Used after transform operations.
- * \{ */
-
-void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag)
-{
- bool ok;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- ok = BMO_op_callf(em->bm,
- BMO_FLAG_DEFAULTS,
- "automerge verts=%hv dist=%f",
- hflag,
- scene->toolsettings->doublimit);
-
- if (LIKELY(ok) && update) {
- EDBM_update_generic(em, true, true);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Back-Buffer OpenGL Selection
* \{ */
@@ -1031,8 +1001,11 @@ bool EDBM_unified_findnearest(ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
Base **bases,
const uint bases_len,
- bool use_boundary,
- int *r_base_index,
+ bool use_boundary_vertices,
+ bool use_boundary_edges,
+ int *r_base_index_vert,
+ int *r_base_index_edge,
+ int *r_base_index_face,
struct BMVert **r_eve,
struct BMEdge **r_eed,
struct BMFace **r_efa)
@@ -1045,10 +1018,30 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
uint base_index;
BMElem *ele;
} best = {0, NULL};
+ /* Currently unused, keep since we may want to pick the best. */
+ UNUSED_VARS(best);
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_vert = {0, NULL};
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_edge = {0, NULL};
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_face = {0, NULL};
if (ED_view3d_win_to_ray_clipped(
vc->depsgraph, vc->ar, vc->v3d, mval_fl, ray_origin, ray_direction, true)) {
float dist_sq_best = FLT_MAX;
+ float dist_sq_best_vert = FLT_MAX;
+ float dist_sq_best_edge = FLT_MAX;
+ float dist_sq_best_face = FLT_MAX;
const bool use_vert = (r_eve != NULL);
const bool use_edge = (r_eed != NULL);
@@ -1078,18 +1071,23 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
BM_mesh_elem_index_ensure(bm, BM_VERT);
}
- if (use_boundary && (use_vert || use_edge)) {
+ if ((use_boundary_vertices || use_boundary_edges) && (use_vert || use_edge)) {
BMEdge *e;
BMIter eiter;
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) && (BM_edge_is_boundary(e))) {
- if (use_vert) {
+ if (use_vert && use_boundary_vertices) {
for (uint j = 0; j < 2; j++) {
BMVert *v = *((&e->v1) + j);
float point[3];
mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_vert) {
+ dist_sq_best_vert = dist_sq_test;
+ best_vert.base_index = base_index;
+ best_vert.ele = (BMElem *)v;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1098,7 +1096,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
- if (use_edge) {
+ if (use_edge && use_boundary_edges) {
float point[3];
#if 0
const float dist_sq_test = dist_squared_ray_to_seg_v3(
@@ -1114,6 +1112,11 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
mul_m4_v3(obedit->obmat, point);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_edge) {
+ dist_sq_best_edge = dist_sq_test;
+ best_edge.base_index = base_index;
+ best_edge.ele = (BMElem *)e;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1124,46 +1127,55 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
}
- else {
- /* Non boundary case. */
- if (use_vert) {
- BMVert *v;
- BMIter viter;
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
- float point[3];
- mul_v3_m4v3(point, obedit->obmat, v->co);
- const float dist_sq_test = dist_squared_to_ray_v3_normalized(
- ray_origin, ray_direction, v->co);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- best.base_index = base_index;
- best.ele = (BMElem *)v;
- }
+ /* Non boundary case. */
+ if (use_vert && !use_boundary_vertices) {
+ BMVert *v;
+ BMIter viter;
+ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
+ const float dist_sq_test = dist_squared_to_ray_v3_normalized(
+ ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_vert) {
+ dist_sq_best_vert = dist_sq_test;
+ best_vert.base_index = base_index;
+ best_vert.ele = (BMElem *)v;
+ }
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)v;
}
}
}
- if (use_edge) {
- BMEdge *e;
- BMIter eiter;
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
- float point[3];
- if (coords) {
- mid_v3_v3v3(
- point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
- }
- else {
- mid_v3_v3v3(point, e->v1->co, e->v2->co);
- }
- mul_m4_v3(obedit->obmat, point);
- const float dist_sq_test = dist_squared_to_ray_v3_normalized(
- ray_origin, ray_direction, point);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- best.base_index = base_index;
- best.ele = (BMElem *)e;
- }
+ }
+
+ if (use_edge && !use_boundary_edges) {
+ BMEdge *e;
+ BMIter eiter;
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ if (coords) {
+ mid_v3_v3v3(
+ point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
+ }
+ else {
+ mid_v3_v3v3(point, e->v1->co, e->v2->co);
+ }
+ mul_m4_v3(obedit->obmat, point);
+ const float dist_sq_test = dist_squared_to_ray_v3_normalized(
+ ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_edge) {
+ dist_sq_best_edge = dist_sq_test;
+ best_edge.base_index = base_index;
+ best_edge.ele = (BMElem *)e;
+ }
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)e;
}
}
}
@@ -1184,6 +1196,11 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
mul_m4_v3(obedit->obmat, point);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_face) {
+ dist_sq_best_face = dist_sq_test;
+ best_face.base_index = base_index;
+ best_face.ele = (BMElem *)f;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1195,7 +1212,10 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
- *r_base_index = best.base_index;
+ *r_base_index_vert = best_vert.base_index;
+ *r_base_index_edge = best_edge.base_index;
+ *r_base_index_face = best_face.base_index;
+
if (r_eve) {
*r_eve = NULL;
}
@@ -1206,22 +1226,17 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
*r_efa = NULL;
}
- if (best.ele) {
- switch (best.ele->head.htype) {
- case BM_VERT:
- *r_eve = (BMVert *)best.ele;
- break;
- case BM_EDGE:
- *r_eed = (BMEdge *)best.ele;
- break;
- case BM_FACE:
- *r_efa = (BMFace *)best.ele;
- break;
- default:
- BLI_assert(0);
- }
+ if (best_vert.ele) {
+ *r_eve = (BMVert *)best_vert.ele;
+ }
+ if (best_edge.ele) {
+ *r_eed = (BMEdge *)best_edge.ele;
}
- return (best.ele != NULL);
+ if (best_face.ele) {
+ *r_efa = (BMFace *)best_face.ele;
+ }
+
+ return (best_vert.ele != NULL || best_edge.ele != NULL || best_face.ele != NULL);
}
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 65c058556f5..0c4db012786 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -437,6 +437,7 @@ void EDBM_project_snap_verts(bContext *C, Depsgraph *depsgraph, ARegion *ar, BME
},
mval,
NULL,
+ NULL,
co_proj,
NULL)) {
mul_v3_m4v3(eve->co, obedit->imat, co_proj);
@@ -3130,12 +3131,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT);
if (use_unselected) {
- EDBM_op_init(em, &bmop, op, "automerge verts=%hv dist=%f", BM_ELEM_SELECT, threshold);
- BMO_op_exec(em->bm, &bmop);
-
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- continue;
- }
+ EDBM_automerge(obedit, false, BM_ELEM_SELECT, threshold);
}
else {
EDBM_op_init(em, &bmop, op, "find_doubles verts=%hv dist=%f", BM_ELEM_SELECT, threshold);
@@ -4040,7 +4036,7 @@ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const
ma_obdata = NULL;
}
- BKE_material_clear_id(bmain, obdata, true);
+ BKE_material_clear_id(bmain, obdata);
BKE_material_resize_object(bmain, ob, 1, true);
BKE_material_resize_id(bmain, obdata, 1, true);
@@ -4051,7 +4047,7 @@ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const
id_us_plus((ID *)ma_obdata);
}
else {
- BKE_material_clear_id(bmain, obdata, true);
+ BKE_material_clear_id(bmain, obdata);
BKE_material_resize_object(bmain, ob, 0, true);
BKE_material_resize_id(bmain, obdata, 0, true);
}
@@ -5710,7 +5706,7 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
"use_dissolve_boundaries",
false,
"All Boundaries",
- "Dissolve all vertices inbetween face boundaries");
+ "Dissolve all vertices in between face boundaries");
RNA_def_enum_flag(ot->srna,
"delimit",
rna_enum_mesh_delimit_mode_items,
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index d7ed14184fa..522c2f32d27 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -85,7 +85,7 @@ void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess)
tmpbm = NULL;
if (recalctess) {
- BKE_editmesh_tessface_calc(em);
+ BKE_editmesh_looptri_calc(em);
}
}
@@ -105,7 +105,7 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
backup->bmcopy = NULL;
if (recalctess && em) {
- BKE_editmesh_tessface_calc(em);
+ BKE_editmesh_looptri_calc(em);
}
}
@@ -162,7 +162,7 @@ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool
/* when copying, tessellation isn't to for faster copying,
* but means we need to re-tessellate here */
if (em->looptris == NULL) {
- BKE_editmesh_tessface_calc(em);
+ BKE_editmesh_looptri_calc(em);
}
if (em->ob) {
@@ -292,10 +292,6 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
Mesh *me = ob->data;
BMesh *bm;
- if (UNLIKELY(!me->mpoly && me->totface)) {
- BKE_mesh_convert_mfaces_to_mpolys(me);
- }
-
bm = BKE_mesh_to_bmesh(me,
ob,
add_key_index,
@@ -347,10 +343,6 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
.calc_object_remap = true,
}));
-#ifdef USE_TESSFACE_DEFAULT
- BKE_mesh_tessface_calc(me);
-#endif
-
/* Free derived mesh. usually this would happen through depsgraph but there
* are exceptions like file save that will not cause this, and we want to
* avoid ending up with an invalid derived mesh then.
@@ -1397,15 +1389,15 @@ void EDBM_stats_update(BMEditMesh *em)
/* so many tools call these that we better make it a generic function.
*/
-void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive)
+void EDBM_update_generic(BMEditMesh *em, const bool do_tessellation, const bool is_destructive)
{
Object *ob = em->ob;
/* order of calling isn't important */
DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, ob->data);
- if (do_tessface) {
- BKE_editmesh_tessface_calc(em);
+ if (do_tessellation) {
+ BKE_editmesh_looptri_calc(em);
}
if (is_destructive) {
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index ee8de9d8ea9..569994bead1 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -289,18 +289,14 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set, co
if (me->mloopuv && do_init) {
CustomData_add_layer_named(
&me->ldata, CD_MLOOPUV, CD_DUPLICATE, me->mloopuv, me->totloop, name);
- CustomData_add_layer_named(
- &me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface, name);
is_init = true;
}
else {
CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, name);
- CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface, name);
}
if (active_set || layernum_dst == 0) {
CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, layernum_dst);
- CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum_dst);
}
BKE_mesh_update_customdata_pointers(me, true);
@@ -418,16 +414,13 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set, const b
if (me->mloopcol && do_init) {
CustomData_add_layer_named(
&me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop, name);
- CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface, name);
}
else {
CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name);
- CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface, name);
}
if (active_set || layernum == 0) {
CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum);
- CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);
}
BKE_mesh_update_customdata_pointers(me, true);
@@ -885,18 +878,8 @@ void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot)
/************************** Add Geometry Layers *************************/
-void ED_mesh_update(
- Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_loose, bool calc_tessface)
+void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_loose)
{
- bool tessface_input = false;
-
- if (mesh->totface > 0 && mesh->totpoly == 0) {
- BKE_mesh_convert_mfaces_to_mpolys(mesh);
-
- /* would only be converting back again, don't bother */
- tessface_input = true;
- }
-
if (calc_edges_loose && mesh->totedge) {
BKE_mesh_calc_edges_loose(mesh);
}
@@ -905,15 +888,8 @@ void ED_mesh_update(
BKE_mesh_calc_edges(mesh, calc_edges, true);
}
- if (calc_tessface) {
- if (tessface_input == false) {
- BKE_mesh_tessface_calc(mesh);
- }
- }
- else {
- /* default state is not to have tessface's so make sure this is the case */
- BKE_mesh_tessface_clear(mesh);
- }
+ /* Default state is not to have tessface's so make sure this is the case. */
+ BKE_mesh_tessface_clear(mesh);
BKE_mesh_calc_normals(mesh);
@@ -988,39 +964,6 @@ static void mesh_add_edges(Mesh *mesh, int len)
mesh->totedge = totedge;
}
-static void mesh_add_tessfaces(Mesh *mesh, int len)
-{
- CustomData fdata;
- MFace *mface;
- int i, totface;
-
- if (len == 0) {
- return;
- }
-
- totface = mesh->totface + len; /* new face count */
-
- /* update customdata */
- CustomData_copy(&mesh->fdata, &fdata, CD_MASK_MESH.fmask, CD_DEFAULT, totface);
- CustomData_copy_data(&mesh->fdata, &fdata, 0, 0, mesh->totface);
-
- if (!CustomData_has_layer(&fdata, CD_MFACE)) {
- CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
- }
-
- CustomData_free(&mesh->fdata, mesh->totface);
- mesh->fdata = fdata;
- BKE_mesh_update_customdata_pointers(mesh, true);
-
- /* set default flags */
- mface = &mesh->mface[mesh->totface];
- for (i = 0; i < len; i++, mface++) {
- mface->flag = ME_FACE_SEL;
- }
-
- mesh->totface = totface;
-}
-
static void mesh_add_loops(Mesh *mesh, int len)
{
CustomData ldata;
@@ -1109,20 +1052,6 @@ static void mesh_remove_edges(Mesh *mesh, int len)
mesh->totedge = totedge;
}
-static void mesh_remove_faces(Mesh *mesh, int len)
-{
- int totface;
-
- if (len == 0) {
- return;
- }
-
- totface = mesh->totface - len; /* new face count */
- CustomData_free_elem(&mesh->fdata, totface, len);
-
- mesh->totface = totface;
-}
-
#if 0
void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces)
{
@@ -1143,21 +1072,6 @@ void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges,
}
#endif
-void ED_mesh_tessfaces_add(Mesh *mesh, ReportList *reports, int count)
-{
- if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add tessfaces in edit mode");
- return;
- }
-
- if (mesh->mpoly) {
- BKE_report(reports, RPT_ERROR, "Cannot add tessfaces to a mesh that already has polygons");
- return;
- }
-
- mesh_add_tessfaces(mesh, count);
-}
-
void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count)
{
if (mesh->edit_mesh) {
@@ -1178,20 +1092,6 @@ void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count)
mesh_add_verts(mesh, count);
}
-void ED_mesh_faces_remove(Mesh *mesh, ReportList *reports, int count)
-{
- if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot remove faces in edit mode");
- return;
- }
- else if (count > mesh->totface) {
- BKE_report(reports, RPT_ERROR, "Cannot remove more faces than the mesh contains");
- return;
- }
-
- mesh_remove_faces(mesh, count);
-}
-
void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count)
{
if (mesh->edit_mesh) {
@@ -1240,26 +1140,6 @@ void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count)
mesh_add_polys(mesh, count);
}
-void ED_mesh_calc_tessface(Mesh *mesh, bool free_mpoly)
-{
- if (mesh->edit_mesh) {
- BKE_editmesh_tessface_calc(mesh->edit_mesh);
- }
- else {
- BKE_mesh_tessface_calc(mesh);
- }
- if (free_mpoly) {
- CustomData_free(&mesh->ldata, mesh->totloop);
- CustomData_free(&mesh->pdata, mesh->totpoly);
- mesh->totloop = 0;
- mesh->totpoly = 0;
- mesh->mloop = NULL;
- mesh->mloopcol = NULL;
- mesh->mloopuv = NULL;
- mesh->mpoly = NULL;
- }
-}
-
void ED_mesh_report_mirror_ex(wmOperator *op, int totmirr, int totfail, char selectmode)
{
const char *elem_type;
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 8d585977105..3558a07c6fb 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -122,6 +122,8 @@ void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt);
void MESH_OT_polybuild_face_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_split_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_dissolve_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_transform_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_delete_at_cursor(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
void MESH_OT_inset(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index c3387dcfc09..9b6e991a9f5 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -145,6 +145,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_polybuild_face_at_cursor);
WM_operatortype_append(MESH_OT_polybuild_split_at_cursor);
WM_operatortype_append(MESH_OT_polybuild_dissolve_at_cursor);
+ WM_operatortype_append(MESH_OT_polybuild_transform_at_cursor);
+ WM_operatortype_append(MESH_OT_polybuild_delete_at_cursor);
WM_operatortype_append(MESH_OT_uv_texture_add);
WM_operatortype_append(MESH_OT_uv_texture_remove);
@@ -331,6 +333,25 @@ void ED_operatormacros_mesh(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ ot = WM_operatortype_append_macro("MESH_OT_polybuild_transform_at_cursor_move",
+ "Transform at Cursor Move",
+ "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ ot = WM_operatortype_append_macro("MESH_OT_polybuild_extrude_at_cursor_move",
+ "Extrude at Cursor Move",
+ "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
}
/* note mesh keymap also for other space? */