diff options
author | YimingWu <xp8110@outlook.com> | 2019-09-04 06:30:16 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2019-09-04 06:30:16 +0300 |
commit | 55a6fc0be3ffa823052aba45bec12c6902e7bd53 (patch) | |
tree | fb8cb4e411e22fcb49e443ea4da636660618877f /source/blender/editors/mesh | |
parent | afac2afbfcdb06a2d2655e63d0b8bc35b1aba18e (diff) | |
parent | da25aca2677ec2b566cad1809eebceee22b28b53 (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.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_automerge.c | 517 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c | 13 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife.c | 4 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_polybuild.c | 189 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_preselect_elem.c | 206 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_select.c | 191 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_tools.c | 14 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_utils.c | 20 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_data.c | 126 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_ops.c | 21 |
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? */ |