diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/mesh | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/mesh')
31 files changed, 27949 insertions, 26864 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 707aeb781c6..e67d63b01a5 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -16,77 +16,77 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ../include - ../uvedit - ../../blenkernel - ../../blenlib - ../../blentranslation - ../../depsgraph - ../../bmesh - ../../gpu - ../../imbuf - ../../makesdna - ../../makesrna - ../../render/extern/include - ../../windowmanager - ../../../../intern/clog - ../../../../intern/guardedalloc - ../../../../intern/glew-mx + ../include + ../uvedit + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../depsgraph + ../../bmesh + ../../gpu + ../../imbuf + ../../makesdna + ../../makesrna + ../../render/extern/include + ../../windowmanager + ../../../../intern/clog + ../../../../intern/guardedalloc + ../../../../intern/glew-mx ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${GLEW_INCLUDE_PATH} ) set(SRC - editface.c - editmesh_add.c - editmesh_add_gizmo.c - editmesh_bevel.c - editmesh_bisect.c - editmesh_extrude.c - editmesh_extrude_screw.c - editmesh_extrude_spin.c - editmesh_extrude_spin_gizmo.c - editmesh_inset.c - editmesh_intersect.c - editmesh_knife.c - editmesh_knife_project.c - editmesh_loopcut.c - editmesh_path.c - editmesh_polybuild.c - editmesh_preselect_edgering.c - editmesh_preselect_elem.c - editmesh_rip.c - editmesh_rip_edge.c - editmesh_select.c - editmesh_select_similar.c - editmesh_tools.c - editmesh_undo.c - editmesh_utils.c - mesh_data.c - mesh_mirror.c - mesh_ops.c - meshtools.c + editface.c + editmesh_add.c + editmesh_add_gizmo.c + editmesh_bevel.c + editmesh_bisect.c + editmesh_extrude.c + editmesh_extrude_screw.c + editmesh_extrude_spin.c + editmesh_extrude_spin_gizmo.c + editmesh_inset.c + editmesh_intersect.c + editmesh_knife.c + editmesh_knife_project.c + editmesh_loopcut.c + editmesh_path.c + editmesh_polybuild.c + editmesh_preselect_edgering.c + editmesh_preselect_elem.c + editmesh_rip.c + editmesh_rip_edge.c + editmesh_select.c + editmesh_select_similar.c + editmesh_tools.c + editmesh_undo.c + editmesh_utils.c + mesh_data.c + mesh_mirror.c + mesh_ops.c + meshtools.c - mesh_intern.h + mesh_intern.h ) set(LIB - bf_blenkernel - bf_blenlib + bf_blenkernel + bf_blenlib ) if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) endif() if(WITH_FREESTYLE) - add_definitions(-DWITH_FREESTYLE) + add_definitions(-DWITH_FREESTYLE) endif() if(WITH_BULLET) - add_definitions(-DWITH_BULLET) + add_definitions(-DWITH_BULLET) endif() add_definitions(${GL_DEFINITIONS}) diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 7a6144d8e0f..f342cc3a809 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -57,601 +57,603 @@ * use in object mode when selecting faces (while painting) */ void paintface_flush_flags(struct bContext *C, Object *ob, short flag) { - Mesh *me = BKE_mesh_from_object(ob); - MPoly *polys, *mp_orig; - const int *index_array = NULL; - int totpoly; - int i; - - BLI_assert((flag & ~(SELECT | ME_HIDE)) == 0); - - if (me == NULL) - return; - - /* note, call #BKE_mesh_flush_hidden_from_verts_ex first when changing hidden flags */ - - /* we could call this directly in all areas that change selection, - * since this could become slow for realtime updates (circle-select for eg) */ - if (flag & SELECT) { - BKE_mesh_flush_select_from_polys(me); - } - - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - - if (ob_eval == NULL) { - return; - } - - Mesh *me_orig = ob_eval->runtime.mesh_orig; - Mesh *me_eval = ob_eval->runtime.mesh_eval; - bool updated = false; - - if (me_orig != NULL && me_eval != NULL && me_orig->totpoly == me->totpoly) { - /* Update the COW copy of the mesh. */ - for (i = 0; i < me->totpoly; i++) { - me_orig->mpoly[i].flag = me->mpoly[i].flag; - } - - /* If the mesh has only deform modifiers, the evaluated mesh shares arrays. */ - if (me_eval->mpoly == me_orig->mpoly) { - updated = true; - } - /* Mesh polys => Final derived polys */ - else if ((index_array = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX))) { - polys = me_eval->mpoly; - totpoly = me_eval->totpoly; - - /* loop over final derived polys */ - for (i = 0; i < totpoly; i++) { - if (index_array[i] != ORIGINDEX_NONE) { - /* Copy flags onto the final derived poly from the original mesh poly */ - mp_orig = me->mpoly + index_array[i]; - polys[i].flag = mp_orig->flag; - - } - } - - updated = true; - } - } - - if (updated) { - if (flag & ME_HIDE) { - BKE_mesh_batch_cache_dirty_tag(me_eval, BKE_MESH_BATCH_DIRTY_ALL); - } - else { - BKE_mesh_batch_cache_dirty_tag(me_eval, BKE_MESH_BATCH_DIRTY_SELECT); - } - - DEG_id_tag_update(ob->data, ID_RECALC_SELECT); - } - else { - DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - } - - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); + Mesh *me = BKE_mesh_from_object(ob); + MPoly *polys, *mp_orig; + const int *index_array = NULL; + int totpoly; + int i; + + BLI_assert((flag & ~(SELECT | ME_HIDE)) == 0); + + if (me == NULL) + return; + + /* note, call #BKE_mesh_flush_hidden_from_verts_ex first when changing hidden flags */ + + /* we could call this directly in all areas that change selection, + * since this could become slow for realtime updates (circle-select for eg) */ + if (flag & SELECT) { + BKE_mesh_flush_select_from_polys(me); + } + + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + + if (ob_eval == NULL) { + return; + } + + Mesh *me_orig = ob_eval->runtime.mesh_orig; + Mesh *me_eval = ob_eval->runtime.mesh_eval; + bool updated = false; + + if (me_orig != NULL && me_eval != NULL && me_orig->totpoly == me->totpoly) { + /* Update the COW copy of the mesh. */ + for (i = 0; i < me->totpoly; i++) { + me_orig->mpoly[i].flag = me->mpoly[i].flag; + } + + /* If the mesh has only deform modifiers, the evaluated mesh shares arrays. */ + if (me_eval->mpoly == me_orig->mpoly) { + updated = true; + } + /* Mesh polys => Final derived polys */ + else if ((index_array = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX))) { + polys = me_eval->mpoly; + totpoly = me_eval->totpoly; + + /* loop over final derived polys */ + for (i = 0; i < totpoly; i++) { + if (index_array[i] != ORIGINDEX_NONE) { + /* Copy flags onto the final derived poly from the original mesh poly */ + mp_orig = me->mpoly + index_array[i]; + polys[i].flag = mp_orig->flag; + } + } + + updated = true; + } + } + + if (updated) { + if (flag & ME_HIDE) { + BKE_mesh_batch_cache_dirty_tag(me_eval, BKE_MESH_BATCH_DIRTY_ALL); + } + else { + BKE_mesh_batch_cache_dirty_tag(me_eval, BKE_MESH_BATCH_DIRTY_SELECT); + } + + DEG_id_tag_update(ob->data, ID_RECALC_SELECT); + } + else { + DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); } void paintface_hide(bContext *C, Object *ob, const bool unselected) { - Mesh *me; - MPoly *mpoly; - int a; + Mesh *me; + MPoly *mpoly; + int a; - me = BKE_mesh_from_object(ob); - if (me == NULL || me->totpoly == 0) return; + me = BKE_mesh_from_object(ob); + if (me == NULL || me->totpoly == 0) + return; - mpoly = me->mpoly; - a = me->totpoly; - while (a--) { - if ((mpoly->flag & ME_HIDE) == 0) { - if (((mpoly->flag & ME_FACE_SEL) == 0) == unselected) { - mpoly->flag |= ME_HIDE; - } - } + mpoly = me->mpoly; + a = me->totpoly; + while (a--) { + if ((mpoly->flag & ME_HIDE) == 0) { + if (((mpoly->flag & ME_FACE_SEL) == 0) == unselected) { + mpoly->flag |= ME_HIDE; + } + } - if (mpoly->flag & ME_HIDE) { - mpoly->flag &= ~ME_FACE_SEL; - } + if (mpoly->flag & ME_HIDE) { + mpoly->flag &= ~ME_FACE_SEL; + } - mpoly++; - } + mpoly++; + } - BKE_mesh_flush_hidden_from_polys(me); + BKE_mesh_flush_hidden_from_polys(me); - paintface_flush_flags(C, ob, SELECT | ME_HIDE); + paintface_flush_flags(C, ob, SELECT | ME_HIDE); } - void paintface_reveal(bContext *C, Object *ob, const bool select) { - Mesh *me; - MPoly *mpoly; - int a; - - me = BKE_mesh_from_object(ob); - if (me == NULL || me->totpoly == 0) return; - - mpoly = me->mpoly; - a = me->totpoly; - while (a--) { - if (mpoly->flag & ME_HIDE) { - SET_FLAG_FROM_TEST(mpoly->flag, select, ME_FACE_SEL); - mpoly->flag &= ~ME_HIDE; - } - mpoly++; - } - - BKE_mesh_flush_hidden_from_polys(me); - - paintface_flush_flags(C, ob, SELECT | ME_HIDE); + Mesh *me; + MPoly *mpoly; + int a; + + me = BKE_mesh_from_object(ob); + if (me == NULL || me->totpoly == 0) + return; + + mpoly = me->mpoly; + a = me->totpoly; + while (a--) { + if (mpoly->flag & ME_HIDE) { + SET_FLAG_FROM_TEST(mpoly->flag, select, ME_FACE_SEL); + mpoly->flag &= ~ME_HIDE; + } + mpoly++; + } + + BKE_mesh_flush_hidden_from_polys(me); + + paintface_flush_flags(C, ob, SELECT | ME_HIDE); } /* Set tface seams based on edge data, uses hash table to find seam edges. */ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index, const bool select) { - MPoly *mp; - MLoop *ml; - int a, b; - bool do_it = true; - bool mark = false; - - BLI_bitmap *edge_tag = BLI_BITMAP_NEW(me->totedge, __func__); - BLI_bitmap *poly_tag = BLI_BITMAP_NEW(me->totpoly, __func__); - - if (index != (unsigned int)-1) { - /* only put face under cursor in array */ - mp = &me->mpoly[index]; - BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart); - BLI_BITMAP_ENABLE(poly_tag, index); - } - else { - /* fill array by selection */ - mp = me->mpoly; - for (a = 0; a < me->totpoly; a++, mp++) { - if (mp->flag & ME_HIDE) { - /* pass */ - } - else if (mp->flag & ME_FACE_SEL) { - BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart); - BLI_BITMAP_ENABLE(poly_tag, a); - } - } - } - - while (do_it) { - do_it = false; - - /* expand selection */ - mp = me->mpoly; - for (a = 0; a < me->totpoly; a++, mp++) { - if (mp->flag & ME_HIDE) - continue; - - if (!BLI_BITMAP_TEST(poly_tag, a)) { - mark = false; - - ml = me->mloop + mp->loopstart; - for (b = 0; b < mp->totloop; b++, ml++) { - if ((me->medge[ml->e].flag & ME_SEAM) == 0) { - if (BLI_BITMAP_TEST(edge_tag, ml->e)) { - mark = true; - break; - } - } - } - - if (mark) { - BLI_BITMAP_ENABLE(poly_tag, a); - BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart); - do_it = true; - } - } - } - } - - MEM_freeN(edge_tag); - - for (a = 0, mp = me->mpoly; a < me->totpoly; a++, mp++) { - if (BLI_BITMAP_TEST(poly_tag, a)) { - SET_FLAG_FROM_TEST(mp->flag, select, ME_FACE_SEL); - } - } - - MEM_freeN(poly_tag); + MPoly *mp; + MLoop *ml; + int a, b; + bool do_it = true; + bool mark = false; + + BLI_bitmap *edge_tag = BLI_BITMAP_NEW(me->totedge, __func__); + BLI_bitmap *poly_tag = BLI_BITMAP_NEW(me->totpoly, __func__); + + if (index != (unsigned int)-1) { + /* only put face under cursor in array */ + mp = &me->mpoly[index]; + BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart); + BLI_BITMAP_ENABLE(poly_tag, index); + } + else { + /* fill array by selection */ + mp = me->mpoly; + for (a = 0; a < me->totpoly; a++, mp++) { + if (mp->flag & ME_HIDE) { + /* pass */ + } + else if (mp->flag & ME_FACE_SEL) { + BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart); + BLI_BITMAP_ENABLE(poly_tag, a); + } + } + } + + while (do_it) { + do_it = false; + + /* expand selection */ + mp = me->mpoly; + for (a = 0; a < me->totpoly; a++, mp++) { + if (mp->flag & ME_HIDE) + continue; + + if (!BLI_BITMAP_TEST(poly_tag, a)) { + mark = false; + + ml = me->mloop + mp->loopstart; + for (b = 0; b < mp->totloop; b++, ml++) { + if ((me->medge[ml->e].flag & ME_SEAM) == 0) { + if (BLI_BITMAP_TEST(edge_tag, ml->e)) { + mark = true; + break; + } + } + } + + if (mark) { + BLI_BITMAP_ENABLE(poly_tag, a); + BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart); + do_it = true; + } + } + } + } + + MEM_freeN(edge_tag); + + for (a = 0, mp = me->mpoly; a < me->totpoly; a++, mp++) { + if (BLI_BITMAP_TEST(poly_tag, a)) { + SET_FLAG_FROM_TEST(mp->flag, select, ME_FACE_SEL); + } + } + + MEM_freeN(poly_tag); } void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const bool select) { - Mesh *me; - unsigned int index = (unsigned int)-1; + Mesh *me; + unsigned int index = (unsigned int)-1; - me = BKE_mesh_from_object(ob); - if (me == NULL || me->totpoly == 0) return; + me = BKE_mesh_from_object(ob); + if (me == NULL || me->totpoly == 0) + return; - if (mval) { - if (!ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) { - return; - } - } + if (mval) { + if (!ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) { + return; + } + } - select_linked_tfaces_with_seams(me, index, select); + select_linked_tfaces_with_seams(me, index, select); - paintface_flush_flags(C, ob, SELECT); + paintface_flush_flags(C, ob, SELECT); } bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags) { - Mesh *me; - MPoly *mpoly; - int a; - - me = BKE_mesh_from_object(ob); - if (me == NULL) { - return false; - } - - if (action == SEL_TOGGLE) { - action = SEL_SELECT; - - mpoly = me->mpoly; - a = me->totpoly; - while (a--) { - if ((mpoly->flag & ME_HIDE) == 0 && mpoly->flag & ME_FACE_SEL) { - action = SEL_DESELECT; - break; - } - mpoly++; - } - } - - bool changed = false; - - mpoly = me->mpoly; - a = me->totpoly; - while (a--) { - if ((mpoly->flag & ME_HIDE) == 0) { - switch (action) { - case SEL_SELECT: - if ((mpoly->flag & ME_FACE_SEL) == 0) { - mpoly->flag |= ME_FACE_SEL; - changed = true; - } - break; - case SEL_DESELECT: - if ((mpoly->flag & ME_FACE_SEL) != 0) { - mpoly->flag &= ~ME_FACE_SEL; - changed = true; - } - break; - case SEL_INVERT: - mpoly->flag ^= ME_FACE_SEL; - changed = true; - break; - } - } - mpoly++; - } - - if (changed) { - if (flush_flags) { - paintface_flush_flags(C, ob, SELECT); - } - } - return changed; + Mesh *me; + MPoly *mpoly; + int a; + + me = BKE_mesh_from_object(ob); + if (me == NULL) { + return false; + } + + if (action == SEL_TOGGLE) { + action = SEL_SELECT; + + mpoly = me->mpoly; + a = me->totpoly; + while (a--) { + if ((mpoly->flag & ME_HIDE) == 0 && mpoly->flag & ME_FACE_SEL) { + action = SEL_DESELECT; + break; + } + mpoly++; + } + } + + bool changed = false; + + mpoly = me->mpoly; + a = me->totpoly; + while (a--) { + if ((mpoly->flag & ME_HIDE) == 0) { + switch (action) { + case SEL_SELECT: + if ((mpoly->flag & ME_FACE_SEL) == 0) { + mpoly->flag |= ME_FACE_SEL; + changed = true; + } + break; + case SEL_DESELECT: + if ((mpoly->flag & ME_FACE_SEL) != 0) { + mpoly->flag &= ~ME_FACE_SEL; + changed = true; + } + break; + case SEL_INVERT: + mpoly->flag ^= ME_FACE_SEL; + changed = true; + break; + } + } + mpoly++; + } + + if (changed) { + if (flush_flags) { + paintface_flush_flags(C, ob, SELECT); + } + } + return changed; } bool paintface_minmax(Object *ob, float r_min[3], float r_max[3]) { - const Mesh *me; - const MPoly *mp; - const MLoop *ml; - const MVert *mvert; - int a, b; - bool ok = false; - float vec[3], bmat[3][3]; - - me = BKE_mesh_from_object(ob); - if (!me || !me->mloopuv) { - return ok; - } - - copy_m3_m4(bmat, ob->obmat); - - mvert = me->mvert; - mp = me->mpoly; - for (a = me->totpoly; a > 0; a--, mp++) { - if (mp->flag & ME_HIDE || !(mp->flag & ME_FACE_SEL)) - continue; - - ml = me->mloop + mp->totloop; - for (b = 0; b < mp->totloop; b++, ml++) { - mul_v3_m3v3(vec, bmat, mvert[ml->v].co); - add_v3_v3v3(vec, vec, ob->obmat[3]); - minmax_v3v3_v3(r_min, r_max, vec); - } - - ok = true; - } - - return ok; + const Mesh *me; + const MPoly *mp; + const MLoop *ml; + const MVert *mvert; + int a, b; + bool ok = false; + float vec[3], bmat[3][3]; + + me = BKE_mesh_from_object(ob); + if (!me || !me->mloopuv) { + return ok; + } + + copy_m3_m4(bmat, ob->obmat); + + mvert = me->mvert; + mp = me->mpoly; + for (a = me->totpoly; a > 0; a--, mp++) { + if (mp->flag & ME_HIDE || !(mp->flag & ME_FACE_SEL)) + continue; + + ml = me->mloop + mp->totloop; + for (b = 0; b < mp->totloop; b++, ml++) { + mul_v3_m3v3(vec, bmat, mvert[ml->v].co); + add_v3_v3v3(vec, vec, ob->obmat[3]); + minmax_v3v3_v3(r_min, r_max, vec); + } + + ok = true; + } + + return ok; } -bool paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], bool extend, bool deselect, bool toggle) +bool paintface_mouse_select( + struct bContext *C, Object *ob, const int mval[2], bool extend, bool deselect, bool toggle) { - Mesh *me; - MPoly *mpoly_sel; - uint index; - - /* Get the face under the cursor */ - me = BKE_mesh_from_object(ob); - - if (!ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) { - return false; - } - - if (index >= me->totpoly) { - return false; - } - - mpoly_sel = me->mpoly + index; - if (mpoly_sel->flag & ME_HIDE) return false; - - /* clear flags */ - if (!extend && !deselect && !toggle) { - paintface_deselect_all_visible(C, ob, SEL_DESELECT, false); - } - - me->act_face = (int)index; - - if (extend) { - mpoly_sel->flag |= ME_FACE_SEL; - } - else if (deselect) { - mpoly_sel->flag &= ~ME_FACE_SEL; - } - else if (toggle) { - if (mpoly_sel->flag & ME_FACE_SEL) - mpoly_sel->flag &= ~ME_FACE_SEL; - else - mpoly_sel->flag |= ME_FACE_SEL; - } - else { - mpoly_sel->flag |= ME_FACE_SEL; - } - - /* image window redraw */ - - paintface_flush_flags(C, ob, SELECT); - ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views - return true; + Mesh *me; + MPoly *mpoly_sel; + uint index; + + /* Get the face under the cursor */ + me = BKE_mesh_from_object(ob); + + if (!ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) { + return false; + } + + if (index >= me->totpoly) { + return false; + } + + mpoly_sel = me->mpoly + index; + if (mpoly_sel->flag & ME_HIDE) + return false; + + /* clear flags */ + if (!extend && !deselect && !toggle) { + paintface_deselect_all_visible(C, ob, SEL_DESELECT, false); + } + + me->act_face = (int)index; + + if (extend) { + mpoly_sel->flag |= ME_FACE_SEL; + } + else if (deselect) { + mpoly_sel->flag &= ~ME_FACE_SEL; + } + else if (toggle) { + if (mpoly_sel->flag & ME_FACE_SEL) + mpoly_sel->flag &= ~ME_FACE_SEL; + else + mpoly_sel->flag |= ME_FACE_SEL; + } + else { + mpoly_sel->flag |= ME_FACE_SEL; + } + + /* image window redraw */ + + paintface_flush_flags(C, ob, SELECT); + ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views + return true; } bool do_paintface_box_select(ViewContext *vc, const rcti *rect, int sel_op) { - Object *ob = vc->obact; - Mesh *me; - - me = BKE_mesh_from_object(ob); - if ((me == NULL) || (me->totpoly == 0)) { - return false; - } - - bool changed = false; - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - changed |= paintface_deselect_all_visible(vc->C, vc->obact, SEL_DESELECT, false); - } - - if (BLI_rcti_is_empty(rect)) { - /* pass */ - } - else { - MPoly *mpoly; - uint *rt; - int a, index; - - char *selar = MEM_callocN(me->totpoly + 1, "selar"); - - uint buf_len; - uint *buf = ED_view3d_select_id_read_rect(vc, rect, &buf_len); - - rt = buf; - - a = buf_len; - while (a--) { - if (*rt) { - index = *rt; - if (index <= me->totpoly) { - selar[index] = 1; - } - } - rt++; - } - - mpoly = me->mpoly; - for (a = 1; a <= me->totpoly; a++, mpoly++) { - if ((mpoly->flag & ME_HIDE) == 0) { - const bool is_select = mpoly->flag & ME_FACE_SEL; - const bool is_inside = (selar[a] != 0); - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); - if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL); - changed = true; - } - } - } - - MEM_freeN(buf); - MEM_freeN(selar); + Object *ob = vc->obact; + Mesh *me; + + me = BKE_mesh_from_object(ob); + if ((me == NULL) || (me->totpoly == 0)) { + return false; + } + + bool changed = false; + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + changed |= paintface_deselect_all_visible(vc->C, vc->obact, SEL_DESELECT, false); + } + + if (BLI_rcti_is_empty(rect)) { + /* pass */ + } + else { + MPoly *mpoly; + uint *rt; + int a, index; + + char *selar = MEM_callocN(me->totpoly + 1, "selar"); + + uint buf_len; + uint *buf = ED_view3d_select_id_read_rect(vc, rect, &buf_len); + + rt = buf; + + a = buf_len; + while (a--) { + if (*rt) { + index = *rt; + if (index <= me->totpoly) { + selar[index] = 1; + } + } + rt++; + } + + mpoly = me->mpoly; + for (a = 1; a <= me->totpoly; a++, mpoly++) { + if ((mpoly->flag & ME_HIDE) == 0) { + const bool is_select = mpoly->flag & ME_FACE_SEL; + const bool is_inside = (selar[a] != 0); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL); + changed = true; + } + } + } + + MEM_freeN(buf); + MEM_freeN(selar); #ifdef __APPLE__ - glReadBuffer(GL_BACK); + glReadBuffer(GL_BACK); #endif - } + } - if (changed) { - paintface_flush_flags(vc->C, vc->obact, SELECT); - } - return changed; + if (changed) { + paintface_flush_flags(vc->C, vc->obact, SELECT); + } + return changed; } - /* (similar to void paintface_flush_flags(Object *ob)) * copy the vertex flags, most importantly selection from the mesh to the final derived mesh, * use in object mode when selecting vertices (while painting) */ void paintvert_flush_flags(Object *ob) { - Mesh *me = BKE_mesh_from_object(ob); - Mesh *me_eval = ob->runtime.mesh_eval; - MVert *mvert_eval, *mv; - const int *index_array = NULL; - int totvert; - int i; - - if (me == NULL) - return; - - /* we could call this directly in all areas that change selection, - * since this could become slow for realtime updates (circle-select for eg) */ - BKE_mesh_flush_select_from_verts(me); - - if (me_eval == NULL) - return; - - index_array = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); - - mvert_eval = me_eval->mvert; - totvert = me_eval->totvert; - - mv = mvert_eval; - - if (index_array) { - int orig_index; - for (i = 0; i < totvert; i++, mv++) { - orig_index = index_array[i]; - if (orig_index != ORIGINDEX_NONE) { - mv->flag = me->mvert[index_array[i]].flag; - } - } - } - else { - for (i = 0; i < totvert; i++, mv++) { - mv->flag = me->mvert[i].flag; - } - } - - BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL); + Mesh *me = BKE_mesh_from_object(ob); + Mesh *me_eval = ob->runtime.mesh_eval; + MVert *mvert_eval, *mv; + const int *index_array = NULL; + int totvert; + int i; + + if (me == NULL) + return; + + /* we could call this directly in all areas that change selection, + * since this could become slow for realtime updates (circle-select for eg) */ + BKE_mesh_flush_select_from_verts(me); + + if (me_eval == NULL) + return; + + index_array = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); + + mvert_eval = me_eval->mvert; + totvert = me_eval->totvert; + + mv = mvert_eval; + + if (index_array) { + int orig_index; + for (i = 0; i < totvert; i++, mv++) { + orig_index = index_array[i]; + if (orig_index != ORIGINDEX_NONE) { + mv->flag = me->mvert[index_array[i]].flag; + } + } + } + else { + for (i = 0; i < totvert; i++, mv++) { + mv->flag = me->mvert[i].flag; + } + } + + BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL); } void paintvert_tag_select_update(struct bContext *C, struct Object *ob) { - DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); + DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); } /* note: if the caller passes false to flush_flags, * then they will need to run paintvert_flush_flags(ob) themselves */ bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags) { - Mesh *me; - MVert *mvert; - int a; - - me = BKE_mesh_from_object(ob); - if (me == NULL) { - return false; - } - - if (action == SEL_TOGGLE) { - action = SEL_SELECT; - - mvert = me->mvert; - a = me->totvert; - while (a--) { - if ((mvert->flag & ME_HIDE) == 0 && mvert->flag & SELECT) { - action = SEL_DESELECT; - break; - } - mvert++; - } - } - - bool changed = false; - mvert = me->mvert; - a = me->totvert; - while (a--) { - if ((mvert->flag & ME_HIDE) == 0) { - switch (action) { - case SEL_SELECT: - if ((mvert->flag & SELECT) == 0) { - mvert->flag |= SELECT; - changed = true; - } - break; - case SEL_DESELECT: - if ((mvert->flag & SELECT) != 0) { - mvert->flag &= ~SELECT; - changed = true; - } - break; - case SEL_INVERT: - mvert->flag ^= SELECT; - changed = true; - break; - } - } - mvert++; - } - - if (changed) { - /* handle mselect */ - if (action == SEL_SELECT) { - /* pass */ - } - else if (ELEM(action, SEL_DESELECT, SEL_INVERT)) { - BKE_mesh_mselect_clear(me); - } - else { - BKE_mesh_mselect_validate(me); - } - - if (flush_flags) { - paintvert_flush_flags(ob); - } - } - return changed; + Mesh *me; + MVert *mvert; + int a; + + me = BKE_mesh_from_object(ob); + if (me == NULL) { + return false; + } + + if (action == SEL_TOGGLE) { + action = SEL_SELECT; + + mvert = me->mvert; + a = me->totvert; + while (a--) { + if ((mvert->flag & ME_HIDE) == 0 && mvert->flag & SELECT) { + action = SEL_DESELECT; + break; + } + mvert++; + } + } + + bool changed = false; + mvert = me->mvert; + a = me->totvert; + while (a--) { + if ((mvert->flag & ME_HIDE) == 0) { + switch (action) { + case SEL_SELECT: + if ((mvert->flag & SELECT) == 0) { + mvert->flag |= SELECT; + changed = true; + } + break; + case SEL_DESELECT: + if ((mvert->flag & SELECT) != 0) { + mvert->flag &= ~SELECT; + changed = true; + } + break; + case SEL_INVERT: + mvert->flag ^= SELECT; + changed = true; + break; + } + } + mvert++; + } + + if (changed) { + /* handle mselect */ + if (action == SEL_SELECT) { + /* pass */ + } + else if (ELEM(action, SEL_DESELECT, SEL_INVERT)) { + BKE_mesh_mselect_clear(me); + } + else { + BKE_mesh_mselect_validate(me); + } + + if (flush_flags) { + paintvert_flush_flags(ob); + } + } + return changed; } void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags) { - Mesh *me = BKE_mesh_from_object(ob); - MVert *mv; - MDeformVert *dv; - int a, tot; - - if (me == NULL || me->dvert == NULL) { - return; - } - - if (!extend) { - paintvert_deselect_all_visible(ob, SEL_DESELECT, false); - } - - dv = me->dvert; - tot = me->totvert; - - for (a = 0, mv = me->mvert; a < tot; a++, mv++, dv++) { - if ((mv->flag & ME_HIDE) == 0) { - if (dv->dw == NULL) { - /* if null weight then not grouped */ - mv->flag |= SELECT; - } - } - } - - if (flush_flags) { - paintvert_flush_flags(ob); - } + Mesh *me = BKE_mesh_from_object(ob); + MVert *mv; + MDeformVert *dv; + int a, tot; + + if (me == NULL || me->dvert == NULL) { + return; + } + + if (!extend) { + paintvert_deselect_all_visible(ob, SEL_DESELECT, false); + } + + dv = me->dvert; + tot = me->totvert; + + for (a = 0, mv = me->mvert; a < tot; a++, mv++, dv++) { + if ((mv->flag & ME_HIDE) == 0) { + if (dv->dw == NULL) { + /* if null weight then not grouped */ + mv->flag |= SELECT; + } + } + } + + if (flush_flags) { + paintvert_flush_flags(ob); + } } diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index aca8fac8bf7..815f51a4772 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -44,595 +44,646 @@ #include "ED_object.h" #include "ED_uvedit.h" -#include "mesh_intern.h" /* own include */ - +#include "mesh_intern.h" /* own include */ #define MESH_ADD_VERTS_MAXI 10000000 - /* ********* add primitive operators ************* */ typedef struct MakePrimitiveData { - float mat[4][4]; - bool was_editmode; + float mat[4][4]; + bool was_editmode; } MakePrimitiveData; -static Object *make_prim_init( - bContext *C, const char *idname, - const float loc[3], const float rot[3], ushort local_view_bits, - MakePrimitiveData *r_creation_data) +static Object *make_prim_init(bContext *C, + const char *idname, + const float loc[3], + const float rot[3], + ushort local_view_bits, + MakePrimitiveData *r_creation_data) { - struct Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); + struct Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); - r_creation_data->was_editmode = false; - if (obedit == NULL || obedit->type != OB_MESH) { - obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, local_view_bits); - ED_object_editmode_enter_ex(bmain, scene, obedit, 0); + r_creation_data->was_editmode = false; + if (obedit == NULL || obedit->type != OB_MESH) { + obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, local_view_bits); + ED_object_editmode_enter_ex(bmain, scene, obedit, 0); - r_creation_data->was_editmode = true; - } + r_creation_data->was_editmode = true; + } - ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); + ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); - return obedit; + return obedit; } -static void make_prim_finish(bContext *C, Object *obedit, const MakePrimitiveData *creation_data, int enter_editmode) +static void make_prim_finish(bContext *C, + Object *obedit, + const MakePrimitiveData *creation_data, + int enter_editmode) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const bool exit_editmode = ((creation_data->was_editmode == true) && (enter_editmode == false)); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const bool exit_editmode = ((creation_data->was_editmode == true) && (enter_editmode == false)); - /* Primitive has all verts selected, use vert select flush - * to push this up to edges & faces. */ - EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); + /* Primitive has all verts selected, use vert select flush + * to push this up to edges & faces. */ + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); - /* only recalc editmode tessface if we are staying in editmode */ - EDBM_update_generic(em, !exit_editmode, true); + /* only recalc editmode tessface if we are staying in editmode */ + EDBM_update_generic(em, !exit_editmode, true); - /* userdef */ - if (exit_editmode) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); + /* userdef */ + if (exit_editmode) { + ED_object_editmode_exit(C, EM_FREEDATA); + } + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); } static int add_primitive_plane_exec(bContext *C, wmOperator *op) { - MakePrimitiveData creation_data; - Object *obedit; - BMEditMesh *em; - float loc[3], rot[3]; - bool enter_editmode; - ushort local_view_bits; - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), - loc, rot, local_view_bits, &creation_data); - em = BKE_editmesh_from_object(obedit); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", - 1, 1, RNA_float_get(op->ptr, "size") / 2.0f, creation_data.mat, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - make_prim_finish(C, obedit, &creation_data, enter_editmode); - - return OPERATOR_FINISHED; + MakePrimitiveData creation_data; + Object *obedit; + BMEditMesh *em; + float loc[3], rot[3]; + bool enter_editmode; + ushort local_view_bits; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + WM_operator_view3d_unit_defaults(C, op); + ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init( + C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, local_view_bits, &creation_data); + em = BKE_editmesh_from_object(obedit); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf( + em, + op, + "verts.out", + false, + "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", + 1, + 1, + RNA_float_get(op->ptr, "size") / 2.0f, + creation_data.mat, + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, obedit, &creation_data, enter_editmode); + + return OPERATOR_FINISHED; } void MESH_OT_primitive_plane_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Plane"; - ot->description = "Construct a filled planar mesh with 4 vertices"; - ot->idname = "MESH_OT_primitive_plane_add"; + /* identifiers */ + ot->name = "Add Plane"; + ot->description = "Construct a filled planar mesh with 4 vertices"; + ot->idname = "MESH_OT_primitive_plane_add"; - /* api callbacks */ - ot->exec = add_primitive_plane_exec; - ot->poll = ED_operator_scene_editable; + /* api callbacks */ + ot->exec = add_primitive_plane_exec; + ot->poll = ED_operator_scene_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ED_object_add_unit_props_size(ot); - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + ED_object_add_unit_props_size(ot); + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); } static int add_primitive_cube_exec(bContext *C, wmOperator *op) { - MakePrimitiveData creation_data; - Object *obedit; - BMEditMesh *em; - float loc[3], rot[3]; - bool enter_editmode; - ushort local_view_bits; - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), - loc, rot, local_view_bits, &creation_data); - em = BKE_editmesh_from_object(obedit); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_cube matrix=%m4 size=%f calc_uvs=%b", - creation_data.mat, RNA_float_get(op->ptr, "size"), calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - /* BMESH_TODO make plane side this: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */ - make_prim_finish(C, obedit, &creation_data, enter_editmode); - - return OPERATOR_FINISHED; + MakePrimitiveData creation_data; + Object *obedit; + BMEditMesh *em; + float loc[3], rot[3]; + bool enter_editmode; + ushort local_view_bits; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + WM_operator_view3d_unit_defaults(C, op); + ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init( + C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, local_view_bits, &creation_data); + em = BKE_editmesh_from_object(obedit); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf(em, + op, + "verts.out", + false, + "create_cube matrix=%m4 size=%f calc_uvs=%b", + creation_data.mat, + RNA_float_get(op->ptr, "size"), + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + /* BMESH_TODO make plane side this: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */ + make_prim_finish(C, obedit, &creation_data, enter_editmode); + + return OPERATOR_FINISHED; } void MESH_OT_primitive_cube_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Cube"; - ot->description = "Construct a cube mesh"; - ot->idname = "MESH_OT_primitive_cube_add"; + /* identifiers */ + ot->name = "Add Cube"; + ot->description = "Construct a cube mesh"; + ot->idname = "MESH_OT_primitive_cube_add"; - /* api callbacks */ - ot->exec = add_primitive_cube_exec; - ot->poll = ED_operator_scene_editable; + /* api callbacks */ + ot->exec = add_primitive_cube_exec; + ot->poll = ED_operator_scene_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ED_object_add_unit_props_size(ot); - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + ED_object_add_unit_props_size(ot); + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); } static const EnumPropertyItem fill_type_items[] = { - {0, "NOTHING", 0, "Nothing", "Don't fill at all"}, - {1, "NGON", 0, "Ngon", "Use ngons"}, - {2, "TRIFAN", 0, "Triangle Fan", "Use triangle fans"}, - {0, NULL, 0, NULL, NULL}, + {0, "NOTHING", 0, "Nothing", "Don't fill at all"}, + {1, "NGON", 0, "Ngon", "Use ngons"}, + {2, "TRIFAN", 0, "Triangle Fan", "Use triangle fans"}, + {0, NULL, 0, NULL, NULL}, }; static int add_primitive_circle_exec(bContext *C, wmOperator *op) { - MakePrimitiveData creation_data; - Object *obedit; - BMEditMesh *em; - float loc[3], rot[3]; - bool enter_editmode; - ushort local_view_bits; - int cap_end, cap_tri; - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - cap_end = RNA_enum_get(op->ptr, "fill_type"); - cap_tri = (cap_end == 2); - - WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), - loc, rot, local_view_bits, &creation_data); - em = BKE_editmesh_from_object(obedit); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_circle segments=%i radius=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b", - RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"), - cap_end, cap_tri, creation_data.mat, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - make_prim_finish(C, obedit, &creation_data, enter_editmode); - - return OPERATOR_FINISHED; + MakePrimitiveData creation_data; + Object *obedit; + BMEditMesh *em; + float loc[3], rot[3]; + bool enter_editmode; + ushort local_view_bits; + int cap_end, cap_tri; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + cap_end = RNA_enum_get(op->ptr, "fill_type"); + cap_tri = (cap_end == 2); + + WM_operator_view3d_unit_defaults(C, op); + ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init( + C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, local_view_bits, &creation_data); + em = BKE_editmesh_from_object(obedit); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf( + em, + op, + "verts.out", + false, + "create_circle segments=%i radius=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b", + RNA_int_get(op->ptr, "vertices"), + RNA_float_get(op->ptr, "radius"), + cap_end, + cap_tri, + creation_data.mat, + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, obedit, &creation_data, enter_editmode); + + return OPERATOR_FINISHED; } void MESH_OT_primitive_circle_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Circle"; - ot->description = "Construct a circle mesh"; - ot->idname = "MESH_OT_primitive_circle_add"; + /* identifiers */ + ot->name = "Add Circle"; + ot->description = "Construct a circle mesh"; + ot->idname = "MESH_OT_primitive_circle_add"; - /* api callbacks */ - ot->exec = add_primitive_circle_exec; - ot->poll = ED_operator_scene_editable; + /* api callbacks */ + ot->exec = add_primitive_circle_exec; + ot->poll = ED_operator_scene_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500); - ED_object_add_unit_props_radius(ot); - RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", ""); + /* props */ + RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500); + ED_object_add_unit_props_radius(ot); + RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", ""); - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); } static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) { - MakePrimitiveData creation_data; - Object *obedit; - BMEditMesh *em; - float loc[3], rot[3]; - bool enter_editmode; - ushort local_view_bits; - const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); - const bool cap_end = (end_fill_type != 0); - const bool cap_tri = (end_fill_type == 2); - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), - loc, rot, local_view_bits, &creation_data); - em = BKE_editmesh_from_object(obedit); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b", - RNA_int_get(op->ptr, "vertices"), - RNA_float_get(op->ptr, "radius"), - RNA_float_get(op->ptr, "radius"), - cap_end, cap_tri, - RNA_float_get(op->ptr, "depth"), creation_data.mat, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - make_prim_finish(C, obedit, &creation_data, enter_editmode); - - return OPERATOR_FINISHED; + MakePrimitiveData creation_data; + Object *obedit; + BMEditMesh *em; + float loc[3], rot[3]; + bool enter_editmode; + ushort local_view_bits; + const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); + const bool cap_end = (end_fill_type != 0); + const bool cap_tri = (end_fill_type == 2); + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + WM_operator_view3d_unit_defaults(C, op); + ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), + loc, + rot, + local_view_bits, + &creation_data); + em = BKE_editmesh_from_object(obedit); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf(em, + op, + "verts.out", + false, + "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b " + "cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b", + RNA_int_get(op->ptr, "vertices"), + RNA_float_get(op->ptr, "radius"), + RNA_float_get(op->ptr, "radius"), + cap_end, + cap_tri, + RNA_float_get(op->ptr, "depth"), + creation_data.mat, + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, obedit, &creation_data, enter_editmode); + + return OPERATOR_FINISHED; } void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Cylinder"; - ot->description = "Construct a cylinder mesh"; - ot->idname = "MESH_OT_primitive_cylinder_add"; - - /* api callbacks */ - ot->exec = add_primitive_cylinder_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500); - ED_object_add_unit_props_radius(ot); - RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00); - RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", ""); - - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + /* identifiers */ + ot->name = "Add Cylinder"; + ot->description = "Construct a cylinder mesh"; + ot->idname = "MESH_OT_primitive_cylinder_add"; + + /* api callbacks */ + ot->exec = add_primitive_cylinder_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500); + ED_object_add_unit_props_radius(ot); + RNA_def_float_distance( + ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00); + RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", ""); + + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); } static int add_primitive_cone_exec(bContext *C, wmOperator *op) { - MakePrimitiveData creation_data; - Object *obedit; - BMEditMesh *em; - float loc[3], rot[3]; - bool enter_editmode; - ushort local_view_bits; - const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); - const bool cap_end = (end_fill_type != 0); - const bool cap_tri = (end_fill_type == 2); - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), - loc, rot, local_view_bits, &creation_data); - em = BKE_editmesh_from_object(obedit); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b", - RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"), - RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), - creation_data.mat, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - make_prim_finish(C, obedit, &creation_data, enter_editmode); - - return OPERATOR_FINISHED; + MakePrimitiveData creation_data; + Object *obedit; + BMEditMesh *em; + float loc[3], rot[3]; + bool enter_editmode; + ushort local_view_bits; + const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); + const bool cap_end = (end_fill_type != 0); + const bool cap_tri = (end_fill_type == 2); + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + WM_operator_view3d_unit_defaults(C, op); + ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init( + C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, local_view_bits, &creation_data); + em = BKE_editmesh_from_object(obedit); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf(em, + op, + "verts.out", + false, + "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b " + "cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b", + RNA_int_get(op->ptr, "vertices"), + RNA_float_get(op->ptr, "radius1"), + RNA_float_get(op->ptr, "radius2"), + cap_end, + cap_tri, + RNA_float_get(op->ptr, "depth"), + creation_data.mat, + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, obedit, &creation_data, enter_editmode); + + return OPERATOR_FINISHED; } void MESH_OT_primitive_cone_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Cone"; - ot->description = "Construct a conic mesh"; - ot->idname = "MESH_OT_primitive_cone_add"; - - /* api callbacks */ - ot->exec = add_primitive_cone_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500); - RNA_def_float_distance(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00); - RNA_def_float_distance(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.0, 100.00); - RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00); - RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", ""); - - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + /* identifiers */ + ot->name = "Add Cone"; + ot->description = "Construct a conic mesh"; + ot->idname = "MESH_OT_primitive_cone_add"; + + /* api callbacks */ + ot->exec = add_primitive_cone_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500); + RNA_def_float_distance( + ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00); + RNA_def_float_distance( + ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.0, 100.00); + RNA_def_float_distance( + ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00); + RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", ""); + + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); } static int add_primitive_grid_exec(bContext *C, wmOperator *op) { - MakePrimitiveData creation_data; - Object *obedit; - BMEditMesh *em; - float loc[3], rot[3]; - bool enter_editmode; - ushort local_view_bits; - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), - loc, rot, local_view_bits, &creation_data); - em = BKE_editmesh_from_object(obedit); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", - RNA_int_get(op->ptr, "x_subdivisions"), - RNA_int_get(op->ptr, "y_subdivisions"), - RNA_float_get(op->ptr, "size") / 2.0f, creation_data.mat, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - make_prim_finish(C, obedit, &creation_data, enter_editmode); - - return OPERATOR_FINISHED; + MakePrimitiveData creation_data; + Object *obedit; + BMEditMesh *em; + float loc[3], rot[3]; + bool enter_editmode; + ushort local_view_bits; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + WM_operator_view3d_unit_defaults(C, op); + ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init( + C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, local_view_bits, &creation_data); + em = BKE_editmesh_from_object(obedit); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf( + em, + op, + "verts.out", + false, + "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", + RNA_int_get(op->ptr, "x_subdivisions"), + RNA_int_get(op->ptr, "y_subdivisions"), + RNA_float_get(op->ptr, "size") / 2.0f, + creation_data.mat, + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, obedit, &creation_data, enter_editmode); + + return OPERATOR_FINISHED; } void MESH_OT_primitive_grid_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Grid"; - ot->description = "Construct a grid mesh"; - ot->idname = "MESH_OT_primitive_grid_add"; - - /* api callbacks */ - ot->exec = add_primitive_grid_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - /* Note that if you use MESH_ADD_VERTS_MAXI for both x and y at the same time you will still reach - * impossible values (10^12 vertices or so...). */ - RNA_def_int(ot->srna, "x_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "X Subdivisions", "", 2, 1000); - RNA_def_int(ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000); - - ED_object_add_unit_props_size(ot); - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + /* identifiers */ + ot->name = "Add Grid"; + ot->description = "Construct a grid mesh"; + ot->idname = "MESH_OT_primitive_grid_add"; + + /* api callbacks */ + ot->exec = add_primitive_grid_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + /* Note that if you use MESH_ADD_VERTS_MAXI for both x and y at the same time you will still reach + * impossible values (10^12 vertices or so...). */ + RNA_def_int( + ot->srna, "x_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "X Subdivisions", "", 2, 1000); + RNA_def_int( + ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000); + + ED_object_add_unit_props_size(ot); + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); } static int add_primitive_monkey_exec(bContext *C, wmOperator *op) { - MakePrimitiveData creation_data; - Object *obedit; - BMEditMesh *em; - float loc[3], rot[3]; - float dia; - bool enter_editmode; - ushort local_view_bits; - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &local_view_bits, NULL); - - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), - loc, rot, local_view_bits, &creation_data); - dia = RNA_float_get(op->ptr, "size") / 2.0f; - mul_mat3_m4_fl(creation_data.mat, dia); - - em = BKE_editmesh_from_object(obedit); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_monkey matrix=%m4 calc_uvs=%b", creation_data.mat, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - make_prim_finish(C, obedit, &creation_data, enter_editmode); - - return OPERATOR_FINISHED; + MakePrimitiveData creation_data; + Object *obedit; + BMEditMesh *em; + float loc[3], rot[3]; + float dia; + bool enter_editmode; + ushort local_view_bits; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + WM_operator_view3d_unit_defaults(C, op); + ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &local_view_bits, NULL); + + obedit = make_prim_init( + C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, local_view_bits, &creation_data); + dia = RNA_float_get(op->ptr, "size") / 2.0f; + mul_mat3_m4_fl(creation_data.mat, dia); + + em = BKE_editmesh_from_object(obedit); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf(em, + op, + "verts.out", + false, + "create_monkey matrix=%m4 calc_uvs=%b", + creation_data.mat, + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, obedit, &creation_data, enter_editmode); + + return OPERATOR_FINISHED; } void MESH_OT_primitive_monkey_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Monkey"; - ot->description = "Construct a Suzanne mesh"; - ot->idname = "MESH_OT_primitive_monkey_add"; - - /* api callbacks */ - ot->exec = add_primitive_monkey_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - ED_object_add_unit_props_size(ot); - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + /* identifiers */ + ot->name = "Add Monkey"; + ot->description = "Construct a Suzanne mesh"; + ot->idname = "MESH_OT_primitive_monkey_add"; + + /* api callbacks */ + ot->exec = add_primitive_monkey_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + ED_object_add_unit_props_size(ot); + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); } static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) { - MakePrimitiveData creation_data; - Object *obedit; - BMEditMesh *em; - float loc[3], rot[3]; - bool enter_editmode; - ushort local_view_bits; - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), - loc, rot, local_view_bits, &creation_data); - em = BKE_editmesh_from_object(obedit); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b", - RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"), - RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - make_prim_finish(C, obedit, &creation_data, enter_editmode); - - return OPERATOR_FINISHED; + MakePrimitiveData creation_data; + Object *obedit; + BMEditMesh *em; + float loc[3], rot[3]; + bool enter_editmode; + ushort local_view_bits; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + WM_operator_view3d_unit_defaults(C, op); + ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init( + C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, local_view_bits, &creation_data); + em = BKE_editmesh_from_object(obedit); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf( + em, + op, + "verts.out", + false, + "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b", + RNA_int_get(op->ptr, "segments"), + RNA_int_get(op->ptr, "ring_count"), + RNA_float_get(op->ptr, "radius"), + creation_data.mat, + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, obedit, &creation_data, enter_editmode); + + return OPERATOR_FINISHED; } void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add UV Sphere"; - ot->description = "Construct a UV sphere mesh"; - ot->idname = "MESH_OT_primitive_uv_sphere_add"; + /* identifiers */ + ot->name = "Add UV Sphere"; + ot->description = "Construct a UV sphere mesh"; + ot->idname = "MESH_OT_primitive_uv_sphere_add"; - /* api callbacks */ - ot->exec = add_primitive_uvsphere_exec; - ot->poll = ED_operator_scene_editable; + /* api callbacks */ + ot->exec = add_primitive_uvsphere_exec; + ot->poll = ED_operator_scene_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_int(ot->srna, "segments", 32, 3, MESH_ADD_VERTS_MAXI / 100, "Segments", "", 3, 500); - RNA_def_int(ot->srna, "ring_count", 16, 3, MESH_ADD_VERTS_MAXI / 100, "Rings", "", 3, 500); + /* props */ + RNA_def_int(ot->srna, "segments", 32, 3, MESH_ADD_VERTS_MAXI / 100, "Segments", "", 3, 500); + RNA_def_int(ot->srna, "ring_count", 16, 3, MESH_ADD_VERTS_MAXI / 100, "Rings", "", 3, 500); - ED_object_add_unit_props_radius(ot); - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + ED_object_add_unit_props_radius(ot); + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); } static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) { - MakePrimitiveData creation_data; - Object *obedit; - BMEditMesh *em; - float loc[3], rot[3]; - bool enter_editmode; - ushort local_view_bits; - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), - loc, rot, local_view_bits, &creation_data); - em = BKE_editmesh_from_object(obedit); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b", - RNA_int_get(op->ptr, "subdivisions"), - RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - make_prim_finish(C, obedit, &creation_data, enter_editmode); - - return OPERATOR_FINISHED; + MakePrimitiveData creation_data; + Object *obedit; + BMEditMesh *em; + float loc[3], rot[3]; + bool enter_editmode; + ushort local_view_bits; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + WM_operator_view3d_unit_defaults(C, op); + ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), + loc, + rot, + local_view_bits, + &creation_data); + em = BKE_editmesh_from_object(obedit); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf( + em, + op, + "verts.out", + false, + "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b", + RNA_int_get(op->ptr, "subdivisions"), + RNA_float_get(op->ptr, "radius"), + creation_data.mat, + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, obedit, &creation_data, enter_editmode); + + return OPERATOR_FINISHED; } void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Ico Sphere"; - ot->description = "Construct an Icosphere mesh"; - ot->idname = "MESH_OT_primitive_ico_sphere_add"; + /* identifiers */ + ot->name = "Add Ico Sphere"; + ot->description = "Construct an Icosphere mesh"; + ot->idname = "MESH_OT_primitive_ico_sphere_add"; - /* api callbacks */ - ot->exec = add_primitive_icosphere_exec; - ot->poll = ED_operator_scene_editable; + /* api callbacks */ + ot->exec = add_primitive_icosphere_exec; + ot->poll = ED_operator_scene_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_int(ot->srna, "subdivisions", 2, 1, 10, "Subdivisions", "", 1, 8); + /* props */ + RNA_def_int(ot->srna, "subdivisions", 2, 1, 10, "Subdivisions", "", 1, 8); - ED_object_add_unit_props_radius(ot); - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + ED_object_add_unit_props_radius(ot); + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); } diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c index b01a935e4d2..9ed2c15f1c1 100644 --- a/source/blender/editors/mesh/editmesh_add_gizmo.c +++ b/source/blender/editors/mesh/editmesh_add_gizmo.c @@ -48,7 +48,7 @@ #include "BLT_translation.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /* -------------------------------------------------------------------- */ /** \name Helper Functions @@ -60,51 +60,52 @@ * We may base this choice on context, * for now pick the "ground" based on the 3D cursor's dominant plane pointing down relative to the view. */ -static void calc_initial_placement_point_from_view( - bContext *C, const float mval[2], - float r_location[3], float r_rotation[3][3]) +static void calc_initial_placement_point_from_view(bContext *C, + const float mval[2], + float r_location[3], + float r_rotation[3][3]) { - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - - bool use_mouse_project = true; /* TODO: make optional */ - - float cursor_matrix[4][4]; - float orient_matrix[3][3]; - ED_view3d_cursor3d_calc_mat4(scene, cursor_matrix); - - float dots[3] = { - dot_v3v3(rv3d->viewinv[2], cursor_matrix[0]), - dot_v3v3(rv3d->viewinv[2], cursor_matrix[1]), - dot_v3v3(rv3d->viewinv[2], cursor_matrix[2]), - }; - const int axis = axis_dominant_v3_single(dots); - - copy_v3_v3(orient_matrix[0], cursor_matrix[(axis + 1) % 3]); - copy_v3_v3(orient_matrix[1], cursor_matrix[(axis + 2) % 3]); - copy_v3_v3(orient_matrix[2], cursor_matrix[axis]); - - if (dot_v3v3(rv3d->viewinv[2], orient_matrix[2]) < 0.0f) { - negate_v3(orient_matrix[2]); - } - if (is_negative_m3(orient_matrix)) { - swap_v3_v3(orient_matrix[0], orient_matrix[1]); - } - - if (use_mouse_project) { - float plane[4]; - plane_from_point_normal_v3(plane, cursor_matrix[3], orient_matrix[2]); - if (ED_view3d_win_to_3d_on_plane(ar, plane, mval, true, r_location)) { - copy_m3_m3(r_rotation, orient_matrix); - return; - } - } - - /* fallback */ - copy_v3_v3(r_location, cursor_matrix[3]); - copy_m3_m3(r_rotation, orient_matrix); + Scene *scene = CTX_data_scene(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + bool use_mouse_project = true; /* TODO: make optional */ + + float cursor_matrix[4][4]; + float orient_matrix[3][3]; + ED_view3d_cursor3d_calc_mat4(scene, cursor_matrix); + + float dots[3] = { + dot_v3v3(rv3d->viewinv[2], cursor_matrix[0]), + dot_v3v3(rv3d->viewinv[2], cursor_matrix[1]), + dot_v3v3(rv3d->viewinv[2], cursor_matrix[2]), + }; + const int axis = axis_dominant_v3_single(dots); + + copy_v3_v3(orient_matrix[0], cursor_matrix[(axis + 1) % 3]); + copy_v3_v3(orient_matrix[1], cursor_matrix[(axis + 2) % 3]); + copy_v3_v3(orient_matrix[2], cursor_matrix[axis]); + + if (dot_v3v3(rv3d->viewinv[2], orient_matrix[2]) < 0.0f) { + negate_v3(orient_matrix[2]); + } + if (is_negative_m3(orient_matrix)) { + swap_v3_v3(orient_matrix[0], orient_matrix[1]); + } + + if (use_mouse_project) { + float plane[4]; + plane_from_point_normal_v3(plane, cursor_matrix[3], orient_matrix[2]); + if (ED_view3d_win_to_3d_on_plane(ar, plane, mval, true, r_location)) { + copy_m3_m3(r_rotation, orient_matrix); + return; + } + } + + /* fallback */ + copy_v3_v3(r_location, cursor_matrix[3]); + copy_m3_m3(r_rotation, orient_matrix); } /** \} */ @@ -114,12 +115,12 @@ static void calc_initial_placement_point_from_view( * \{ */ typedef struct GizmoPlacementGroup { - struct wmGizmo *cage; - struct { - bContext *context; - wmOperator *op; - PropertyRNA *prop_matrix; - } data; + struct wmGizmo *cage; + struct { + bContext *context; + wmOperator *op; + PropertyRNA *prop_matrix; + } data; } GizmoPlacementGroup; /** @@ -129,178 +130,181 @@ typedef struct GizmoPlacementGroup { */ static void gizmo_placement_exec(GizmoPlacementGroup *ggd) { - wmOperator *op = ggd->data.op; - if (op == WM_operator_last_redo((bContext *)ggd->data.context)) { - ED_undo_operator_repeat((bContext *)ggd->data.context, op); - } + wmOperator *op = ggd->data.op; + if (op == WM_operator_last_redo((bContext *)ggd->data.context)) { + ED_undo_operator_repeat((bContext *)ggd->data.context, op); + } } static void gizmo_mesh_placement_update_from_op(GizmoPlacementGroup *ggd) { - wmOperator *op = ggd->data.op; - UNUSED_VARS(op); - /* For now don't read back from the operator. */ + wmOperator *op = ggd->data.op; + UNUSED_VARS(op); + /* For now don't read back from the operator. */ #if 0 - RNA_property_float_get_array(op->ptr, ggd->data.prop_matrix, &ggd->cage->matrix_offset[0][0]); + RNA_property_float_get_array(op->ptr, ggd->data.prop_matrix, &ggd->cage->matrix_offset[0][0]); #endif } /* translate callbacks */ -static void gizmo_placement_prop_matrix_get( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - void *value_p) +static void gizmo_placement_prop_matrix_get(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + void *value_p) { - GizmoPlacementGroup *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - float *value = value_p; - BLI_assert(gz_prop->type->array_length == 16); - UNUSED_VARS_NDEBUG(gz_prop); - - if (value_p != ggd->cage->matrix_offset) { - mul_m4_m4m4(value_p, ggd->cage->matrix_basis, ggd->cage->matrix_offset); - RNA_property_float_get_array(op->ptr, ggd->data.prop_matrix, value); - } + GizmoPlacementGroup *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + float *value = value_p; + BLI_assert(gz_prop->type->array_length == 16); + UNUSED_VARS_NDEBUG(gz_prop); + + if (value_p != ggd->cage->matrix_offset) { + mul_m4_m4m4(value_p, ggd->cage->matrix_basis, ggd->cage->matrix_offset); + RNA_property_float_get_array(op->ptr, ggd->data.prop_matrix, value); + } } -static void gizmo_placement_prop_matrix_set( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - const void *value) +static void gizmo_placement_prop_matrix_set(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + const void *value) { - GizmoPlacementGroup *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; + GizmoPlacementGroup *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; - BLI_assert(gz_prop->type->array_length == 16); - UNUSED_VARS_NDEBUG(gz_prop); + BLI_assert(gz_prop->type->array_length == 16); + UNUSED_VARS_NDEBUG(gz_prop); - float mat[4][4]; - mul_m4_m4m4(mat, ggd->cage->matrix_basis, value); + float mat[4][4]; + mul_m4_m4m4(mat, ggd->cage->matrix_basis, value); - if (is_negative_m4(mat)) { - negate_mat3_m4(mat); - } + if (is_negative_m4(mat)) { + negate_mat3_m4(mat); + } - RNA_property_float_set_array(op->ptr, ggd->data.prop_matrix, &mat[0][0]); + RNA_property_float_set_array(op->ptr, ggd->data.prop_matrix, &mat[0][0]); - gizmo_placement_exec(ggd); + gizmo_placement_exec(ggd); } static bool gizmo_mesh_placement_poll(const bContext *C, wmGizmoGroupType *gzgt) { - return ED_gizmo_poll_or_unlink_delayed_from_operator(C, gzgt, "MESH_OT_primitive_cube_add_gizmo"); + return ED_gizmo_poll_or_unlink_delayed_from_operator( + C, gzgt, "MESH_OT_primitive_cube_add_gizmo"); } -static void gizmo_mesh_placement_modal_from_setup( - const bContext *C, wmGizmoGroup *gzgroup) +static void gizmo_mesh_placement_modal_from_setup(const bContext *C, wmGizmoGroup *gzgroup) { - GizmoPlacementGroup *ggd = gzgroup->customdata; - - /* Initial size. */ - { - wmGizmo *gz = ggd->cage; - zero_m4(gz->matrix_offset); - - /* TODO: support zero scaled matrix in 'GIZMO_GT_cage_3d'. */ - gz->matrix_offset[0][0] = 0.01; - gz->matrix_offset[1][1] = 0.01; - gz->matrix_offset[2][2] = 0.01; - gz->matrix_offset[3][3] = 1.0f; - } - - /* Start off dragging. */ - { - wmWindow *win = CTX_wm_window(C); - ARegion *ar = CTX_wm_region(C); - wmGizmo *gz = ggd->cage; - - { - float mat3[3][3]; - float location[3]; - calc_initial_placement_point_from_view( - (bContext *)C, (float[2]){ - win->eventstate->x - ar->winrct.xmin, - win->eventstate->y - ar->winrct.ymin, - }, - location, mat3); - copy_m4_m3(gz->matrix_basis, mat3); - copy_v3_v3(gz->matrix_basis[3], location); - } - - if (1) { - wmGizmoMap *gzmap = gzgroup->parent_gzmap; - WM_gizmo_modal_set_from_setup( - gzmap, (bContext *)C, ggd->cage, ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, win->eventstate); - } - } + GizmoPlacementGroup *ggd = gzgroup->customdata; + + /* Initial size. */ + { + wmGizmo *gz = ggd->cage; + zero_m4(gz->matrix_offset); + + /* TODO: support zero scaled matrix in 'GIZMO_GT_cage_3d'. */ + gz->matrix_offset[0][0] = 0.01; + gz->matrix_offset[1][1] = 0.01; + gz->matrix_offset[2][2] = 0.01; + gz->matrix_offset[3][3] = 1.0f; + } + + /* Start off dragging. */ + { + wmWindow *win = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + wmGizmo *gz = ggd->cage; + + { + float mat3[3][3]; + float location[3]; + calc_initial_placement_point_from_view((bContext *)C, + (float[2]){ + win->eventstate->x - ar->winrct.xmin, + win->eventstate->y - ar->winrct.ymin, + }, + location, + mat3); + copy_m4_m3(gz->matrix_basis, mat3); + copy_v3_v3(gz->matrix_basis[3], location); + } + + if (1) { + wmGizmoMap *gzmap = gzgroup->parent_gzmap; + WM_gizmo_modal_set_from_setup(gzmap, + (bContext *)C, + ggd->cage, + ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, + win->eventstate); + } + } } static void gizmo_mesh_placement_setup(const bContext *C, wmGizmoGroup *gzgroup) { - wmOperator *op = WM_operator_last_redo(C); + wmOperator *op = WM_operator_last_redo(C); - if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_gizmo")) { - return; - } + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_gizmo")) { + return; + } - struct GizmoPlacementGroup *ggd = MEM_callocN(sizeof(GizmoPlacementGroup), __func__); - gzgroup->customdata = ggd; + struct GizmoPlacementGroup *ggd = MEM_callocN(sizeof(GizmoPlacementGroup), __func__); + gzgroup->customdata = ggd; - const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_3d", true); + const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_3d", true); - ggd->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, NULL); + ggd->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, NULL); - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->cage->color); + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->cage->color); - RNA_enum_set(ggd->cage->ptr, "transform", - ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE | - ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | - ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_SIGNED); + RNA_enum_set(ggd->cage->ptr, + "transform", + ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE | ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | + ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_SIGNED); - WM_gizmo_set_flag(ggd->cage, WM_GIZMO_DRAW_VALUE, true); + WM_gizmo_set_flag(ggd->cage, WM_GIZMO_DRAW_VALUE, true); - ggd->data.context = (bContext *)C; - ggd->data.op = op; - ggd->data.prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); + ggd->data.context = (bContext *)C; + ggd->data.op = op; + ggd->data.prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); - gizmo_mesh_placement_update_from_op(ggd); + gizmo_mesh_placement_update_from_op(ggd); - /* Setup property callbacks */ - { - WM_gizmo_target_property_def_func( - ggd->cage, "matrix", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_placement_prop_matrix_get, - .value_set_fn = gizmo_placement_prop_matrix_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - } + /* Setup property callbacks */ + { + WM_gizmo_target_property_def_func(ggd->cage, + "matrix", + &(const struct wmGizmoPropertyFnParams){ + .value_get_fn = gizmo_placement_prop_matrix_get, + .value_set_fn = gizmo_placement_prop_matrix_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + } - gizmo_mesh_placement_modal_from_setup(C, gzgroup); + gizmo_mesh_placement_modal_from_setup(C, gzgroup); } -static void gizmo_mesh_placement_draw_prepare( - const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +static void gizmo_mesh_placement_draw_prepare(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - GizmoPlacementGroup *ggd = gzgroup->customdata; - if (ggd->data.op->next) { - ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context); - } - gizmo_mesh_placement_update_from_op(ggd); + GizmoPlacementGroup *ggd = gzgroup->customdata; + if (ggd->data.op->next) { + ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context); + } + gizmo_mesh_placement_update_from_op(ggd); } static void MESH_GGT_add_bounds(struct wmGizmoGroupType *gzgt) { - gzgt->name = "Mesh Add Bounds"; - gzgt->idname = "MESH_GGT_add_bounds"; + gzgt->name = "Mesh Add Bounds"; + gzgt->idname = "MESH_GGT_add_bounds"; - gzgt->flag = WM_GIZMOGROUPTYPE_3D; + gzgt->flag = WM_GIZMOGROUPTYPE_3D; - gzgt->gzmap_params.spaceid = SPACE_VIEW3D; - gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; - gzgt->poll = gizmo_mesh_placement_poll; - gzgt->setup = gizmo_mesh_placement_setup; - gzgt->draw_prepare = gizmo_mesh_placement_draw_prepare; + gzgt->poll = gizmo_mesh_placement_poll; + gzgt->setup = gizmo_mesh_placement_setup; + gzgt->draw_prepare = gizmo_mesh_placement_draw_prepare; } /** \} */ @@ -313,89 +317,94 @@ static void MESH_GGT_add_bounds(struct wmGizmoGroupType *gzgt) * and share the same BMesh creation code. * \{ */ - static int add_primitive_cube_gizmo_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - float matrix[4][4]; - - /* Get the matrix that defines the cube bounds (as set by the gizmo cage). */ - { - PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); - if (RNA_property_is_set(op->ptr, prop_matrix)) { - RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]); - invert_m4_m4(obedit->imat, obedit->obmat); - mul_m4_m4m4(matrix, obedit->imat, matrix); - } - else { - /* For the first update the widget may not set the matrix. */ - return OPERATOR_FINISHED; - } - } - - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_cube matrix=%m4 size=%f calc_uvs=%b", - matrix, 1.0f, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); - EDBM_update_generic(em, true, true); - - return OPERATOR_FINISHED; + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + float matrix[4][4]; + + /* Get the matrix that defines the cube bounds (as set by the gizmo cage). */ + { + PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); + if (RNA_property_is_set(op->ptr, prop_matrix)) { + RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]); + invert_m4_m4(obedit->imat, obedit->obmat); + mul_m4_m4m4(matrix, obedit->imat, matrix); + } + else { + /* For the first update the widget may not set the matrix. */ + return OPERATOR_FINISHED; + } + } + + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf(em, + op, + "verts.out", + false, + "create_cube matrix=%m4 size=%f calc_uvs=%b", + matrix, + 1.0f, + calc_uvs)) { + return OPERATOR_CANCELLED; + } + + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); + EDBM_update_generic(em, true, true); + + return OPERATOR_FINISHED; } -static int add_primitive_cube_gizmo_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int add_primitive_cube_gizmo_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) { - View3D *v3d = CTX_wm_view3d(C); - - int ret = add_primitive_cube_gizmo_exec(C, op); - if (ret & OPERATOR_FINISHED) { - /* Setup gizmos */ - if (v3d && ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0)) { - wmGizmoGroupType *gzgt = WM_gizmogrouptype_find("MESH_GGT_add_bounds", false); - if (!WM_gizmo_group_type_ensure_ptr(gzgt)) { - struct Main *bmain = CTX_data_main(C); - WM_gizmo_group_type_reinit_ptr(bmain, gzgt); - } - } - } - - return ret; + View3D *v3d = CTX_wm_view3d(C); + + int ret = add_primitive_cube_gizmo_exec(C, op); + if (ret & OPERATOR_FINISHED) { + /* Setup gizmos */ + if (v3d && ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0)) { + wmGizmoGroupType *gzgt = WM_gizmogrouptype_find("MESH_GGT_add_bounds", false); + if (!WM_gizmo_group_type_ensure_ptr(gzgt)) { + struct Main *bmain = CTX_data_main(C); + WM_gizmo_group_type_reinit_ptr(bmain, gzgt); + } + } + } + + return ret; } void MESH_OT_primitive_cube_add_gizmo(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Cube"; - ot->description = "Construct a cube mesh"; - ot->idname = "MESH_OT_primitive_cube_add_gizmo"; + /* identifiers */ + ot->name = "Add Cube"; + ot->description = "Construct a cube mesh"; + ot->idname = "MESH_OT_primitive_cube_add_gizmo"; - /* api callbacks */ - ot->invoke = add_primitive_cube_gizmo_invoke; - ot->exec = add_primitive_cube_gizmo_exec; - ot->poll = ED_operator_editmesh_view3d; + /* api callbacks */ + ot->invoke = add_primitive_cube_gizmo_invoke; + ot->exec = add_primitive_cube_gizmo_exec; + ot->poll = ED_operator_editmesh_view3d; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); - /* hidden props */ - PropertyRNA *prop = RNA_def_float_matrix(ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* hidden props */ + PropertyRNA *prop = RNA_def_float_matrix( + ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - WM_gizmogrouptype_append(MESH_GGT_add_bounds); + WM_gizmogrouptype_append(MESH_GGT_add_bounds); } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 1059374dcc5..2c0c8b2c708 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -51,10 +51,9 @@ #include "ED_transform.h" #include "ED_view3d.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ - -#define MVAL_PIXEL_MARGIN 5.0f +#define MVAL_PIXEL_MARGIN 5.0f #define PROFILE_HARD_MIN 0.0f @@ -67,839 +66,925 @@ #define SEGMENTS_VALUE 3 #define NUM_VALUE_KINDS 4 -static const char *value_rna_name[NUM_VALUE_KINDS] = {"offset", "offset_pct", "profile", "segments"}; +static const char *value_rna_name[NUM_VALUE_KINDS] = { + "offset", "offset_pct", "profile", "segments"}; static const float value_clamp_min[NUM_VALUE_KINDS] = {0.0f, 0.0f, PROFILE_HARD_MIN, 1.0f}; static const float value_clamp_max[NUM_VALUE_KINDS] = {1e6, 100.0f, 1.0f, SEGMENTS_HARD_MAX}; static const float value_start[NUM_VALUE_KINDS] = {0.0f, 0.0f, 0.5f, 1.0f}; -static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f, 4.0f}; +static const float value_scale_per_inch[NUM_VALUE_KINDS] = {0.0f, 100.0f, 1.0f, 4.0f}; typedef struct { - BMEditMesh *em; - BMBackup mesh_backup; + BMEditMesh *em; + BMBackup mesh_backup; } BevelObjectStore; - typedef struct { - float initial_length[NUM_VALUE_KINDS]; - float scale[NUM_VALUE_KINDS]; - NumInput num_input[NUM_VALUE_KINDS]; - /** The current value when shift is pressed. Negative when shift not active. */ - float shift_value[NUM_VALUE_KINDS]; - float max_obj_scale; - bool is_modal; - - BevelObjectStore *ob_store; - uint ob_store_len; - - /* modal only */ - float mcenter[2]; - void *draw_handle_pixel; - short gizmo_flag; - short value_mode; /* Which value does mouse movement and numeric input affect? */ - float segments; /* Segments as float so smooth mouse pan works in small increments */ + float initial_length[NUM_VALUE_KINDS]; + float scale[NUM_VALUE_KINDS]; + NumInput num_input[NUM_VALUE_KINDS]; + /** The current value when shift is pressed. Negative when shift not active. */ + float shift_value[NUM_VALUE_KINDS]; + float max_obj_scale; + bool is_modal; + + BevelObjectStore *ob_store; + uint ob_store_len; + + /* modal only */ + float mcenter[2]; + void *draw_handle_pixel; + short gizmo_flag; + short value_mode; /* Which value does mouse movement and numeric input affect? */ + float segments; /* Segments as float so smooth mouse pan works in small increments */ } BevelData; enum { - BEV_MODAL_CANCEL = 1, - BEV_MODAL_CONFIRM, - BEV_MODAL_VALUE_OFFSET, - BEV_MODAL_VALUE_PROFILE, - BEV_MODAL_VALUE_SEGMENTS, - BEV_MODAL_SEGMENTS_UP, - BEV_MODAL_SEGMENTS_DOWN, - BEV_MODAL_OFFSET_MODE_CHANGE, - BEV_MODAL_CLAMP_OVERLAP_TOGGLE, - BEV_MODAL_VERTEX_ONLY_TOGGLE, - BEV_MODAL_HARDEN_NORMALS_TOGGLE, - BEV_MODAL_MARK_SEAM_TOGGLE, - BEV_MODAL_MARK_SHARP_TOGGLE, - BEV_MODAL_OUTER_MITER_CHANGE, - BEV_MODAL_INNER_MITER_CHANGE, + BEV_MODAL_CANCEL = 1, + BEV_MODAL_CONFIRM, + BEV_MODAL_VALUE_OFFSET, + BEV_MODAL_VALUE_PROFILE, + BEV_MODAL_VALUE_SEGMENTS, + BEV_MODAL_SEGMENTS_UP, + BEV_MODAL_SEGMENTS_DOWN, + BEV_MODAL_OFFSET_MODE_CHANGE, + BEV_MODAL_CLAMP_OVERLAP_TOGGLE, + BEV_MODAL_VERTEX_ONLY_TOGGLE, + BEV_MODAL_HARDEN_NORMALS_TOGGLE, + BEV_MODAL_MARK_SEAM_TOGGLE, + BEV_MODAL_MARK_SHARP_TOGGLE, + BEV_MODAL_OUTER_MITER_CHANGE, + BEV_MODAL_INNER_MITER_CHANGE, }; static float get_bevel_offset(wmOperator *op) { - float val; + float val; - if (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT) - val = RNA_float_get(op->ptr, "offset_pct"); - else - val = RNA_float_get(op->ptr, "offset"); - return val; + if (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT) + val = RNA_float_get(op->ptr, "offset_pct"); + else + val = RNA_float_get(op->ptr, "offset"); + return val; } static void edbm_bevel_update_header(bContext *C, wmOperator *op) { - char header[UI_MAX_DRAW_STR]; - char buf[UI_MAX_DRAW_STR]; - char *p = buf; - int available_len = sizeof(buf); - Scene *sce = CTX_data_scene(C); - char offset_str[NUM_STR_REP_LEN]; - const char *mode_str, *omiter_str, *imiter_str; - PropertyRNA *prop; + char header[UI_MAX_DRAW_STR]; + char buf[UI_MAX_DRAW_STR]; + char *p = buf; + int available_len = sizeof(buf); + Scene *sce = CTX_data_scene(C); + char offset_str[NUM_STR_REP_LEN]; + const char *mode_str, *omiter_str, *imiter_str; + PropertyRNA *prop; #define WM_MODALKEY(_id) \ - WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) - - if (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT) { - BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%.1f%%", RNA_float_get(op->ptr, "offset_pct")); - } - else { - bUnit_AsString2( - offset_str, NUM_STR_REP_LEN, (double)RNA_float_get(op->ptr, "offset"), 3, - B_UNIT_LENGTH, &sce->unit, true); - } - - prop = RNA_struct_find_property(op->ptr, "offset_type"); - RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &mode_str); - prop = RNA_struct_find_property(op->ptr, "miter_outer"); - RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &omiter_str); - prop = RNA_struct_find_property(op->ptr, "miter_inner"); - RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &imiter_str); - - BLI_snprintf( - header, sizeof(header), - IFACE_("%s: confirm, " - "%s: cancel, " - "%s: mode (%s), " - "%s: width (%s), " - "%s: segments (%d), " - "%s: profile (%.3f), " - "%s: clamp overlap (%s), " - "%s: vertex only (%s), " - "%s: outer miter (%s), " - "%s: inner miter (%s), " - "%s: harden normals (%s), " - "%s: mark seam (%s), " - "%s: mark sharp (%s)" - ), - WM_MODALKEY(BEV_MODAL_CONFIRM), - WM_MODALKEY(BEV_MODAL_CANCEL), - WM_MODALKEY(BEV_MODAL_OFFSET_MODE_CHANGE), - mode_str, - WM_MODALKEY(BEV_MODAL_VALUE_OFFSET), - offset_str, - WM_MODALKEY(BEV_MODAL_VALUE_SEGMENTS), - RNA_int_get(op->ptr, "segments"), - WM_MODALKEY(BEV_MODAL_VALUE_PROFILE), - RNA_float_get(op->ptr, "profile"), - WM_MODALKEY(BEV_MODAL_CLAMP_OVERLAP_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")), - WM_MODALKEY(BEV_MODAL_VERTEX_ONLY_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")), - WM_MODALKEY(BEV_MODAL_OUTER_MITER_CHANGE), - omiter_str, - WM_MODALKEY(BEV_MODAL_INNER_MITER_CHANGE), - imiter_str, - WM_MODALKEY(BEV_MODAL_HARDEN_NORMALS_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "harden_normals")), - WM_MODALKEY(BEV_MODAL_MARK_SEAM_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_seam")), - WM_MODALKEY(BEV_MODAL_MARK_SHARP_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp")) - ); + WM_modalkeymap_operator_items_to_string_buf( \ + op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) + + if (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT) { + BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%.1f%%", RNA_float_get(op->ptr, "offset_pct")); + } + else { + bUnit_AsString2(offset_str, + NUM_STR_REP_LEN, + (double)RNA_float_get(op->ptr, "offset"), + 3, + B_UNIT_LENGTH, + &sce->unit, + true); + } + + prop = RNA_struct_find_property(op->ptr, "offset_type"); + RNA_property_enum_name_gettexted( + C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &mode_str); + prop = RNA_struct_find_property(op->ptr, "miter_outer"); + RNA_property_enum_name_gettexted( + C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &omiter_str); + prop = RNA_struct_find_property(op->ptr, "miter_inner"); + RNA_property_enum_name_gettexted( + C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &imiter_str); + + BLI_snprintf(header, + sizeof(header), + IFACE_("%s: confirm, " + "%s: cancel, " + "%s: mode (%s), " + "%s: width (%s), " + "%s: segments (%d), " + "%s: profile (%.3f), " + "%s: clamp overlap (%s), " + "%s: vertex only (%s), " + "%s: outer miter (%s), " + "%s: inner miter (%s), " + "%s: harden normals (%s), " + "%s: mark seam (%s), " + "%s: mark sharp (%s)"), + WM_MODALKEY(BEV_MODAL_CONFIRM), + WM_MODALKEY(BEV_MODAL_CANCEL), + WM_MODALKEY(BEV_MODAL_OFFSET_MODE_CHANGE), + mode_str, + WM_MODALKEY(BEV_MODAL_VALUE_OFFSET), + offset_str, + WM_MODALKEY(BEV_MODAL_VALUE_SEGMENTS), + RNA_int_get(op->ptr, "segments"), + WM_MODALKEY(BEV_MODAL_VALUE_PROFILE), + RNA_float_get(op->ptr, "profile"), + WM_MODALKEY(BEV_MODAL_CLAMP_OVERLAP_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")), + WM_MODALKEY(BEV_MODAL_VERTEX_ONLY_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")), + WM_MODALKEY(BEV_MODAL_OUTER_MITER_CHANGE), + omiter_str, + WM_MODALKEY(BEV_MODAL_INNER_MITER_CHANGE), + imiter_str, + WM_MODALKEY(BEV_MODAL_HARDEN_NORMALS_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "harden_normals")), + WM_MODALKEY(BEV_MODAL_MARK_SEAM_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_seam")), + WM_MODALKEY(BEV_MODAL_MARK_SHARP_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp"))); #undef WM_MODALKEY - ED_workspace_status_text(C, header); + ED_workspace_status_text(C, header); } static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) { - Scene *scene = CTX_data_scene(C); - BevelData *opdata; - ViewLayer *view_layer = CTX_data_view_layer(C); - float pixels_per_inch; - int i, otype; - - if (is_modal) { - RNA_float_set(op->ptr, "offset", 0.0f); - RNA_float_set(op->ptr, "offset_pct", 0.0f); - } - - op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator"); - uint objects_used_len = 0; - opdata->max_obj_scale = FLT_MIN; - - { - uint ob_store_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( - view_layer, CTX_wm_view3d(C), &ob_store_len); - opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); - for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { - Object *obedit = objects[ob_index]; - float scale = mat4_to_scale(obedit->obmat); - opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel > 0) { - opdata->ob_store[objects_used_len].em = em; - objects_used_len++; - } - } - MEM_freeN(objects); - opdata->ob_store_len = objects_used_len; - } - - opdata->is_modal = is_modal; - otype = RNA_enum_get(op->ptr, "offset_type"); - opdata->value_mode = (otype == BEVEL_AMT_PERCENT) ? OFFSET_VALUE_PERCENT : OFFSET_VALUE; - opdata->segments = (float) RNA_int_get(op->ptr, "segments"); - pixels_per_inch = U.dpi * U.pixelsize; - - for (i = 0; i < NUM_VALUE_KINDS; i++) { - opdata->shift_value[i] = -1.0f; - opdata->initial_length[i] = -1.0f; - /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */ - opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch; - - initNumInput(&opdata->num_input[i]); - opdata->num_input[i].idx_max = 0; - opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE; - if (i == SEGMENTS_VALUE) { - opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO; - } - if (i == OFFSET_VALUE) { - opdata->num_input[i].unit_sys = scene->unit.system; - } - /* Not sure this is a factor or a unit? */ - opdata->num_input[i].unit_type[0] = B_UNIT_NONE; - } - - /* avoid the cost of allocating a bm copy */ - if (is_modal) { - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(opdata->ob_store[ob_index].em); - } - opdata->draw_handle_pixel = ED_region_draw_cb_activate( - ar->type, ED_region_draw_mouse_line_cb, - opdata->mcenter, REGION_DRAW_POST_PIXEL); - G.moving = G_TRANSFORM_EDIT; - - if (v3d) { - opdata->gizmo_flag = v3d->gizmo_flag; - v3d->gizmo_flag = V3D_GIZMO_HIDE; - } - } - - return true; + Scene *scene = CTX_data_scene(C); + BevelData *opdata; + ViewLayer *view_layer = CTX_data_view_layer(C); + float pixels_per_inch; + int i, otype; + + if (is_modal) { + RNA_float_set(op->ptr, "offset", 0.0f); + RNA_float_set(op->ptr, "offset_pct", 0.0f); + } + + op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator"); + uint objects_used_len = 0; + opdata->max_obj_scale = FLT_MIN; + + { + uint ob_store_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &ob_store_len); + opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); + for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { + Object *obedit = objects[ob_index]; + float scale = mat4_to_scale(obedit->obmat); + opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel > 0) { + opdata->ob_store[objects_used_len].em = em; + objects_used_len++; + } + } + MEM_freeN(objects); + opdata->ob_store_len = objects_used_len; + } + + opdata->is_modal = is_modal; + otype = RNA_enum_get(op->ptr, "offset_type"); + opdata->value_mode = (otype == BEVEL_AMT_PERCENT) ? OFFSET_VALUE_PERCENT : OFFSET_VALUE; + opdata->segments = (float)RNA_int_get(op->ptr, "segments"); + pixels_per_inch = U.dpi * U.pixelsize; + + for (i = 0; i < NUM_VALUE_KINDS; i++) { + opdata->shift_value[i] = -1.0f; + opdata->initial_length[i] = -1.0f; + /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */ + opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch; + + initNumInput(&opdata->num_input[i]); + opdata->num_input[i].idx_max = 0; + opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE; + if (i == SEGMENTS_VALUE) { + opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO; + } + if (i == OFFSET_VALUE) { + opdata->num_input[i].unit_sys = scene->unit.system; + } + /* Not sure this is a factor or a unit? */ + opdata->num_input[i].unit_type[0] = B_UNIT_NONE; + } + + /* avoid the cost of allocating a bm copy */ + if (is_modal) { + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store( + opdata->ob_store[ob_index].em); + } + opdata->draw_handle_pixel = ED_region_draw_cb_activate( + ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); + G.moving = G_TRANSFORM_EDIT; + + if (v3d) { + opdata->gizmo_flag = v3d->gizmo_flag; + v3d->gizmo_flag = V3D_GIZMO_HIDE; + } + } + + return true; } static bool edbm_bevel_calc(wmOperator *op) { - BevelData *opdata = op->customdata; - BMEditMesh *em; - BMOperator bmop; - bool changed = false; - - const float offset = get_bevel_offset(op); - const int offset_type = RNA_enum_get(op->ptr, "offset_type"); - const int segments = RNA_int_get(op->ptr, "segments"); - const float profile = RNA_float_get(op->ptr, "profile"); - const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); - const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap"); - int material = RNA_int_get(op->ptr, "material"); - const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide"); - const bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); - const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); - const bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals"); - const int face_strength_mode = RNA_enum_get(op->ptr, "face_strength_mode"); - const int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); - const int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); - const float spread = RNA_float_get(op->ptr, "spread"); - - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - em = opdata->ob_store[ob_index].em; - - /* revert to original mesh */ - if (opdata->is_modal) { - EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false); - } - - if (em->ob) { - material = CLAMPIS(material, -1, em->ob->totcol - 1); - } - - Mesh *me = em->ob->data; - - if (harden_normals && !(me->flag & ME_AUTOSMOOTH)) { - /* harden_normals only has a visible effect if autosmooth is on, so turn it on */ - me->flag |= ME_AUTOSMOOTH; - } - - EDBM_op_init( - em, &bmop, op, - "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f " - "clamp_overlap=%b material=%i loop_slide=%b mark_seam=%b mark_sharp=%b " - "harden_normals=%b face_strength_mode=%i " - "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f", - BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, - clamp_overlap, material, loop_slide, mark_seam, mark_sharp, harden_normals, face_strength_mode, - miter_outer, miter_inner, spread, me->smoothresh); - - BMO_op_exec(em->bm, &bmop); - - if (offset != 0.0f) { - /* not essential, but we may have some loose geometry that - * won't get bevel'd and better not leave it selected */ - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - } - - /* no need to de-select existing geometry */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - - EDBM_mesh_normals_update(em); - - EDBM_update_generic(em, true, true); - changed = true; - } - return changed; + BevelData *opdata = op->customdata; + BMEditMesh *em; + BMOperator bmop; + bool changed = false; + + const float offset = get_bevel_offset(op); + const int offset_type = RNA_enum_get(op->ptr, "offset_type"); + const int segments = RNA_int_get(op->ptr, "segments"); + const float profile = RNA_float_get(op->ptr, "profile"); + const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); + const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap"); + int material = RNA_int_get(op->ptr, "material"); + const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide"); + const bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); + const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); + const bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals"); + const int face_strength_mode = RNA_enum_get(op->ptr, "face_strength_mode"); + const int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); + const int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); + const float spread = RNA_float_get(op->ptr, "spread"); + + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + em = opdata->ob_store[ob_index].em; + + /* revert to original mesh */ + if (opdata->is_modal) { + EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false); + } + + if (em->ob) { + material = CLAMPIS(material, -1, em->ob->totcol - 1); + } + + Mesh *me = em->ob->data; + + if (harden_normals && !(me->flag & ME_AUTOSMOOTH)) { + /* harden_normals only has a visible effect if autosmooth is on, so turn it on */ + me->flag |= ME_AUTOSMOOTH; + } + + EDBM_op_init(em, + &bmop, + op, + "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f " + "clamp_overlap=%b material=%i loop_slide=%b mark_seam=%b mark_sharp=%b " + "harden_normals=%b face_strength_mode=%i " + "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f", + BM_ELEM_SELECT, + offset, + segments, + vertex_only, + offset_type, + profile, + clamp_overlap, + material, + loop_slide, + mark_seam, + mark_sharp, + harden_normals, + face_strength_mode, + miter_outer, + miter_inner, + spread, + me->smoothresh); + + BMO_op_exec(em->bm, &bmop); + + if (offset != 0.0f) { + /* not essential, but we may have some loose geometry that + * won't get bevel'd and better not leave it selected */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + } + + /* no need to de-select existing geometry */ + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_mesh_normals_update(em); + + EDBM_update_generic(em, true, true); + changed = true; + } + return changed; } static void edbm_bevel_exit(bContext *C, wmOperator *op) { - BevelData *opdata = op->customdata; - - ScrArea *sa = CTX_wm_area(C); - - if (sa) { - ED_area_status_text(sa, NULL); - } - - if (opdata->is_modal) { - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, NULL, false); - } - ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); - if (v3d) { - v3d->gizmo_flag = opdata->gizmo_flag; - } - G.moving = 0; - } - MEM_SAFE_FREE(opdata->ob_store); - MEM_SAFE_FREE(op->customdata); - op->customdata = NULL; + BevelData *opdata = op->customdata; + + ScrArea *sa = CTX_wm_area(C); + + if (sa) { + ED_area_status_text(sa, NULL); + } + + if (opdata->is_modal) { + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, NULL, false); + } + ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); + if (v3d) { + v3d->gizmo_flag = opdata->gizmo_flag; + } + G.moving = 0; + } + MEM_SAFE_FREE(opdata->ob_store); + MEM_SAFE_FREE(op->customdata); + op->customdata = NULL; } static void edbm_bevel_cancel(bContext *C, wmOperator *op) { - BevelData *opdata = op->customdata; - if (opdata->is_modal) { - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true); - EDBM_update_generic(opdata->ob_store[ob_index].em, false, true); - } - } - - edbm_bevel_exit(C, op); - - /* need to force redisplay or we may still view the modified result */ - ED_region_tag_redraw(CTX_wm_region(C)); + BevelData *opdata = op->customdata; + if (opdata->is_modal) { + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + EDBM_redo_state_free( + &opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true); + EDBM_update_generic(opdata->ob_store[ob_index].em, false, true); + } + } + + edbm_bevel_exit(C, op); + + /* need to force redisplay or we may still view the modified result */ + ED_region_tag_redraw(CTX_wm_region(C)); } /* bevel! yay!!*/ static int edbm_bevel_exec(bContext *C, wmOperator *op) { - if (!edbm_bevel_init(C, op, false)) { - return OPERATOR_CANCELLED; - } + if (!edbm_bevel_init(C, op, false)) { + return OPERATOR_CANCELLED; + } - if (!edbm_bevel_calc(op)) { - edbm_bevel_cancel(C, op); - return OPERATOR_CANCELLED; - } + if (!edbm_bevel_calc(op)) { + edbm_bevel_cancel(C, op); + return OPERATOR_CANCELLED; + } - edbm_bevel_exit(C, op); + edbm_bevel_exit(C, op); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event, bool mode_changed) { - BevelData *opdata; - float mlen[2], len, value, sc, st; - int vmode; - - opdata = op->customdata; - mlen[0] = opdata->mcenter[0] - event->mval[0]; - mlen[1] = opdata->mcenter[1] - event->mval[1]; - len = len_v2(mlen); - vmode = opdata->value_mode; - if (mode_changed || opdata->initial_length[vmode] == -1.0f) { - /* If current value is not default start value, adjust len so that - * the scaling and offset in edbm_bevel_mouse_set_value will - * start at current value */ - value = (vmode == SEGMENTS_VALUE) ? - opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]); - sc = opdata->scale[vmode]; - st = value_start[vmode]; - if (value != value_start[vmode]) { - len = (st + sc * (len - MVAL_PIXEL_MARGIN) - value) / sc; - } - } - opdata->initial_length[opdata->value_mode] = len; + BevelData *opdata; + float mlen[2], len, value, sc, st; + int vmode; + + opdata = op->customdata; + mlen[0] = opdata->mcenter[0] - event->mval[0]; + mlen[1] = opdata->mcenter[1] - event->mval[1]; + len = len_v2(mlen); + vmode = opdata->value_mode; + if (mode_changed || opdata->initial_length[vmode] == -1.0f) { + /* If current value is not default start value, adjust len so that + * the scaling and offset in edbm_bevel_mouse_set_value will + * start at current value */ + value = (vmode == SEGMENTS_VALUE) ? opdata->segments : + RNA_float_get(op->ptr, value_rna_name[vmode]); + sc = opdata->scale[vmode]; + st = value_start[vmode]; + if (value != value_start[vmode]) { + len = (st + sc * (len - MVAL_PIXEL_MARGIN) - value) / sc; + } + } + opdata->initial_length[opdata->value_mode] = len; } static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - BevelData *opdata; - float center_3d[3]; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + BevelData *opdata; + float center_3d[3]; - if (!edbm_bevel_init(C, op, true)) { - return OPERATOR_CANCELLED; - } + if (!edbm_bevel_init(C, op, true)) { + return OPERATOR_CANCELLED; + } - opdata = op->customdata; + opdata = op->customdata; - /* initialize mouse values */ - if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, center_3d, opdata->mcenter)) { - /* in this case the tool will likely do nothing, - * ideally this will never happen and should be checked for above */ - opdata->mcenter[0] = opdata->mcenter[1] = 0; - } + /* initialize mouse values */ + if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, center_3d, opdata->mcenter)) { + /* in this case the tool will likely do nothing, + * ideally this will never happen and should be checked for above */ + opdata->mcenter[0] = opdata->mcenter[1] = 0; + } - /* for OFFSET_VALUE only, the scale is the size of a pixel under the mouse in 3d space */ - opdata->scale[OFFSET_VALUE] = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; - /* since we are affecting untransformed object but seeing in transformed space, compensate for that */ - opdata->scale[OFFSET_VALUE] /= opdata->max_obj_scale; + /* for OFFSET_VALUE only, the scale is the size of a pixel under the mouse in 3d space */ + opdata->scale[OFFSET_VALUE] = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; + /* since we are affecting untransformed object but seeing in transformed space, compensate for that */ + opdata->scale[OFFSET_VALUE] /= opdata->max_obj_scale; - edbm_bevel_calc_initial_length(op, event, false); + edbm_bevel_calc_initial_length(op, event, false); - edbm_bevel_update_header(C, op); + edbm_bevel_update_header(C, op); - if (!edbm_bevel_calc(op)) { - edbm_bevel_cancel(C, op); - ED_workspace_status_text(C, NULL); - return OPERATOR_CANCELLED; - } + if (!edbm_bevel_calc(op)) { + edbm_bevel_cancel(C, op); + ED_workspace_status_text(C, NULL); + return OPERATOR_CANCELLED; + } - WM_event_add_modal_handler(C, op); + WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } static void edbm_bevel_mouse_set_value(wmOperator *op, const wmEvent *event) { - BevelData *opdata = op->customdata; - int vmode = opdata->value_mode; - float mdiff[2]; - float value; - - mdiff[0] = opdata->mcenter[0] - event->mval[0]; - mdiff[1] = opdata->mcenter[1] - event->mval[1]; - - value = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length[vmode]); - - /* Scale according to value mode */ - value = value_start[vmode] + value * opdata->scale[vmode]; - - /* Fake shift-transform... */ - if (event->shift) { - if (opdata->shift_value[vmode] < 0.0f) { - opdata->shift_value[vmode] = (vmode == SEGMENTS_VALUE) ? - opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]); - } - value = (value - opdata->shift_value[vmode]) * 0.1f + opdata->shift_value[vmode]; - } - else if (opdata->shift_value[vmode] >= 0.0f) { - opdata->shift_value[vmode] = -1.0f; - } - - /* clamp accordingto value mode, and store value back */ - CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); - if (vmode == SEGMENTS_VALUE) { - opdata->segments = value; - RNA_int_set(op->ptr, "segments", (int)(value + 0.5f)); - } - else { - RNA_float_set(op->ptr, value_rna_name[vmode], value); - } + BevelData *opdata = op->customdata; + int vmode = opdata->value_mode; + float mdiff[2]; + float value; + + mdiff[0] = opdata->mcenter[0] - event->mval[0]; + mdiff[1] = opdata->mcenter[1] - event->mval[1]; + + value = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length[vmode]); + + /* Scale according to value mode */ + value = value_start[vmode] + value * opdata->scale[vmode]; + + /* Fake shift-transform... */ + if (event->shift) { + if (opdata->shift_value[vmode] < 0.0f) { + opdata->shift_value[vmode] = (vmode == SEGMENTS_VALUE) ? + opdata->segments : + RNA_float_get(op->ptr, value_rna_name[vmode]); + } + value = (value - opdata->shift_value[vmode]) * 0.1f + opdata->shift_value[vmode]; + } + else if (opdata->shift_value[vmode] >= 0.0f) { + opdata->shift_value[vmode] = -1.0f; + } + + /* clamp accordingto value mode, and store value back */ + CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); + if (vmode == SEGMENTS_VALUE) { + opdata->segments = value; + RNA_int_set(op->ptr, "segments", (int)(value + 0.5f)); + } + else { + RNA_float_set(op->ptr, value_rna_name[vmode], value); + } } static void edbm_bevel_numinput_set_value(wmOperator *op) { - BevelData *opdata = op->customdata; - float value; - int vmode; - - vmode = opdata->value_mode; - value = (vmode == SEGMENTS_VALUE) ? - opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]); - applyNumInput(&opdata->num_input[vmode], &value); - CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); - if (vmode == SEGMENTS_VALUE) { - opdata->segments = value; - RNA_int_set(op->ptr, "segments", (int)value); - } - else { - RNA_float_set(op->ptr, value_rna_name[vmode], value); - } + BevelData *opdata = op->customdata; + float value; + int vmode; + + vmode = opdata->value_mode; + value = (vmode == SEGMENTS_VALUE) ? opdata->segments : + RNA_float_get(op->ptr, value_rna_name[vmode]); + applyNumInput(&opdata->num_input[vmode], &value); + CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); + if (vmode == SEGMENTS_VALUE) { + opdata->segments = value; + RNA_int_set(op->ptr, "segments", (int)value); + } + else { + RNA_float_set(op->ptr, value_rna_name[vmode], value); + } } /* Hide one of offset or offset_pct, depending on offset_type */ -static bool edbm_bevel_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) +static bool edbm_bevel_poll_property(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) { - const char *prop_id = RNA_property_identifier(prop); + const char *prop_id = RNA_property_identifier(prop); - if (STRPREFIX(prop_id, "offset")) { - int offset_type = RNA_enum_get(op->ptr, "offset_type"); + if (STRPREFIX(prop_id, "offset")) { + int offset_type = RNA_enum_get(op->ptr, "offset_type"); - if (STREQ(prop_id, "offset") && offset_type == BEVEL_AMT_PERCENT) - return false; - else if (STREQ(prop_id, "offset_pct") && offset_type != BEVEL_AMT_PERCENT) - return false; - } + if (STREQ(prop_id, "offset") && offset_type == BEVEL_AMT_PERCENT) + return false; + else if (STREQ(prop_id, "offset_pct") && offset_type != BEVEL_AMT_PERCENT) + return false; + } - return true; + return true; } wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf) { - static const EnumPropertyItem modal_items[] = { - {BEV_MODAL_CANCEL, "CANCEL", 0, "Cancel", "Cancel bevel"}, - {BEV_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", "Confirm bevel"}, - {BEV_MODAL_VALUE_OFFSET, "VALUE_OFFSET", 0, "Value is offset", - "Value changes offset"}, - {BEV_MODAL_VALUE_PROFILE, "VALUE_PROFILE", 0, "Value is profile", - "Value changes profile"}, - {BEV_MODAL_VALUE_SEGMENTS, "VALUE_SEGMENTS", 0, "Value is segments", - "Value changes segments"}, - {BEV_MODAL_SEGMENTS_UP, "SEGMENTS_UP", 0, "Increase segments", - "Increase segments"}, - {BEV_MODAL_SEGMENTS_DOWN, "SEGMENTS_DOWN", 0, "Decrease segments", - "Decrease segments"}, - {BEV_MODAL_OFFSET_MODE_CHANGE, "OFFSET_MODE_CHANGE", 0, "Change offset mode", - "Cycle through offset modes"}, - {BEV_MODAL_CLAMP_OVERLAP_TOGGLE, "CLAMP_OVERLAP_TOGGLE", 0, "Toggle clamp overlap", - "Toggle clamp overlap flag"}, - {BEV_MODAL_VERTEX_ONLY_TOGGLE, "VERTEX_ONLY_TOGGLE", 0, "Toggle vertex only", - "Toggle vertex only flag"}, - {BEV_MODAL_HARDEN_NORMALS_TOGGLE, "HARDEN_NORMALS_TOGGLE", 0, "Toggle harden normals", - "Toggle harden normals flag"}, - {BEV_MODAL_MARK_SEAM_TOGGLE, "MARK_SEAM_TOGGLE", 0, "Toggle mark seam", - "Toggle mark seam flag"}, - {BEV_MODAL_MARK_SHARP_TOGGLE, "MARK_SHARP_TOGGLE", 0, "Toggle mark sharp", - "Toggle mark sharp flag"}, - {BEV_MODAL_OUTER_MITER_CHANGE, "OUTER_MITER_CHANGE", 0, "Change outer miter", - "Cycle through outer miter kinds"}, - {BEV_MODAL_INNER_MITER_CHANGE, "INNER_MITER_CHANGE", 0, "Change inner miter", - "Cycle through inner miter kinds"}, - {0, NULL, 0, NULL, NULL}, - }; - - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Bevel Modal Map"); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) - return NULL; - - keymap = WM_modalkeymap_add(keyconf, "Bevel Modal Map", modal_items); - - WM_modalkeymap_assign(keymap, "MESH_OT_bevel"); - - return keymap; + static const EnumPropertyItem modal_items[] = { + {BEV_MODAL_CANCEL, "CANCEL", 0, "Cancel", "Cancel bevel"}, + {BEV_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", "Confirm bevel"}, + {BEV_MODAL_VALUE_OFFSET, "VALUE_OFFSET", 0, "Value is offset", "Value changes offset"}, + {BEV_MODAL_VALUE_PROFILE, "VALUE_PROFILE", 0, "Value is profile", "Value changes profile"}, + {BEV_MODAL_VALUE_SEGMENTS, + "VALUE_SEGMENTS", + 0, + "Value is segments", + "Value changes segments"}, + {BEV_MODAL_SEGMENTS_UP, "SEGMENTS_UP", 0, "Increase segments", "Increase segments"}, + {BEV_MODAL_SEGMENTS_DOWN, "SEGMENTS_DOWN", 0, "Decrease segments", "Decrease segments"}, + {BEV_MODAL_OFFSET_MODE_CHANGE, + "OFFSET_MODE_CHANGE", + 0, + "Change offset mode", + "Cycle through offset modes"}, + {BEV_MODAL_CLAMP_OVERLAP_TOGGLE, + "CLAMP_OVERLAP_TOGGLE", + 0, + "Toggle clamp overlap", + "Toggle clamp overlap flag"}, + {BEV_MODAL_VERTEX_ONLY_TOGGLE, + "VERTEX_ONLY_TOGGLE", + 0, + "Toggle vertex only", + "Toggle vertex only flag"}, + {BEV_MODAL_HARDEN_NORMALS_TOGGLE, + "HARDEN_NORMALS_TOGGLE", + 0, + "Toggle harden normals", + "Toggle harden normals flag"}, + {BEV_MODAL_MARK_SEAM_TOGGLE, + "MARK_SEAM_TOGGLE", + 0, + "Toggle mark seam", + "Toggle mark seam flag"}, + {BEV_MODAL_MARK_SHARP_TOGGLE, + "MARK_SHARP_TOGGLE", + 0, + "Toggle mark sharp", + "Toggle mark sharp flag"}, + {BEV_MODAL_OUTER_MITER_CHANGE, + "OUTER_MITER_CHANGE", + 0, + "Change outer miter", + "Cycle through outer miter kinds"}, + {BEV_MODAL_INNER_MITER_CHANGE, + "INNER_MITER_CHANGE", + 0, + "Change inner miter", + "Cycle through inner miter kinds"}, + {0, NULL, 0, NULL, NULL}, + }; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Bevel Modal Map"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) + return NULL; + + keymap = WM_modalkeymap_add(keyconf, "Bevel Modal Map", modal_items); + + WM_modalkeymap_assign(keymap, "MESH_OT_bevel"); + + return keymap; } static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) { - BevelData *opdata = op->customdata; - const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]); - bool handled = false; - short etype = event->type; - short eval = event->val; - - /* When activated from toolbar, need to convert leftmouse release to confirm */ - if (etype == LEFTMOUSE && eval == KM_RELEASE && - RNA_boolean_get(op->ptr, "release_confirm")) - { - etype = EVT_MODAL_MAP; - eval = BEV_MODAL_CONFIRM; - } - /* Modal numinput active, try to handle numeric inputs first... */ - if (etype != EVT_MODAL_MAP && eval == KM_PRESS && has_numinput && - handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) - { - edbm_bevel_numinput_set_value(op); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - return OPERATOR_RUNNING_MODAL; - } - else if (etype == MOUSEMOVE) { - if (!has_numinput) { - edbm_bevel_mouse_set_value(op, event); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - } - } - else if (etype == MOUSEPAN) { - float delta = 0.02f * (event->y - event->prevy); - if (opdata->segments >= 1 && opdata->segments + delta < 1) - opdata->segments = 1; - else - opdata->segments += delta; - RNA_int_set(op->ptr, "segments", (int)opdata->segments); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - } - else if (etype == EVT_MODAL_MAP) { - switch (eval) { - case BEV_MODAL_CANCEL: - edbm_bevel_cancel(C, op); - ED_workspace_status_text(C, NULL); - return OPERATOR_CANCELLED; - - case BEV_MODAL_CONFIRM: - edbm_bevel_calc(op); - edbm_bevel_exit(C, op); - ED_workspace_status_text(C, NULL); - return OPERATOR_FINISHED; - - case BEV_MODAL_SEGMENTS_UP: - opdata->segments = opdata->segments + 1; - RNA_int_set(op->ptr, "segments", (int)opdata->segments); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - - case BEV_MODAL_SEGMENTS_DOWN: - opdata->segments = max_ff(opdata->segments - 1, 1); - RNA_int_set(op->ptr, "segments", (int)opdata->segments); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - - case BEV_MODAL_OFFSET_MODE_CHANGE: - { - int type = RNA_enum_get(op->ptr, "offset_type"); - type++; - if (type > BEVEL_AMT_PERCENT) { - type = BEVEL_AMT_OFFSET; - } - if (opdata->value_mode == OFFSET_VALUE && type == BEVEL_AMT_PERCENT) - opdata->value_mode = OFFSET_VALUE_PERCENT; - else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT) - opdata->value_mode = OFFSET_VALUE; - RNA_enum_set(op->ptr, "offset_type", type); - if (opdata->initial_length[opdata->value_mode] == -1.0f) - edbm_bevel_calc_initial_length(op, event, true); - } - /* Update offset accordingly to new offset_type. */ - if (!has_numinput && - (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT)) - { - edbm_bevel_mouse_set_value(op, event); - } - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - - case BEV_MODAL_CLAMP_OVERLAP_TOGGLE: - { - bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap"); - RNA_boolean_set(op->ptr, "clamp_overlap", !clamp_overlap); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_VALUE_OFFSET: - opdata->value_mode = OFFSET_VALUE; - edbm_bevel_calc_initial_length(op, event, true); - break; - - case BEV_MODAL_VALUE_PROFILE: - opdata->value_mode = PROFILE_VALUE; - edbm_bevel_calc_initial_length(op, event, true); - break; - - case BEV_MODAL_VALUE_SEGMENTS: - opdata->value_mode = SEGMENTS_VALUE; - edbm_bevel_calc_initial_length(op, event, true); - break; - - case BEV_MODAL_VERTEX_ONLY_TOGGLE: - { - bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); - RNA_boolean_set(op->ptr, "vertex_only", !vertex_only); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_MARK_SEAM_TOGGLE: - { - bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); - RNA_boolean_set(op->ptr, "mark_seam", !mark_seam); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_MARK_SHARP_TOGGLE: - { - bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); - RNA_boolean_set(op->ptr, "mark_sharp", !mark_sharp); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_INNER_MITER_CHANGE: - { - int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); - miter_inner++; - if (miter_inner == BEVEL_MITER_PATCH) - miter_inner++; /* no patch option for inner miter */ - if (miter_inner > BEVEL_MITER_ARC) - miter_inner = BEVEL_MITER_SHARP; - RNA_enum_set(op->ptr, "miter_inner", miter_inner); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_OUTER_MITER_CHANGE: - { - int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); - miter_outer++; - if (miter_outer > BEVEL_MITER_ARC) - miter_outer = BEVEL_MITER_SHARP; - RNA_enum_set(op->ptr, "miter_outer", miter_outer); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_HARDEN_NORMALS_TOGGLE: - { - bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals"); - RNA_boolean_set(op->ptr, "harden_normals", !harden_normals); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - } - } - - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (!handled && eval == KM_PRESS && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) { - edbm_bevel_numinput_set_value(op); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - return OPERATOR_RUNNING_MODAL; - } - - return OPERATOR_RUNNING_MODAL; + BevelData *opdata = op->customdata; + const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]); + bool handled = false; + short etype = event->type; + short eval = event->val; + + /* When activated from toolbar, need to convert leftmouse release to confirm */ + if (etype == LEFTMOUSE && eval == KM_RELEASE && RNA_boolean_get(op->ptr, "release_confirm")) { + etype = EVT_MODAL_MAP; + eval = BEV_MODAL_CONFIRM; + } + /* Modal numinput active, try to handle numeric inputs first... */ + if (etype != EVT_MODAL_MAP && eval == KM_PRESS && has_numinput && + handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) { + edbm_bevel_numinput_set_value(op); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + return OPERATOR_RUNNING_MODAL; + } + else if (etype == MOUSEMOVE) { + if (!has_numinput) { + edbm_bevel_mouse_set_value(op, event); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + } + } + else if (etype == MOUSEPAN) { + float delta = 0.02f * (event->y - event->prevy); + if (opdata->segments >= 1 && opdata->segments + delta < 1) + opdata->segments = 1; + else + opdata->segments += delta; + RNA_int_set(op->ptr, "segments", (int)opdata->segments); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + } + else if (etype == EVT_MODAL_MAP) { + switch (eval) { + case BEV_MODAL_CANCEL: + edbm_bevel_cancel(C, op); + ED_workspace_status_text(C, NULL); + return OPERATOR_CANCELLED; + + case BEV_MODAL_CONFIRM: + edbm_bevel_calc(op); + edbm_bevel_exit(C, op); + ED_workspace_status_text(C, NULL); + return OPERATOR_FINISHED; + + case BEV_MODAL_SEGMENTS_UP: + opdata->segments = opdata->segments + 1; + RNA_int_set(op->ptr, "segments", (int)opdata->segments); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + + case BEV_MODAL_SEGMENTS_DOWN: + opdata->segments = max_ff(opdata->segments - 1, 1); + RNA_int_set(op->ptr, "segments", (int)opdata->segments); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + + case BEV_MODAL_OFFSET_MODE_CHANGE: { + int type = RNA_enum_get(op->ptr, "offset_type"); + type++; + if (type > BEVEL_AMT_PERCENT) { + type = BEVEL_AMT_OFFSET; + } + if (opdata->value_mode == OFFSET_VALUE && type == BEVEL_AMT_PERCENT) + opdata->value_mode = OFFSET_VALUE_PERCENT; + else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT) + opdata->value_mode = OFFSET_VALUE; + RNA_enum_set(op->ptr, "offset_type", type); + if (opdata->initial_length[opdata->value_mode] == -1.0f) + edbm_bevel_calc_initial_length(op, event, true); + } + /* Update offset accordingly to new offset_type. */ + if (!has_numinput && + (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT)) { + edbm_bevel_mouse_set_value(op, event); + } + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + + case BEV_MODAL_CLAMP_OVERLAP_TOGGLE: { + bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap"); + RNA_boolean_set(op->ptr, "clamp_overlap", !clamp_overlap); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_VALUE_OFFSET: + opdata->value_mode = OFFSET_VALUE; + edbm_bevel_calc_initial_length(op, event, true); + break; + + case BEV_MODAL_VALUE_PROFILE: + opdata->value_mode = PROFILE_VALUE; + edbm_bevel_calc_initial_length(op, event, true); + break; + + case BEV_MODAL_VALUE_SEGMENTS: + opdata->value_mode = SEGMENTS_VALUE; + edbm_bevel_calc_initial_length(op, event, true); + break; + + case BEV_MODAL_VERTEX_ONLY_TOGGLE: { + bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); + RNA_boolean_set(op->ptr, "vertex_only", !vertex_only); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_MARK_SEAM_TOGGLE: { + bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); + RNA_boolean_set(op->ptr, "mark_seam", !mark_seam); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_MARK_SHARP_TOGGLE: { + bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); + RNA_boolean_set(op->ptr, "mark_sharp", !mark_sharp); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_INNER_MITER_CHANGE: { + int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); + miter_inner++; + if (miter_inner == BEVEL_MITER_PATCH) + miter_inner++; /* no patch option for inner miter */ + if (miter_inner > BEVEL_MITER_ARC) + miter_inner = BEVEL_MITER_SHARP; + RNA_enum_set(op->ptr, "miter_inner", miter_inner); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_OUTER_MITER_CHANGE: { + int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); + miter_outer++; + if (miter_outer > BEVEL_MITER_ARC) + miter_outer = BEVEL_MITER_SHARP; + RNA_enum_set(op->ptr, "miter_outer", miter_outer); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_HARDEN_NORMALS_TOGGLE: { + bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals"); + RNA_boolean_set(op->ptr, "harden_normals", !harden_normals); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + } + } + + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && eval == KM_PRESS && + handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) { + edbm_bevel_numinput_set_value(op); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_RUNNING_MODAL; } void MESH_OT_bevel(wmOperatorType *ot) { - PropertyRNA *prop; - - static const EnumPropertyItem offset_type_items[] = { - {BEVEL_AMT_OFFSET, "OFFSET", 0, "Offset", "Amount is offset of new edges from original"}, - {BEVEL_AMT_WIDTH, "WIDTH", 0, "Width", "Amount is width of new face"}, - {BEVEL_AMT_DEPTH, "DEPTH", 0, "Depth", "Amount is perpendicular distance from original edge to bevel face"}, - {BEVEL_AMT_PERCENT, "PERCENT", 0, "Percent", "Amount is percent of adjacent edge length"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem face_strength_mode_items[] = { - {BEVEL_FACE_STRENGTH_NONE, "NONE", 0, "None", "Do not set face strength"}, - {BEVEL_FACE_STRENGTH_NEW, "NEW", 0, "New", "Set face strength on new faces only"}, - {BEVEL_FACE_STRENGTH_AFFECTED, "AFFECTED", 0, "Affected", "Set face strength on new and modified faces only"}, - {BEVEL_FACE_STRENGTH_ALL, "ALL", 0, "All", "Set face strength on all faces"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem miter_outer_items[] = { - {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Outside of miter is sharp"}, - {BEVEL_MITER_PATCH, "PATCH", 0, "Patch", "Outside of miter is squared-off patch"}, - {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Outside of miter is arc"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem miter_inner_items[] = { - {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Inside of miter is sharp"}, - {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Inside of miter is arc"}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Bevel"; - ot->description = "Edge Bevel"; - ot->idname = "MESH_OT_bevel"; - - /* api callbacks */ - ot->exec = edbm_bevel_exec; - ot->invoke = edbm_bevel_invoke; - ot->modal = edbm_bevel_modal; - ot->cancel = edbm_bevel_cancel; - ot->poll = ED_operator_editmesh; - ot->poll_property = edbm_bevel_poll_property; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; - - RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Width Type", "What distance Width measures"); - prop = RNA_def_property(ot->srna, "offset", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_range(prop, 0.0, 1e6); - RNA_def_property_ui_range(prop, 0.0f, 100.0, 1, 3); - RNA_def_property_ui_text(prop, "Width", "Bevel amount"); - prop = RNA_def_property(ot->srna, "offset_pct", PROP_FLOAT, PROP_PERCENTAGE); - RNA_def_property_range(prop, 0.0, 100); - RNA_def_property_ui_text(prop, "Width Percent", "Bevel amount for percentage method"); - RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 100); - RNA_def_float( - ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile", - "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f); - RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices"); - RNA_def_boolean( - ot->srna, "clamp_overlap", false, "Clamp Overlap", - "Do not allow beveled edges/vertices to overlap each other"); - RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths"); - RNA_def_boolean(ot->srna, "mark_seam", false, "Mark Seams", "Mark Seams along beveled edges"); - RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp"); - RNA_def_int( - ot->srna, "material", -1, -1, INT_MAX, "Material", - "Material for bevel faces (-1 means use adjacent faces)", -1, 100); - RNA_def_boolean( - ot->srna, "harden_normals", false, "Harden Normals", - "Match normals of new faces to adjacent faces"); - RNA_def_enum( - ot->srna, "face_strength_mode", face_strength_mode_items, BEVEL_FACE_STRENGTH_NONE, - "Face Strength Mode", "Whether to set face strength, and which faces to set face strength on"); - RNA_def_enum( - ot->srna, "miter_outer", miter_outer_items, BEVEL_MITER_SHARP, - "Outer Miter", "Pattern to use for outside of miters"); - RNA_def_enum( - ot->srna, "miter_inner", miter_inner_items, BEVEL_MITER_SHARP, - "Inner Miter", "Pattern to use for inside of miters"); - RNA_def_float( - ot->srna, "spread", 0.1f, 0.0f, 1e6f, "Spread", - "Amount to spread arcs for arc inner miters", 0.0f, 100.0f); - prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - + PropertyRNA *prop; + + static const EnumPropertyItem offset_type_items[] = { + {BEVEL_AMT_OFFSET, "OFFSET", 0, "Offset", "Amount is offset of new edges from original"}, + {BEVEL_AMT_WIDTH, "WIDTH", 0, "Width", "Amount is width of new face"}, + {BEVEL_AMT_DEPTH, + "DEPTH", + 0, + "Depth", + "Amount is perpendicular distance from original edge to bevel face"}, + {BEVEL_AMT_PERCENT, "PERCENT", 0, "Percent", "Amount is percent of adjacent edge length"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem face_strength_mode_items[] = { + {BEVEL_FACE_STRENGTH_NONE, "NONE", 0, "None", "Do not set face strength"}, + {BEVEL_FACE_STRENGTH_NEW, "NEW", 0, "New", "Set face strength on new faces only"}, + {BEVEL_FACE_STRENGTH_AFFECTED, + "AFFECTED", + 0, + "Affected", + "Set face strength on new and modified faces only"}, + {BEVEL_FACE_STRENGTH_ALL, "ALL", 0, "All", "Set face strength on all faces"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem miter_outer_items[] = { + {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Outside of miter is sharp"}, + {BEVEL_MITER_PATCH, "PATCH", 0, "Patch", "Outside of miter is squared-off patch"}, + {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Outside of miter is arc"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem miter_inner_items[] = { + {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Inside of miter is sharp"}, + {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Inside of miter is arc"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Bevel"; + ot->description = "Edge Bevel"; + ot->idname = "MESH_OT_bevel"; + + /* api callbacks */ + ot->exec = edbm_bevel_exec; + ot->invoke = edbm_bevel_invoke; + ot->modal = edbm_bevel_modal; + ot->cancel = edbm_bevel_cancel; + ot->poll = ED_operator_editmesh; + ot->poll_property = edbm_bevel_poll_property; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; + + RNA_def_enum( + ot->srna, "offset_type", offset_type_items, 0, "Width Type", "What distance Width measures"); + prop = RNA_def_property(ot->srna, "offset", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_range(prop, 0.0, 1e6); + RNA_def_property_ui_range(prop, 0.0f, 100.0, 1, 3); + RNA_def_property_ui_text(prop, "Width", "Bevel amount"); + prop = RNA_def_property(ot->srna, "offset_pct", PROP_FLOAT, PROP_PERCENTAGE); + RNA_def_property_range(prop, 0.0, 100); + RNA_def_property_ui_text(prop, "Width Percent", "Bevel amount for percentage method"); + RNA_def_int(ot->srna, + "segments", + 1, + 1, + SEGMENTS_HARD_MAX, + "Segments", + "Segments for curved edge", + 1, + 100); + RNA_def_float(ot->srna, + "profile", + 0.5f, + PROFILE_HARD_MIN, + 1.0f, + "Profile", + "Controls profile shape (0.5 = round)", + PROFILE_HARD_MIN, + 1.0f); + RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices"); + RNA_def_boolean(ot->srna, + "clamp_overlap", + false, + "Clamp Overlap", + "Do not allow beveled edges/vertices to overlap each other"); + RNA_def_boolean( + ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths"); + RNA_def_boolean(ot->srna, "mark_seam", false, "Mark Seams", "Mark Seams along beveled edges"); + RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp"); + RNA_def_int(ot->srna, + "material", + -1, + -1, + INT_MAX, + "Material", + "Material for bevel faces (-1 means use adjacent faces)", + -1, + 100); + RNA_def_boolean(ot->srna, + "harden_normals", + false, + "Harden Normals", + "Match normals of new faces to adjacent faces"); + RNA_def_enum(ot->srna, + "face_strength_mode", + face_strength_mode_items, + BEVEL_FACE_STRENGTH_NONE, + "Face Strength Mode", + "Whether to set face strength, and which faces to set face strength on"); + RNA_def_enum(ot->srna, + "miter_outer", + miter_outer_items, + BEVEL_MITER_SHARP, + "Outer Miter", + "Pattern to use for outside of miters"); + RNA_def_enum(ot->srna, + "miter_inner", + miter_inner_items, + BEVEL_MITER_SHARP, + "Inner Miter", + "Pattern to use for inside of miters"); + RNA_def_float(ot->srna, + "spread", + 0.1f, + 0.0f, + 1e6f, + "Spread", + "Amount to spread arcs for arc inner miters", + 0.0f, + 100.0f); + prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index 61531109a01..bc60ff9274f 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -48,13 +48,13 @@ #include "UI_resources.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ #define USE_GIZMO #ifdef USE_GIZMO -#include "ED_gizmo_library.h" -#include "ED_undo.h" +# include "ED_gizmo_library.h" +# include "ED_undo.h" #endif static int mesh_bisect_exec(bContext *C, wmOperator *op); @@ -63,315 +63,334 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op); /* Model Helpers */ typedef struct { - /* modal only */ - - /* Aligned with objects array. */ - struct { - BMBackup mesh; - bool is_valid; - bool is_dirty; - } *backup; - int backup_len; - short gizmo_flag; + /* modal only */ + + /* Aligned with objects array. */ + struct { + BMBackup mesh; + bool is_valid; + bool is_dirty; + } * backup; + int backup_len; + short gizmo_flag; } BisectData; -static void mesh_bisect_interactive_calc( - bContext *C, wmOperator *op, - float plane_co[3], float plane_no[3]) +static void mesh_bisect_interactive_calc(bContext *C, + wmOperator *op, + float plane_co[3], + float plane_no[3]) { - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - - int x_start = RNA_int_get(op->ptr, "xstart"); - int y_start = RNA_int_get(op->ptr, "ystart"); - int x_end = RNA_int_get(op->ptr, "xend"); - int y_end = RNA_int_get(op->ptr, "yend"); - - /* reference location (some point in front of the view) for finding a point on a plane */ - const float *co_ref = rv3d->ofs; - float co_a_ss[2] = {x_start, y_start}, co_b_ss[2] = {x_end, y_end}, co_delta_ss[2]; - float co_a[3], co_b[3]; - const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL); - - /* view vector */ - ED_view3d_win_to_vector(ar, co_a_ss, co_a); - - /* view delta */ - sub_v2_v2v2(co_delta_ss, co_a_ss, co_b_ss); - ED_view3d_win_to_delta(ar, co_delta_ss, co_b, zfac); - - /* cross both to get a normal */ - cross_v3_v3v3(plane_no, co_a, co_b); - normalize_v3(plane_no); /* not needed but nicer for user */ - - /* point on plane, can use either start or endpoint */ - ED_view3d_win_to_3d(v3d, ar, co_ref, co_a_ss, plane_co); + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + int x_start = RNA_int_get(op->ptr, "xstart"); + int y_start = RNA_int_get(op->ptr, "ystart"); + int x_end = RNA_int_get(op->ptr, "xend"); + int y_end = RNA_int_get(op->ptr, "yend"); + + /* reference location (some point in front of the view) for finding a point on a plane */ + const float *co_ref = rv3d->ofs; + float co_a_ss[2] = {x_start, y_start}, co_b_ss[2] = {x_end, y_end}, co_delta_ss[2]; + float co_a[3], co_b[3]; + const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL); + + /* view vector */ + ED_view3d_win_to_vector(ar, co_a_ss, co_a); + + /* view delta */ + sub_v2_v2v2(co_delta_ss, co_a_ss, co_b_ss); + ED_view3d_win_to_delta(ar, co_delta_ss, co_b, zfac); + + /* cross both to get a normal */ + cross_v3_v3v3(plane_no, co_a, co_b); + normalize_v3(plane_no); /* not needed but nicer for user */ + + /* point on plane, can use either start or endpoint */ + ED_view3d_win_to_3d(v3d, ar, co_ref, co_a_ss, plane_co); } static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ViewLayer *view_layer = CTX_data_view_layer(C); - int valid_objects = 0; - - /* If the properties are set or there is no rv3d, - * skip model and exec immediately. */ - if ((CTX_wm_region_view3d(C) == NULL) || - (RNA_struct_property_is_set(op->ptr, "plane_co") && - RNA_struct_property_is_set(op->ptr, "plane_no"))) - { - return mesh_bisect_exec(C, op); - } - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totedgesel != 0) { - valid_objects++; - } - } - - if (valid_objects == 0) { - BKE_report(op->reports, RPT_ERROR, "Selected edges/faces required"); - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - - int ret = WM_gesture_straightline_invoke(C, op, event); - if (ret & OPERATOR_RUNNING_MODAL) { - View3D *v3d = CTX_wm_view3d(C); - - wmGesture *gesture = op->customdata; - BisectData *opdata; - - opdata = MEM_mallocN(sizeof(BisectData), "inset_operator_data"); - gesture->userdata = opdata; - - opdata->backup_len = objects_len; - opdata->backup = MEM_callocN(sizeof(*opdata->backup) * objects_len, __func__); - - /* Store the mesh backups. */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totedgesel != 0) { - opdata->backup[ob_index].is_valid = true; - opdata->backup[ob_index].mesh = EDBM_redo_state_store(em); - } - } - - /* Misc other vars. */ - G.moving = G_TRANSFORM_EDIT; - opdata->gizmo_flag = v3d->gizmo_flag; - v3d->gizmo_flag = V3D_GIZMO_HIDE; - - /* Initialize modal callout. */ - ED_workspace_status_text(C, IFACE_("LMB: Click and drag to draw cut line")); - } - MEM_freeN(objects); - return ret; + ViewLayer *view_layer = CTX_data_view_layer(C); + int valid_objects = 0; + + /* If the properties are set or there is no rv3d, + * skip model and exec immediately. */ + if ((CTX_wm_region_view3d(C) == NULL) || (RNA_struct_property_is_set(op->ptr, "plane_co") && + RNA_struct_property_is_set(op->ptr, "plane_no"))) { + return mesh_bisect_exec(C, op); + } + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totedgesel != 0) { + valid_objects++; + } + } + + if (valid_objects == 0) { + BKE_report(op->reports, RPT_ERROR, "Selected edges/faces required"); + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + + int ret = WM_gesture_straightline_invoke(C, op, event); + if (ret & OPERATOR_RUNNING_MODAL) { + View3D *v3d = CTX_wm_view3d(C); + + wmGesture *gesture = op->customdata; + BisectData *opdata; + + opdata = MEM_mallocN(sizeof(BisectData), "inset_operator_data"); + gesture->userdata = opdata; + + opdata->backup_len = objects_len; + opdata->backup = MEM_callocN(sizeof(*opdata->backup) * objects_len, __func__); + + /* Store the mesh backups. */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totedgesel != 0) { + opdata->backup[ob_index].is_valid = true; + opdata->backup[ob_index].mesh = EDBM_redo_state_store(em); + } + } + + /* Misc other vars. */ + G.moving = G_TRANSFORM_EDIT; + opdata->gizmo_flag = v3d->gizmo_flag; + v3d->gizmo_flag = V3D_GIZMO_HIDE; + + /* Initialize modal callout. */ + ED_workspace_status_text(C, IFACE_("LMB: Click and drag to draw cut line")); + } + MEM_freeN(objects); + return ret; } static void edbm_bisect_exit(bContext *C, BisectData *opdata) { - View3D *v3d = CTX_wm_view3d(C); - v3d->gizmo_flag = opdata->gizmo_flag; - G.moving = 0; - - for (int ob_index = 0; ob_index < opdata->backup_len; ob_index++) { - if (opdata->backup[ob_index].is_valid) { - EDBM_redo_state_free(&opdata->backup[ob_index].mesh, NULL, false); - } - } - MEM_freeN(opdata->backup); + View3D *v3d = CTX_wm_view3d(C); + v3d->gizmo_flag = opdata->gizmo_flag; + G.moving = 0; + + for (int ob_index = 0; ob_index < opdata->backup_len; ob_index++) { + if (opdata->backup[ob_index].is_valid) { + EDBM_redo_state_free(&opdata->backup[ob_index].mesh, NULL, false); + } + } + MEM_freeN(opdata->backup); } static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event) { - wmGesture *gesture = op->customdata; - BisectData *opdata = gesture->userdata; - BisectData opdata_back = *opdata; /* annoyance, WM_gesture_straightline_modal, frees */ - int ret; - - ret = WM_gesture_straightline_modal(C, op, event); - - /* update or clear modal callout */ - if (event->type == EVT_MODAL_MAP) { - if (event->val == GESTURE_MODAL_BEGIN) { - ED_workspace_status_text(C, IFACE_("LMB: Release to confirm cut line")); - } - else { - ED_workspace_status_text(C, NULL); - } - } - - if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) { - edbm_bisect_exit(C, &opdata_back); + wmGesture *gesture = op->customdata; + BisectData *opdata = gesture->userdata; + BisectData opdata_back = *opdata; /* annoyance, WM_gesture_straightline_modal, frees */ + int ret; + + ret = WM_gesture_straightline_modal(C, op, event); + + /* update or clear modal callout */ + if (event->type == EVT_MODAL_MAP) { + if (event->val == GESTURE_MODAL_BEGIN) { + ED_workspace_status_text(C, IFACE_("LMB: Release to confirm cut line")); + } + else { + ED_workspace_status_text(C, NULL); + } + } + + if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) { + edbm_bisect_exit(C, &opdata_back); #ifdef USE_GIZMO - /* Setup gizmos */ - { - View3D *v3d = CTX_wm_view3d(C); - if (v3d && (v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) { - WM_gizmo_group_type_ensure("MESH_GGT_bisect"); - } - } + /* Setup gizmos */ + { + View3D *v3d = CTX_wm_view3d(C); + if (v3d && (v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) { + WM_gizmo_group_type_ensure("MESH_GGT_bisect"); + } + } #endif - } + } - return ret; + return ret; } /* End Model Helpers */ /* -------------------------------------------------------------------- */ - - static int mesh_bisect_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - - /* both can be NULL, fallbacks values are used */ - RegionView3D *rv3d = ED_view3d_context_rv3d(C); - - int ret = OPERATOR_CANCELLED; - - float plane_co[3]; - float plane_no[3]; - float imat[4][4]; - - const float thresh = RNA_float_get(op->ptr, "threshold"); - const bool use_fill = RNA_boolean_get(op->ptr, "use_fill"); - const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner"); - const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer"); - - PropertyRNA *prop_plane_co; - PropertyRNA *prop_plane_no; - - prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co"); - if (RNA_property_is_set(op->ptr, prop_plane_co)) { - RNA_property_float_get_array(op->ptr, prop_plane_co, plane_co); - } - else { - copy_v3_v3(plane_co, scene->cursor.location); - RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); - } - - prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no"); - if (RNA_property_is_set(op->ptr, prop_plane_no)) { - RNA_property_float_get_array(op->ptr, prop_plane_no, plane_no); - } - else { - if (rv3d) { - copy_v3_v3(plane_no, rv3d->viewinv[1]); - } - else { - /* fallback... */ - plane_no[0] = plane_no[1] = 0.0f; plane_no[2] = 1.0f; - } - RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); - } - - wmGesture *gesture = op->customdata; - BisectData *opdata = (gesture != NULL) ? gesture->userdata : NULL; - - /* -------------------------------------------------------------------- */ - /* Modal support */ - /* Note: keep this isolated, exec can work without this */ - if (opdata != NULL) { - mesh_bisect_interactive_calc(C, op, plane_co, plane_no); - /* Write back to the props. */ - RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); - RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); - } - /* End Modal */ - /* -------------------------------------------------------------------- */ - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(CTX_data_view_layer(C), CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if (opdata != NULL) { - if (opdata->backup[ob_index].is_dirty) { - EDBM_redo_state_restore(opdata->backup[ob_index].mesh, em, false); - opdata->backup[ob_index].is_dirty = false; - } - } - - if (bm->totedgesel == 0) { - continue; - } - - if (opdata != NULL) { - if (opdata->backup[ob_index].is_valid) { - opdata->backup[ob_index].is_dirty = true; - } - } - - float plane_co_local[3]; - float plane_no_local[3]; - copy_v3_v3(plane_co_local, plane_co); - copy_v3_v3(plane_no_local, plane_no); - - invert_m4_m4(imat, obedit->obmat); - mul_m4_v3(imat, plane_co_local); - mul_transposed_mat3_m4_v3(obedit->obmat, plane_no_local); - - BMOperator bmop; - EDBM_op_init(em, &bmop, op, - "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b", - BM_ELEM_SELECT, plane_co_local, plane_no_local, thresh, clear_inner, clear_outer); - BMO_op_exec(bm, &bmop); - - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - - if (use_fill) { - float normal_fill[3]; - BMOperator bmop_fill; - BMOperator bmop_attr; - - normalize_v3_v3(normal_fill, plane_no_local); - if (clear_outer == true && clear_inner == false) { - negate_v3(normal_fill); - } - - /* Fill */ - BMO_op_initf( - bm, &bmop_fill, 0, - "triangle_fill edges=%S normal=%v use_dissolve=%b", - &bmop, "geom_cut.out", normal_fill, true); - BMO_op_exec(bm, &bmop_fill); - - /* Copy Attributes */ - BMO_op_initf(bm, &bmop_attr, 0, - "face_attribute_fill faces=%S use_normals=%b use_data=%b", - &bmop_fill, "geom.out", false, true); - BMO_op_exec(bm, &bmop_attr); - - BMO_slot_buffer_hflag_enable(bm, bmop_fill.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); - - BMO_op_finish(bm, &bmop_attr); - BMO_op_finish(bm, &bmop_fill); - } - - BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); - - if (EDBM_op_finish(em, &bmop, op, true)) { - EDBM_update_generic(em, true, true); - EDBM_selectmode_flush(em); - ret = OPERATOR_FINISHED; - } - } - MEM_freeN(objects); - return ret; + Scene *scene = CTX_data_scene(C); + + /* both can be NULL, fallbacks values are used */ + RegionView3D *rv3d = ED_view3d_context_rv3d(C); + + int ret = OPERATOR_CANCELLED; + + float plane_co[3]; + float plane_no[3]; + float imat[4][4]; + + const float thresh = RNA_float_get(op->ptr, "threshold"); + const bool use_fill = RNA_boolean_get(op->ptr, "use_fill"); + const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner"); + const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer"); + + PropertyRNA *prop_plane_co; + PropertyRNA *prop_plane_no; + + prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co"); + if (RNA_property_is_set(op->ptr, prop_plane_co)) { + RNA_property_float_get_array(op->ptr, prop_plane_co, plane_co); + } + else { + copy_v3_v3(plane_co, scene->cursor.location); + RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); + } + + prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no"); + if (RNA_property_is_set(op->ptr, prop_plane_no)) { + RNA_property_float_get_array(op->ptr, prop_plane_no, plane_no); + } + else { + if (rv3d) { + copy_v3_v3(plane_no, rv3d->viewinv[1]); + } + else { + /* fallback... */ + plane_no[0] = plane_no[1] = 0.0f; + plane_no[2] = 1.0f; + } + RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); + } + + wmGesture *gesture = op->customdata; + BisectData *opdata = (gesture != NULL) ? gesture->userdata : NULL; + + /* -------------------------------------------------------------------- */ + /* Modal support */ + /* Note: keep this isolated, exec can work without this */ + if (opdata != NULL) { + mesh_bisect_interactive_calc(C, op, plane_co, plane_no); + /* Write back to the props. */ + RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); + RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); + } + /* End Modal */ + /* -------------------------------------------------------------------- */ + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + CTX_data_view_layer(C), CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if (opdata != NULL) { + if (opdata->backup[ob_index].is_dirty) { + EDBM_redo_state_restore(opdata->backup[ob_index].mesh, em, false); + opdata->backup[ob_index].is_dirty = false; + } + } + + if (bm->totedgesel == 0) { + continue; + } + + if (opdata != NULL) { + if (opdata->backup[ob_index].is_valid) { + opdata->backup[ob_index].is_dirty = true; + } + } + + float plane_co_local[3]; + float plane_no_local[3]; + copy_v3_v3(plane_co_local, plane_co); + copy_v3_v3(plane_no_local, plane_no); + + invert_m4_m4(imat, obedit->obmat); + mul_m4_v3(imat, plane_co_local); + mul_transposed_mat3_m4_v3(obedit->obmat, plane_no_local); + + BMOperator bmop; + EDBM_op_init( + em, + &bmop, + op, + "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b", + BM_ELEM_SELECT, + plane_co_local, + plane_no_local, + thresh, + clear_inner, + clear_outer); + BMO_op_exec(bm, &bmop); + + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + if (use_fill) { + float normal_fill[3]; + BMOperator bmop_fill; + BMOperator bmop_attr; + + normalize_v3_v3(normal_fill, plane_no_local); + if (clear_outer == true && clear_inner == false) { + negate_v3(normal_fill); + } + + /* Fill */ + BMO_op_initf(bm, + &bmop_fill, + 0, + "triangle_fill edges=%S normal=%v use_dissolve=%b", + &bmop, + "geom_cut.out", + normal_fill, + true); + BMO_op_exec(bm, &bmop_fill); + + /* Copy Attributes */ + BMO_op_initf(bm, + &bmop_attr, + 0, + "face_attribute_fill faces=%S use_normals=%b use_data=%b", + &bmop_fill, + "geom.out", + false, + true); + BMO_op_exec(bm, &bmop_attr); + + BMO_slot_buffer_hflag_enable( + bm, bmop_fill.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); + + BMO_op_finish(bm, &bmop_attr); + BMO_op_finish(bm, &bmop_fill); + } + + BMO_slot_buffer_hflag_enable( + bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); + + if (EDBM_op_finish(em, &bmop, op, true)) { + EDBM_update_generic(em, true, true); + EDBM_selectmode_flush(em); + ret = OPERATOR_FINISHED; + } + } + MEM_freeN(objects); + return ret; } #ifdef USE_GIZMO @@ -380,46 +399,69 @@ static void MESH_GGT_bisect(struct wmGizmoGroupType *gzgt); void MESH_OT_bisect(struct wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Bisect"; - ot->description = "Cut geometry along a plane (click-drag to define plane)"; - ot->idname = "MESH_OT_bisect"; - - /* api callbacks */ - ot->exec = mesh_bisect_exec; - ot->invoke = mesh_bisect_invoke; - ot->modal = mesh_bisect_modal; - ot->cancel = WM_gesture_straightline_cancel; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - - prop = RNA_def_float_vector_xyz(ot->srna, "plane_co", 3, NULL, -1e12f, 1e12f, - "Plane Point", "A point on the plane", -1e4f, 1e4f); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -1.0f, 1.0f, - "Plane Normal", "The direction the plane points", -1.0f, 1.0f); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill in the cut"); - RNA_def_boolean(ot->srna, "clear_inner", false, "Clear Inner", "Remove geometry behind the plane"); - RNA_def_boolean(ot->srna, "clear_outer", false, "Clear Outer", "Remove geometry in front of the plane"); - - RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Axis Threshold", - "Preserves the existing geometry along the cut plane", 0.00001, 0.1); - - WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Bisect"; + ot->description = "Cut geometry along a plane (click-drag to define plane)"; + ot->idname = "MESH_OT_bisect"; + + /* api callbacks */ + ot->exec = mesh_bisect_exec; + ot->invoke = mesh_bisect_invoke; + ot->modal = mesh_bisect_modal; + ot->cancel = WM_gesture_straightline_cancel; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_float_vector_xyz(ot->srna, + "plane_co", + 3, + NULL, + -1e12f, + 1e12f, + "Plane Point", + "A point on the plane", + -1e4f, + 1e4f); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_float_vector(ot->srna, + "plane_no", + 3, + NULL, + -1.0f, + 1.0f, + "Plane Normal", + "The direction the plane points", + -1.0f, + 1.0f); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill in the cut"); + RNA_def_boolean( + ot->srna, "clear_inner", false, "Clear Inner", "Remove geometry behind the plane"); + RNA_def_boolean( + ot->srna, "clear_outer", false, "Clear Outer", "Remove geometry in front of the plane"); + + RNA_def_float(ot->srna, + "threshold", + 0.0001, + 0.0, + 10.0, + "Axis Threshold", + "Preserves the existing geometry along the cut plane", + 0.00001, + 0.1); + + WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); #ifdef USE_GIZMO - WM_gizmogrouptype_append(MESH_GGT_bisect); + WM_gizmogrouptype_append(MESH_GGT_bisect); #endif } - #ifdef USE_GIZMO /* -------------------------------------------------------------------- */ @@ -427,23 +469,23 @@ void MESH_OT_bisect(struct wmOperatorType *ot) * \{ */ typedef struct GizmoGroup { - /* Arrow to change plane depth. */ - struct wmGizmo *translate_z; - /* Translate XYZ */ - struct wmGizmo *translate_c; - /* For grabbing the gizmo and moving freely. */ - struct wmGizmo *rotate_c; - - /* We could store more vars here! */ - struct { - bContext *context; - wmOperator *op; - PropertyRNA *prop_plane_co; - PropertyRNA *prop_plane_no; - - float rotate_axis[3]; - float rotate_up[3]; - } data; + /* Arrow to change plane depth. */ + struct wmGizmo *translate_z; + /* Translate XYZ */ + struct wmGizmo *translate_c; + /* For grabbing the gizmo and moving freely. */ + struct wmGizmo *rotate_c; + + /* We could store more vars here! */ + struct { + bContext *context; + wmOperator *op; + PropertyRNA *prop_plane_co; + PropertyRNA *prop_plane_no; + + float rotate_axis[3]; + float rotate_up[3]; + } data; } GizmoGroup; /** @@ -453,285 +495,284 @@ typedef struct GizmoGroup { */ static void gizmo_bisect_exec(GizmoGroup *ggd) { - wmOperator *op = ggd->data.op; - if (op == WM_operator_last_redo((bContext *)ggd->data.context)) { - ED_undo_operator_repeat((bContext *)ggd->data.context, op); - } + wmOperator *op = ggd->data.op; + if (op == WM_operator_last_redo((bContext *)ggd->data.context)) { + ED_undo_operator_repeat((bContext *)ggd->data.context, op); + } } static void gizmo_mesh_bisect_update_from_op(GizmoGroup *ggd) { - wmOperator *op = ggd->data.op; + wmOperator *op = ggd->data.op; - float plane_co[3], plane_no[3]; + float plane_co[3], plane_no[3]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, plane_co); - RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no); + RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, plane_co); + RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no); - WM_gizmo_set_matrix_location(ggd->translate_z, plane_co); - WM_gizmo_set_matrix_location(ggd->rotate_c, plane_co); - /* translate_c location comes from the property. */ + WM_gizmo_set_matrix_location(ggd->translate_z, plane_co); + WM_gizmo_set_matrix_location(ggd->rotate_c, plane_co); + /* translate_c location comes from the property. */ - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_z, plane_no); + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_z, plane_no); - WM_gizmo_set_scale(ggd->translate_c, 0.2); + WM_gizmo_set_scale(ggd->translate_c, 0.2); - RegionView3D *rv3d = ED_view3d_context_rv3d(ggd->data.context); - if (rv3d) { - normalize_v3_v3(ggd->data.rotate_axis, rv3d->viewinv[2]); - normalize_v3_v3(ggd->data.rotate_up, rv3d->viewinv[1]); + RegionView3D *rv3d = ED_view3d_context_rv3d(ggd->data.context); + if (rv3d) { + normalize_v3_v3(ggd->data.rotate_axis, rv3d->viewinv[2]); + normalize_v3_v3(ggd->data.rotate_up, rv3d->viewinv[1]); - /* ensure its orthogonal */ - project_plane_normalized_v3_v3v3(ggd->data.rotate_up, ggd->data.rotate_up, ggd->data.rotate_axis); - normalize_v3(ggd->data.rotate_up); + /* ensure its orthogonal */ + project_plane_normalized_v3_v3v3( + ggd->data.rotate_up, ggd->data.rotate_up, ggd->data.rotate_axis); + normalize_v3(ggd->data.rotate_up); - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_c, plane_no); + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_c, plane_no); - float plane_no_cross[3]; - cross_v3_v3v3(plane_no_cross, plane_no, ggd->data.rotate_axis); + float plane_no_cross[3]; + cross_v3_v3v3(plane_no_cross, plane_no, ggd->data.rotate_axis); - WM_gizmo_set_matrix_offset_rotation_from_yz_axis(ggd->rotate_c, plane_no_cross, ggd->data.rotate_axis); - RNA_enum_set(ggd->rotate_c->ptr, "draw_options", - ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR | - ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y); - } + WM_gizmo_set_matrix_offset_rotation_from_yz_axis( + ggd->rotate_c, plane_no_cross, ggd->data.rotate_axis); + RNA_enum_set(ggd->rotate_c->ptr, + "draw_options", + ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR | ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y); + } } /* depth callbacks */ -static void gizmo_bisect_prop_depth_get( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - void *value_p) +static void gizmo_bisect_prop_depth_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoGroup *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - float *value = value_p; + GizmoGroup *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + float *value = value_p; - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); - float plane_co[3], plane_no[3]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, plane_co); - RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no); + float plane_co[3], plane_no[3]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, plane_co); + RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no); - value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]); + value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]); } -static void gizmo_bisect_prop_depth_set( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - const void *value_p) +static void gizmo_bisect_prop_depth_set(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + const void *value_p) { - GizmoGroup *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - const float *value = value_p; + GizmoGroup *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + const float *value = value_p; - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); - float plane_co[3], plane[4]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, plane_co); - RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane); - normalize_v3(plane); + float plane_co[3], plane[4]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, plane_co); + RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane); + normalize_v3(plane); - plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]); + plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]); - /* Keep our location, may be offset simply to be inside the viewport. */ - closest_to_plane_normalized_v3(plane_co, plane, plane_co); + /* Keep our location, may be offset simply to be inside the viewport. */ + closest_to_plane_normalized_v3(plane_co, plane, plane_co); - RNA_property_float_set_array(op->ptr, ggd->data.prop_plane_co, plane_co); + RNA_property_float_set_array(op->ptr, ggd->data.prop_plane_co, plane_co); - gizmo_bisect_exec(ggd); + gizmo_bisect_exec(ggd); } /* translate callbacks */ -static void gizmo_bisect_prop_translate_get( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - void *value_p) +static void gizmo_bisect_prop_translate_get(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + void *value_p) { - GizmoGroup *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; + GizmoGroup *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; - BLI_assert(gz_prop->type->array_length == 3); - UNUSED_VARS_NDEBUG(gz_prop); + BLI_assert(gz_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(gz_prop); - RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, value_p); + RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, value_p); } -static void gizmo_bisect_prop_translate_set( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - const void *value_p) +static void gizmo_bisect_prop_translate_set(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + const void *value_p) { - GizmoGroup *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; + GizmoGroup *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; - BLI_assert(gz_prop->type->array_length == 3); - UNUSED_VARS_NDEBUG(gz_prop); + BLI_assert(gz_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(gz_prop); - RNA_property_float_set_array(op->ptr, ggd->data.prop_plane_co, value_p); + RNA_property_float_set_array(op->ptr, ggd->data.prop_plane_co, value_p); - gizmo_bisect_exec(ggd); + gizmo_bisect_exec(ggd); } /* angle callbacks */ -static void gizmo_bisect_prop_angle_get( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - void *value_p) +static void gizmo_bisect_prop_angle_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoGroup *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - float *value = value_p; - - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); - - float plane_no[4]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no); - normalize_v3(plane_no); - - float plane_no_proj[3]; - project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis); - - if (!is_zero_v3(plane_no_proj)) { - const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis); - value[0] = angle; - } - else { - value[0] = 0.0f; - } + GizmoGroup *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + float *value = value_p; + + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); + + float plane_no[4]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no); + normalize_v3(plane_no); + + float plane_no_proj[3]; + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis); + + if (!is_zero_v3(plane_no_proj)) { + const float angle = -angle_signed_on_axis_v3v3_v3( + plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis); + value[0] = angle; + } + else { + value[0] = 0.0f; + } } -static void gizmo_bisect_prop_angle_set( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - const void *value_p) +static void gizmo_bisect_prop_angle_set(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + const void *value_p) { - GizmoGroup *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - const float *value = value_p; - - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); - - float plane_no[4]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no); - normalize_v3(plane_no); - - float plane_no_proj[3]; - project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis); - - if (!is_zero_v3(plane_no_proj)) { - const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis); - const float angle_delta = angle - angle_compat_rad(value[0], angle); - if (angle_delta != 0.0f) { - float mat[3][3]; - axis_angle_normalized_to_mat3(mat, ggd->data.rotate_axis, angle_delta); - mul_m3_v3(mat, plane_no); - - /* re-normalize - seems acceptable */ - RNA_property_float_set_array(op->ptr, ggd->data.prop_plane_no, plane_no); - - gizmo_bisect_exec(ggd); - } - } + GizmoGroup *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + const float *value = value_p; + + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); + + float plane_no[4]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no); + normalize_v3(plane_no); + + float plane_no_proj[3]; + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis); + + if (!is_zero_v3(plane_no_proj)) { + const float angle = -angle_signed_on_axis_v3v3_v3( + plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis); + const float angle_delta = angle - angle_compat_rad(value[0], angle); + if (angle_delta != 0.0f) { + float mat[3][3]; + axis_angle_normalized_to_mat3(mat, ggd->data.rotate_axis, angle_delta); + mul_m3_v3(mat, plane_no); + + /* re-normalize - seems acceptable */ + RNA_property_float_set_array(op->ptr, ggd->data.prop_plane_no, plane_no); + + gizmo_bisect_exec(ggd); + } + } } static bool gizmo_mesh_bisect_poll(const bContext *C, wmGizmoGroupType *gzgt) { - return ED_gizmo_poll_or_unlink_delayed_from_operator(C, gzgt, "MESH_OT_bisect"); + return ED_gizmo_poll_or_unlink_delayed_from_operator(C, gzgt, "MESH_OT_bisect"); } static void gizmo_mesh_bisect_setup(const bContext *C, wmGizmoGroup *gzgroup) { - wmOperator *op = WM_operator_last_redo(C); - - if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) { - return; - } - - struct GizmoGroup *ggd = MEM_callocN(sizeof(GizmoGroup), __func__); - gzgroup->customdata = ggd; - - const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true); - const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true); - const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); - - ggd->translate_z = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); - ggd->translate_c = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL); - ggd->rotate_c = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); - - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_z->color); - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_c->color); - UI_GetThemeColor3fv(TH_GIZMO_SECONDARY, ggd->rotate_c->color); - - RNA_enum_set(ggd->translate_z->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL); - RNA_enum_set(ggd->translate_c->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D); - - WM_gizmo_set_flag(ggd->translate_c, WM_GIZMO_DRAW_VALUE, true); - WM_gizmo_set_flag(ggd->rotate_c, WM_GIZMO_DRAW_VALUE, true); - - { - ggd->data.context = (bContext *)C; - ggd->data.op = op; - ggd->data.prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co"); - ggd->data.prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no"); - } - - gizmo_mesh_bisect_update_from_op(ggd); - - /* Setup property callbacks */ - { - WM_gizmo_target_property_def_func( - ggd->translate_z, "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_bisect_prop_depth_get, - .value_set_fn = gizmo_bisect_prop_depth_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - - WM_gizmo_target_property_def_func( - ggd->translate_c, "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_bisect_prop_translate_get, - .value_set_fn = gizmo_bisect_prop_translate_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - - WM_gizmo_target_property_def_func( - ggd->rotate_c, "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_bisect_prop_angle_get, - .value_set_fn = gizmo_bisect_prop_angle_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - } + wmOperator *op = WM_operator_last_redo(C); + + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) { + return; + } + + struct GizmoGroup *ggd = MEM_callocN(sizeof(GizmoGroup), __func__); + gzgroup->customdata = ggd; + + const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true); + const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true); + const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); + + ggd->translate_z = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); + ggd->translate_c = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL); + ggd->rotate_c = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); + + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_z->color); + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_c->color); + UI_GetThemeColor3fv(TH_GIZMO_SECONDARY, ggd->rotate_c->color); + + RNA_enum_set(ggd->translate_z->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL); + RNA_enum_set(ggd->translate_c->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D); + + WM_gizmo_set_flag(ggd->translate_c, WM_GIZMO_DRAW_VALUE, true); + WM_gizmo_set_flag(ggd->rotate_c, WM_GIZMO_DRAW_VALUE, true); + + { + ggd->data.context = (bContext *)C; + ggd->data.op = op; + ggd->data.prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co"); + ggd->data.prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no"); + } + + gizmo_mesh_bisect_update_from_op(ggd); + + /* Setup property callbacks */ + { + WM_gizmo_target_property_def_func(ggd->translate_z, + "offset", + &(const struct wmGizmoPropertyFnParams){ + .value_get_fn = gizmo_bisect_prop_depth_get, + .value_set_fn = gizmo_bisect_prop_depth_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + WM_gizmo_target_property_def_func(ggd->translate_c, + "offset", + &(const struct wmGizmoPropertyFnParams){ + .value_get_fn = gizmo_bisect_prop_translate_get, + .value_set_fn = gizmo_bisect_prop_translate_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + WM_gizmo_target_property_def_func(ggd->rotate_c, + "offset", + &(const struct wmGizmoPropertyFnParams){ + .value_get_fn = gizmo_bisect_prop_angle_get, + .value_set_fn = gizmo_bisect_prop_angle_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + } } -static void gizmo_mesh_bisect_draw_prepare( - const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +static void gizmo_mesh_bisect_draw_prepare(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - GizmoGroup *ggd = gzgroup->customdata; - if (ggd->data.op->next) { - ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context); - } - gizmo_mesh_bisect_update_from_op(ggd); + GizmoGroup *ggd = gzgroup->customdata; + if (ggd->data.op->next) { + ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context); + } + gizmo_mesh_bisect_update_from_op(ggd); } static void MESH_GGT_bisect(struct wmGizmoGroupType *gzgt) { - gzgt->name = "Mesh Bisect"; - gzgt->idname = "MESH_GGT_bisect"; + gzgt->name = "Mesh Bisect"; + gzgt->idname = "MESH_GGT_bisect"; - gzgt->flag = WM_GIZMOGROUPTYPE_3D; + gzgt->flag = WM_GIZMOGROUPTYPE_3D; - gzgt->gzmap_params.spaceid = SPACE_VIEW3D; - gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; - gzgt->poll = gizmo_mesh_bisect_poll; - gzgt->setup = gizmo_mesh_bisect_setup; - gzgt->draw_prepare = gizmo_mesh_bisect_draw_prepare; + gzgt->poll = gizmo_mesh_bisect_poll; + gzgt->setup = gizmo_mesh_bisect_setup; + gzgt->draw_prepare = gizmo_mesh_bisect_draw_prepare; } /** \} */ -#endif /* USE_GIZMO */ +#endif /* USE_GIZMO */ diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index f2ba227fd2e..eeda7ec5f2d 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -44,232 +44,225 @@ #include "MEM_guardedalloc.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /* -------------------------------------------------------------------- */ /** \name Extrude Internal Utilities * \{ */ static void edbm_extrude_edge_exclude_mirror( - Object *obedit, BMEditMesh *em, - const char hflag, - BMOperator *op, BMOpSlot *slot_edges_exclude) + Object *obedit, BMEditMesh *em, const char hflag, BMOperator *op, BMOpSlot *slot_edges_exclude) { - BMesh *bm = em->bm; - ModifierData *md; - - /* If a mirror modifier with clipping is on, we need to adjust some - * of the cases above to handle edges on the line of symmetry. - */ - for (md = obedit->modifiers.first; md; md = md->next) { - if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { - MirrorModifierData *mmd = (MirrorModifierData *) md; - - if (mmd->flag & MOD_MIR_CLIPPING) { - BMIter iter; - BMEdge *edge; - - float mtx[4][4]; - if (mmd->mirror_ob) { - float imtx[4][4]; - invert_m4_m4(imtx, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, imtx, obedit->obmat); - } - - BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(edge, hflag) && - BM_edge_is_boundary(edge) && - BM_elem_flag_test(edge->l->f, hflag)) - { - float co1[3], co2[3]; - - copy_v3_v3(co1, edge->v1->co); - copy_v3_v3(co2, edge->v2->co); - - if (mmd->mirror_ob) { - mul_v3_m4v3(co1, mtx, co1); - mul_v3_m4v3(co2, mtx, co2); - } - - if (mmd->flag & MOD_MIR_AXIS_X) { - if ((fabsf(co1[0]) < mmd->tolerance) && - (fabsf(co2[0]) < mmd->tolerance)) - { - BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); - } - } - if (mmd->flag & MOD_MIR_AXIS_Y) { - if ((fabsf(co1[1]) < mmd->tolerance) && - (fabsf(co2[1]) < mmd->tolerance)) - { - BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); - } - } - if (mmd->flag & MOD_MIR_AXIS_Z) { - if ((fabsf(co1[2]) < mmd->tolerance) && - (fabsf(co2[2]) < mmd->tolerance)) - { - BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); - } - } - } - } - } - } - } + BMesh *bm = em->bm; + ModifierData *md; + + /* If a mirror modifier with clipping is on, we need to adjust some + * of the cases above to handle edges on the line of symmetry. + */ + for (md = obedit->modifiers.first; md; md = md->next) { + if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { + MirrorModifierData *mmd = (MirrorModifierData *)md; + + if (mmd->flag & MOD_MIR_CLIPPING) { + BMIter iter; + BMEdge *edge; + + float mtx[4][4]; + if (mmd->mirror_ob) { + float imtx[4][4]; + invert_m4_m4(imtx, mmd->mirror_ob->obmat); + mul_m4_m4m4(mtx, imtx, obedit->obmat); + } + + BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(edge, hflag) && BM_edge_is_boundary(edge) && + BM_elem_flag_test(edge->l->f, hflag)) { + float co1[3], co2[3]; + + copy_v3_v3(co1, edge->v1->co); + copy_v3_v3(co2, edge->v2->co); + + if (mmd->mirror_ob) { + mul_v3_m4v3(co1, mtx, co1); + mul_v3_m4v3(co2, mtx, co2); + } + + if (mmd->flag & MOD_MIR_AXIS_X) { + if ((fabsf(co1[0]) < mmd->tolerance) && (fabsf(co2[0]) < mmd->tolerance)) { + BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); + } + } + if (mmd->flag & MOD_MIR_AXIS_Y) { + if ((fabsf(co1[1]) < mmd->tolerance) && (fabsf(co2[1]) < mmd->tolerance)) { + BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); + } + } + if (mmd->flag & MOD_MIR_AXIS_Z) { + if ((fabsf(co1[2]) < mmd->tolerance) && (fabsf(co2[2]) < mmd->tolerance)) { + BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); + } + } + } + } + } + } + } } /* individual face extrude */ /* will use vertex normals for extrusion directions, so *nor is unaffected */ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag) { - BMOIter siter; - BMIter liter; - BMFace *f; - BMLoop *l; - BMOperator bmop; + BMOIter siter; + BMIter liter; + BMFace *f; + BMLoop *l; + BMOperator bmop; - EDBM_op_init( - em, &bmop, op, - "extrude_discrete_faces faces=%hf use_select_history=%b", - hflag, true); + EDBM_op_init( + em, &bmop, op, "extrude_discrete_faces faces=%hf use_select_history=%b", hflag, true); - /* deselect original verts */ - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + /* deselect original verts */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_op_exec(em->bm, &bmop); + BMO_op_exec(em->bm, &bmop); - BMO_ITER (f, &siter, bmop.slots_out, "faces.out", BM_FACE) { - BM_face_select_set(em->bm, f, true); + BMO_ITER (f, &siter, bmop.slots_out, "faces.out", BM_FACE) { + BM_face_select_set(em->bm, f, true); - /* set face vertex normals to face normal */ - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - copy_v3_v3(l->v->no, f->no); - } - } + /* set face vertex normals to face normal */ + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + copy_v3_v3(l->v->no, f->no); + } + } - if (!EDBM_op_finish(em, &bmop, op, true)) { - return false; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + return false; + } - return true; + return true; } /* extrudes individual edges */ -static bool edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, const bool use_normal_flip) +static bool edbm_extrude_edges_indiv(BMEditMesh *em, + wmOperator *op, + const char hflag, + const bool use_normal_flip) { - BMesh *bm = em->bm; - BMOperator bmop; - - EDBM_op_init( - em, &bmop, op, - "extrude_edge_only edges=%he use_normal_flip=%b use_select_history=%b", - hflag, use_normal_flip, true); - - /* deselect original verts */ - BM_SELECT_HISTORY_BACKUP(bm); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BM_SELECT_HISTORY_RESTORE(bm); - - BMO_op_exec(em->bm, &bmop); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); - - if (!EDBM_op_finish(em, &bmop, op, true)) { - return false; - } - - return true; + BMesh *bm = em->bm; + BMOperator bmop; + + EDBM_op_init(em, + &bmop, + op, + "extrude_edge_only edges=%he use_normal_flip=%b use_select_history=%b", + hflag, + use_normal_flip, + true); + + /* deselect original verts */ + BM_SELECT_HISTORY_BACKUP(bm); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BM_SELECT_HISTORY_RESTORE(bm); + + BMO_op_exec(em->bm, &bmop); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "geom.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + return false; + } + + return true; } /* extrudes individual vertices */ static bool edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag) { - BMOperator bmop; + BMOperator bmop; - EDBM_op_init( - em, &bmop, op, - "extrude_vert_indiv verts=%hv use_select_history=%b", - hflag, true); + EDBM_op_init(em, &bmop, op, "extrude_vert_indiv verts=%hv use_select_history=%b", hflag, true); - /* deselect original verts */ - BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "verts", BM_VERT, BM_ELEM_SELECT, true); + /* deselect original verts */ + BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "verts", BM_VERT, BM_ELEM_SELECT, true); - BMO_op_exec(em->bm, &bmop); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true); + BMO_op_exec(em->bm, &bmop); + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true); - if (!EDBM_op_finish(em, &bmop, op, true)) { - return false; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + return false; + } - return true; + return true; } static char edbm_extrude_htype_from_em_select(BMEditMesh *em) { - char htype = BM_ALL_NOLOOP; - - if (em->selectmode & SCE_SELECT_VERTEX) { - /* pass */ - } - else if (em->selectmode & SCE_SELECT_EDGE) { - htype &= ~BM_VERT; - } - else { - htype &= ~(BM_VERT | BM_EDGE); - } - - if (em->bm->totedgesel == 0) { - htype &= ~(BM_EDGE | BM_FACE); - } - else if (em->bm->totfacesel == 0) { - htype &= ~BM_FACE; - } - - return htype; + char htype = BM_ALL_NOLOOP; + + if (em->selectmode & SCE_SELECT_VERTEX) { + /* pass */ + } + else if (em->selectmode & SCE_SELECT_EDGE) { + htype &= ~BM_VERT; + } + else { + htype &= ~(BM_VERT | BM_EDGE); + } + + if (em->bm->totedgesel == 0) { + htype &= ~(BM_EDGE | BM_FACE); + } + else if (em->bm->totfacesel == 0) { + htype &= ~BM_FACE; + } + + return htype; } -static bool edbm_extrude_ex( - Object *obedit, BMEditMesh *em, - char htype, const char hflag, - const bool use_normal_flip, - const bool use_mirror, - const bool use_select_history) +static bool edbm_extrude_ex(Object *obedit, + BMEditMesh *em, + char htype, + const char hflag, + const bool use_normal_flip, + const bool use_mirror, + const bool use_select_history) { - BMesh *bm = em->bm; - BMOIter siter; - BMOperator extop; - BMElem *ele; + BMesh *bm = em->bm; + BMOIter siter; + BMOperator extop; + BMElem *ele; - /* needed to remove the faces left behind */ - if (htype & BM_FACE) { - htype |= BM_EDGE; - } + /* needed to remove the faces left behind */ + if (htype & BM_FACE) { + htype |= BM_EDGE; + } - BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region"); - BMO_slot_bool_set(extop.slots_in, "use_normal_flip", use_normal_flip); - BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history); - BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, hflag); + BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region"); + BMO_slot_bool_set(extop.slots_in, "use_normal_flip", use_normal_flip); + BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history); + BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, hflag); - if (use_mirror) { - BMOpSlot *slot_edges_exclude; - slot_edges_exclude = BMO_slot_get(extop.slots_in, "edges_exclude"); + if (use_mirror) { + BMOpSlot *slot_edges_exclude; + slot_edges_exclude = BMO_slot_get(extop.slots_in, "edges_exclude"); - edbm_extrude_edge_exclude_mirror(obedit, em, hflag, &extop, slot_edges_exclude); - } + edbm_extrude_edge_exclude_mirror(obedit, em, hflag, &extop, slot_edges_exclude); + } - BM_SELECT_HISTORY_BACKUP(bm); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BM_SELECT_HISTORY_RESTORE(bm); + BM_SELECT_HISTORY_BACKUP(bm); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BM_SELECT_HISTORY_RESTORE(bm); - BMO_op_exec(bm, &extop); + BMO_op_exec(bm, &extop); - BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) { - BM_elem_select_set(bm, ele, true); - } + BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) { + BM_elem_select_set(bm, ele, true); + } - BMO_op_finish(bm, &extop); + BMO_op_finish(bm, &extop); - return true; + return true; } /** \} */ @@ -280,65 +273,63 @@ static bool edbm_extrude_ex( static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - const int steps = RNA_int_get(op->ptr, "steps"); - const float offs = RNA_float_get(op->ptr, "offset"); - float dvec[3], tmat[3][3], bmat[3][3]; - short a; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + const int steps = RNA_int_get(op->ptr, "steps"); + const float offs = RNA_float_get(op->ptr, "offset"); + float dvec[3], tmat[3][3], bmat[3][3]; + short a; - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* dvec */ - normalize_v3_v3_length(dvec, rv3d->persinv[2], offs); + /* dvec */ + normalize_v3_v3_length(dvec, rv3d->persinv[2], offs); - /* base correction */ - copy_m3_m4(bmat, obedit->obmat); - invert_m3_m3(tmat, bmat); - mul_m3_v3(tmat, dvec); + /* base correction */ + copy_m3_m4(bmat, obedit->obmat); + invert_m3_m3(tmat, bmat); + mul_m3_v3(tmat, dvec); - for (a = 0; a < steps; a++) { - edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false); + for (a = 0; a < steps; a++) { + edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false); - BMO_op_callf( - em->bm, BMO_FLAG_DEFAULTS, - "translate vec=%v verts=%hv", - dvec, BM_ELEM_SELECT); - } + BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, "translate vec=%v verts=%hv", dvec, BM_ELEM_SELECT); + } - EDBM_mesh_normals_update(em); + EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - } + EDBM_update_generic(em, true, true); + } - MEM_freeN(objects); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_extrude_repeat(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Extrude Repeat Mesh"; - ot->description = "Extrude selected vertices, edges or faces repeatedly"; - ot->idname = "MESH_OT_extrude_repeat"; + /* identifiers */ + ot->name = "Extrude Repeat Mesh"; + ot->description = "Extrude selected vertices, edges or faces repeatedly"; + ot->idname = "MESH_OT_extrude_repeat"; - /* api callbacks */ - ot->exec = edbm_extrude_repeat_exec; - ot->poll = ED_operator_editmesh_view3d; + /* api callbacks */ + ot->exec = edbm_extrude_repeat_exec; + ot->poll = ED_operator_editmesh_view3d; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f); - RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180); + /* props */ + RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f); + RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180); } /** \} */ @@ -350,95 +341,105 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) /* generic extern called extruder */ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) { - const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip"); - const char htype = edbm_extrude_htype_from_em_select(em); - enum {NONE = 0, ELEM_FLAG, VERT_ONLY, EDGE_ONLY} nr; - bool changed = false; - - if (em->selectmode & SCE_SELECT_VERTEX) { - if (em->bm->totvertsel == 0) nr = NONE; - else if (em->bm->totvertsel == 1) nr = VERT_ONLY; - else if (em->bm->totedgesel == 0) nr = VERT_ONLY; - else nr = ELEM_FLAG; - } - else if (em->selectmode & SCE_SELECT_EDGE) { - if (em->bm->totedgesel == 0) nr = NONE; - else if (em->bm->totfacesel == 0) nr = EDGE_ONLY; - else nr = ELEM_FLAG; - } - else { - if (em->bm->totfacesel == 0) nr = NONE; - else nr = ELEM_FLAG; - } - - switch (nr) { - case NONE: - return false; - case ELEM_FLAG: - changed = edbm_extrude_ex(obedit, em, htype, BM_ELEM_SELECT, use_normal_flip, true, true); - break; - case VERT_ONLY: - changed = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); - break; - case EDGE_ONLY: - changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip); - break; - } - - if (changed) { - return true; - } - else { - BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude"); - return false; - } + const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip"); + const char htype = edbm_extrude_htype_from_em_select(em); + enum { NONE = 0, ELEM_FLAG, VERT_ONLY, EDGE_ONLY } nr; + bool changed = false; + + if (em->selectmode & SCE_SELECT_VERTEX) { + if (em->bm->totvertsel == 0) + nr = NONE; + else if (em->bm->totvertsel == 1) + nr = VERT_ONLY; + else if (em->bm->totedgesel == 0) + nr = VERT_ONLY; + else + nr = ELEM_FLAG; + } + else if (em->selectmode & SCE_SELECT_EDGE) { + if (em->bm->totedgesel == 0) + nr = NONE; + else if (em->bm->totfacesel == 0) + nr = EDGE_ONLY; + else + nr = ELEM_FLAG; + } + else { + if (em->bm->totfacesel == 0) + nr = NONE; + else + nr = ELEM_FLAG; + } + + switch (nr) { + case NONE: + return false; + case ELEM_FLAG: + changed = edbm_extrude_ex(obedit, em, htype, BM_ELEM_SELECT, use_normal_flip, true, true); + break; + case VERT_ONLY: + changed = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); + break; + case EDGE_ONLY: + changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip); + break; + } + + if (changed) { + return true; + } + else { + BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude"); + return false; + } } /* extrude without transform */ static int edbm_extrude_region_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel == 0) { - continue; - } - - if (!edbm_extrude_mesh(obedit, em, op)) { - continue; - } - /* This normally happens when pushing undo but modal operators - * like this one don't push undo data until after modal mode is - * done.*/ - EDBM_mesh_normals_update(em); - - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel == 0) { + continue; + } + + if (!edbm_extrude_mesh(obedit, em, op)) { + continue; + } + /* This normally happens when pushing undo but modal operators + * like this one don't push undo data until after modal mode is + * done.*/ + EDBM_mesh_normals_update(em); + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_extrude_region(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Extrude Region"; - ot->idname = "MESH_OT_extrude_region"; - ot->description = "Extrude region of faces"; + /* identifiers */ + ot->name = "Extrude Region"; + ot->idname = "MESH_OT_extrude_region"; + ot->description = "Extrude region of faces"; - /* api callbacks */ - //ot->invoke = mesh_extrude_region_invoke; - ot->exec = edbm_extrude_region_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + //ot->invoke = mesh_extrude_region_invoke; + ot->exec = edbm_extrude_region_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", ""); - Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); + RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", ""); + Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } /** \} */ @@ -452,46 +453,47 @@ void MESH_OT_extrude_region(wmOperatorType *ot) /* extrude without transform */ static int edbm_extrude_context_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel == 0) { - continue; - } - - edbm_extrude_mesh(obedit, em, op); - /* This normally happens when pushing undo but modal operators - * like this one don't push undo data until after modal mode is - * done.*/ - - EDBM_mesh_normals_update(em); - - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel == 0) { + continue; + } + + edbm_extrude_mesh(obedit, em, op); + /* This normally happens when pushing undo but modal operators + * like this one don't push undo data until after modal mode is + * done.*/ + + EDBM_mesh_normals_update(em); + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_extrude_context(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Extrude Context"; - ot->idname = "MESH_OT_extrude_context"; - ot->description = "Extrude selection"; + /* identifiers */ + ot->name = "Extrude Context"; + ot->idname = "MESH_OT_extrude_context"; + ot->description = "Extrude selection"; - /* api callbacks */ - ot->exec = edbm_extrude_context_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_extrude_context_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", ""); - Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); + RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", ""); + Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } /** \} */ @@ -502,42 +504,43 @@ void MESH_OT_extrude_context(wmOperatorType *ot) static int edbm_extrude_verts_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel == 0) { - continue; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel == 0) { + continue; + } - edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); + edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Extrude Only Vertices"; - ot->idname = "MESH_OT_extrude_verts_indiv"; - ot->description = "Extrude individual vertices only"; + /* identifiers */ + ot->name = "Extrude Only Vertices"; + ot->idname = "MESH_OT_extrude_verts_indiv"; + ot->description = "Extrude individual vertices only"; - /* api callbacks */ - ot->exec = edbm_extrude_verts_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_extrude_verts_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* to give to transform */ - Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); + /* to give to transform */ + Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } /** \} */ @@ -548,44 +551,45 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) static int edbm_extrude_edges_exec(bContext *C, wmOperator *op) { - const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totedgesel == 0) { - continue; - } - - edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip); - - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip"); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totedgesel == 0) { + continue; + } + + edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip); + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Extrude Only Edges"; - ot->idname = "MESH_OT_extrude_edges_indiv"; - ot->description = "Extrude individual edges only"; + /* identifiers */ + ot->name = "Extrude Only Edges"; + ot->idname = "MESH_OT_extrude_edges_indiv"; + ot->description = "Extrude individual edges only"; - /* api callbacks */ - ot->exec = edbm_extrude_edges_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_extrude_edges_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* to give to transform */ - RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", ""); - Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); + /* to give to transform */ + RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", ""); + Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } /** \} */ @@ -596,41 +600,42 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) static int edbm_extrude_faces_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totfacesel == 0) { + continue; + } - edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT); + edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT); - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_extrude_faces_indiv(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Extrude Individual Faces"; - ot->idname = "MESH_OT_extrude_faces_indiv"; - ot->description = "Extrude individual faces only"; + /* identifiers */ + ot->name = "Extrude Individual Faces"; + ot->idname = "MESH_OT_extrude_faces_indiv"; + ot->description = "Extrude individual faces only"; - /* api callbacks */ - ot->exec = edbm_extrude_faces_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_extrude_faces_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); + Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } /** \} */ @@ -643,230 +648,235 @@ void MESH_OT_extrude_faces_indiv(wmOperatorType *ot) static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ViewContext vc; - BMVert *v1; - BMIter iter; - float center[3]; - uint verts_len; - - em_setup_viewcontext(C, &vc); - const Object *object_active = vc.obact; - - const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source"); - const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) && - (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE)); - - /* First calculate the center of transformation. */ - zero_v3(center); - verts_len = 0; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - ED_view3d_viewcontext_init_object(&vc, obedit); - const int local_verts_len = vc.em->bm->totvertsel; - - if (vc.em->bm->totvertsel == 0) { - continue; - } - - float local_center[3]; - zero_v3(local_center); - - BM_ITER_MESH(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) { - add_v3_v3(local_center, v1->co); - } - } - - mul_v3_fl(local_center, 1.0f / (float)local_verts_len); - mul_m4_v3(vc.obedit->obmat, local_center); - mul_v3_fl(local_center, (float)local_verts_len); - - add_v3_v3(center, local_center); - verts_len += local_verts_len; - } - - if (verts_len != 0) { - mul_v3_fl(center, 1.0f / (float)verts_len); - } - - /* Then we process the meshes. */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - ED_view3d_viewcontext_init_object(&vc, obedit); - - if (verts_len != 0) { - if (vc.em->bm->totvertsel == 0) { - continue; - } - } - else if (obedit != object_active) { - continue; - } - - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); - ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - - float local_center[3]; - mul_v3_m4v3(local_center, vc.obedit->imat, center); - - /* call extrude? */ - if (verts_len != 0) { - const char extrude_htype = edbm_extrude_htype_from_em_select(vc.em); - BMEdge *eed; - float mat[3][3]; - float vec[3], ofs[3]; - float nor[3] = { 0.0, 0.0, 0.0 }; - - /* 2D normal calc */ - const float mval_f[2] = { (float)event->mval[0], - (float)event->mval[1] }; - - /* check for edges that are half selected, use for rotation */ - bool done = false; - BM_ITER_MESH(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - float co1[2], co2[2]; - - if ((ED_view3d_project_float_object(vc.ar, eed->v1->co, co1, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) && - (ED_view3d_project_float_object(vc.ar, eed->v2->co, co2, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) - { - /* 2D rotate by 90d while adding. - * (x, y) = (y, -x) - * - * accumulate the screenspace normal in 2D, - * with screenspace edge length weighting the result. */ - if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) { - nor[0] += (co1[1] - co2[1]); - nor[1] += -(co1[0] - co2[0]); - } - else { - nor[0] += (co2[1] - co1[1]); - nor[1] += -(co2[0] - co1[0]); - } - done = true; - } - } - } - - if (done) { - float view_vec[3], cross[3]; - - /* convert the 2D normal into 3D */ - mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ - mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ - - /* correct the normal to be aligned on the view plane */ - mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]); - cross_v3_v3v3(cross, nor, view_vec); - cross_v3_v3v3(nor, view_vec, cross); - normalize_v3(nor); - } - - /* center */ - copy_v3_v3(ofs, local_center); - - mul_m4_v3(vc.obedit->obmat, ofs); /* view space */ - ED_view3d_win_to_3d_int(vc.v3d, vc.ar, ofs, event->mval, ofs); - mul_m4_v3(vc.obedit->imat, ofs); // back in object space - - sub_v3_v3(ofs, local_center); - - /* calculate rotation */ - unit_m3(mat); - if (done) { - float angle; - - normalize_v3_v3(vec, ofs); - - angle = angle_normalized_v3v3(vec, nor); - - if (angle != 0.0f) { - float axis[3]; - - cross_v3_v3v3(axis, nor, vec); - - /* halve the rotation if its applied twice */ - if (rot_src) { - angle *= 0.5f; - } - - axis_angle_to_mat3(mat, axis, angle); - } - } - - if (rot_src) { - EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", - BM_ELEM_SELECT, local_center, mat); - - /* also project the source, for retopo workflow */ - if (use_proj) { - EDBM_project_snap_verts(C, vc.ar, vc.em); - } - } - - edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, true, true); - EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", - BM_ELEM_SELECT, local_center, mat); - EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v", - BM_ELEM_SELECT, ofs); - } - else { - /* This only runs for the active object. */ - const float *cursor = vc.scene->cursor.location; - BMOperator bmop; - BMOIter oiter; - - copy_v3_v3(local_center, cursor); - ED_view3d_win_to_3d_int(vc.v3d, vc.ar, local_center, event->mval, local_center); - - mul_m4_v3(vc.obedit->imat, local_center); // back in object space - - EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", local_center); - BMO_op_exec(vc.em->bm, &bmop); - - BMO_ITER(v1, &oiter, bmop.slots_out, "vert.out", BM_VERT) { - BM_vert_select_set(vc.em->bm, v1, true); - } - - if (!EDBM_op_finish(vc.em, &bmop, op, true)) { - continue; - } - } - - if (use_proj) { - EDBM_project_snap_verts(C, vc.ar, vc.em); - } - - /* This normally happens when pushing undo but modal operators - * like this one don't push undo data until after modal mode is - * done. */ - EDBM_mesh_normals_update(vc.em); - - EDBM_update_generic(vc.em, true, true); - } - MEM_freeN(objects); + ViewContext vc; + BMVert *v1; + BMIter iter; + float center[3]; + uint verts_len; + + em_setup_viewcontext(C, &vc); + const Object *object_active = vc.obact; + + const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source"); + const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) && + (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE)); + + /* First calculate the center of transformation. */ + zero_v3(center); + verts_len = 0; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + vc.view_layer, vc.v3d, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ED_view3d_viewcontext_init_object(&vc, obedit); + const int local_verts_len = vc.em->bm->totvertsel; + + if (vc.em->bm->totvertsel == 0) { + continue; + } + + float local_center[3]; + zero_v3(local_center); + + BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) { + add_v3_v3(local_center, v1->co); + } + } + + mul_v3_fl(local_center, 1.0f / (float)local_verts_len); + mul_m4_v3(vc.obedit->obmat, local_center); + mul_v3_fl(local_center, (float)local_verts_len); + + add_v3_v3(center, local_center); + verts_len += local_verts_len; + } + + if (verts_len != 0) { + mul_v3_fl(center, 1.0f / (float)verts_len); + } + + /* Then we process the meshes. */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ED_view3d_viewcontext_init_object(&vc, obedit); + + if (verts_len != 0) { + if (vc.em->bm->totvertsel == 0) { + continue; + } + } + else if (obedit != object_active) { + continue; + } + + invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); + + float local_center[3]; + mul_v3_m4v3(local_center, vc.obedit->imat, center); + + /* call extrude? */ + if (verts_len != 0) { + const char extrude_htype = edbm_extrude_htype_from_em_select(vc.em); + BMEdge *eed; + float mat[3][3]; + float vec[3], ofs[3]; + float nor[3] = {0.0, 0.0, 0.0}; + + /* 2D normal calc */ + const float mval_f[2] = {(float)event->mval[0], (float)event->mval[1]}; + + /* check for edges that are half selected, use for rotation */ + bool done = false; + BM_ITER_MESH (eed, &iter, vc.em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + float co1[2], co2[2]; + + if ((ED_view3d_project_float_object(vc.ar, eed->v1->co, co1, V3D_PROJ_TEST_NOP) == + V3D_PROJ_RET_OK) && + (ED_view3d_project_float_object(vc.ar, eed->v2->co, co2, V3D_PROJ_TEST_NOP) == + V3D_PROJ_RET_OK)) { + /* 2D rotate by 90d while adding. + * (x, y) = (y, -x) + * + * accumulate the screenspace normal in 2D, + * with screenspace edge length weighting the result. */ + if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) { + nor[0] += (co1[1] - co2[1]); + nor[1] += -(co1[0] - co2[0]); + } + else { + nor[0] += (co2[1] - co1[1]); + nor[1] += -(co2[0] - co1[0]); + } + done = true; + } + } + } + + if (done) { + float view_vec[3], cross[3]; + + /* convert the 2D normal into 3D */ + mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ + mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ + + /* correct the normal to be aligned on the view plane */ + mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]); + cross_v3_v3v3(cross, nor, view_vec); + cross_v3_v3v3(nor, view_vec, cross); + normalize_v3(nor); + } + + /* center */ + copy_v3_v3(ofs, local_center); + + mul_m4_v3(vc.obedit->obmat, ofs); /* view space */ + ED_view3d_win_to_3d_int(vc.v3d, vc.ar, ofs, event->mval, ofs); + mul_m4_v3(vc.obedit->imat, ofs); // back in object space + + sub_v3_v3(ofs, local_center); + + /* calculate rotation */ + unit_m3(mat); + if (done) { + float angle; + + normalize_v3_v3(vec, ofs); + + angle = angle_normalized_v3v3(vec, nor); + + if (angle != 0.0f) { + float axis[3]; + + cross_v3_v3v3(axis, nor, vec); + + /* halve the rotation if its applied twice */ + if (rot_src) { + angle *= 0.5f; + } + + axis_angle_to_mat3(mat, axis, angle); + } + } + + if (rot_src) { + EDBM_op_callf( + vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, local_center, mat); + + /* also project the source, for retopo workflow */ + if (use_proj) { + EDBM_project_snap_verts(C, vc.ar, vc.em); + } + } + + edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, true, true); + EDBM_op_callf( + vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, local_center, mat); + EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v", BM_ELEM_SELECT, ofs); + } + else { + /* This only runs for the active object. */ + const float *cursor = vc.scene->cursor.location; + BMOperator bmop; + BMOIter oiter; + + copy_v3_v3(local_center, cursor); + ED_view3d_win_to_3d_int(vc.v3d, vc.ar, local_center, event->mval, local_center); + + mul_m4_v3(vc.obedit->imat, local_center); // back in object space + + EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", local_center); + BMO_op_exec(vc.em->bm, &bmop); + + BMO_ITER (v1, &oiter, bmop.slots_out, "vert.out", BM_VERT) { + BM_vert_select_set(vc.em->bm, v1, true); + } + + if (!EDBM_op_finish(vc.em, &bmop, op, true)) { + continue; + } + } + + if (use_proj) { + EDBM_project_snap_verts(C, vc.ar, vc.em); + } + + /* This normally happens when pushing undo but modal operators + * like this one don't push undo data until after modal mode is + * done. */ + EDBM_mesh_normals_update(vc.em); + + EDBM_update_generic(vc.em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Duplicate or Extrude to Cursor"; - ot->idname = "MESH_OT_dupli_extrude_cursor"; - ot->description = "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor"; - - /* api callbacks */ - ot->invoke = edbm_dupli_extrude_cursor_invoke; - ot->poll = ED_operator_editmesh_region_view3d; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "rotate_source", true, "Rotate Source", "Rotate initial selection giving better shape"); + /* identifiers */ + ot->name = "Duplicate or Extrude to Cursor"; + ot->idname = "MESH_OT_dupli_extrude_cursor"; + ot->description = + "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor"; + + /* api callbacks */ + ot->invoke = edbm_dupli_extrude_cursor_invoke; + ot->poll = ED_operator_editmesh_region_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, + "rotate_source", + true, + "Rotate Source", + "Rotate initial selection giving better shape"); } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_extrude_screw.c b/source/blender/editors/mesh/editmesh_extrude_screw.c index 4b3a93a2111..c9422545c7b 100644 --- a/source/blender/editors/mesh/editmesh_extrude_screw.c +++ b/source/blender/editors/mesh/editmesh_extrude_screw.c @@ -41,7 +41,7 @@ #include "ED_screen.h" #include "ED_view3d.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /* -------------------------------------------------------------------- */ /** \name Screw Operator @@ -49,158 +49,178 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) { - BMEdge *eed; - BMVert *eve, *v1, *v2; - BMIter iter, eiter; - float dvec[3], nor[3], cent[3], axis[3], v1_co_global[3], v2_co_global[3]; - int steps, turns; - int valence; - uint objects_empty_len = 0; - uint failed_axis_len = 0; - uint failed_vertices_len = 0; - - turns = RNA_int_get(op->ptr, "turns"); - steps = RNA_int_get(op->ptr, "steps"); - RNA_float_get_array(op->ptr, "center", cent); - RNA_float_get_array(op->ptr, "axis", axis); - - uint objects_len = 0; - ViewLayer *view_layer = CTX_data_view_layer(C); - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if (bm->totvertsel < 2) { - if (bm->totvertsel == 0) { - objects_empty_len++; - } - continue; - } - - if (is_zero_v3(axis)) { - failed_axis_len++; - continue; - } - - /* find two vertices with valence count == 1, more or less is wrong */ - v1 = NULL; - v2 = NULL; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - valence = 0; - BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - valence++; - } - } - - if (valence == 1) { - if (v1 == NULL) { - v1 = eve; - } - else if (v2 == NULL) { - v2 = eve; - } - else { - v1 = NULL; - break; - } - } - } - - if (v1 == NULL || v2 == NULL) { - failed_vertices_len++; - continue; - } - - copy_v3_v3(nor, obedit->obmat[2]); - - /* calculate dvec */ - mul_v3_m4v3(v1_co_global, obedit->obmat, v1->co); - mul_v3_m4v3(v2_co_global, obedit->obmat, v2->co); - sub_v3_v3v3(dvec, v1_co_global, v2_co_global); - mul_v3_fl(dvec, 1.0f / steps); - - if (dot_v3v3(nor, dvec) > 0.0f) - negate_v3(dvec); - - BMOperator spinop; - if (!EDBM_op_init(em, &spinop, op, - "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 use_duplicate=%b", - BM_ELEM_SELECT, cent, axis, dvec, turns * steps, DEG2RADF(360.0f * turns), obedit->obmat, false)) - { - continue; - } - - BMO_op_exec(bm, &spinop); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); - - if (!EDBM_op_finish(em, &spinop, op, true)) { - continue; - } - - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - - if (failed_axis_len == objects_len - objects_empty_len) { - BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis"); - } - else if (failed_vertices_len == objects_len - objects_empty_len) { - BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too"); - } - - return OPERATOR_FINISHED; + BMEdge *eed; + BMVert *eve, *v1, *v2; + BMIter iter, eiter; + float dvec[3], nor[3], cent[3], axis[3], v1_co_global[3], v2_co_global[3]; + int steps, turns; + int valence; + uint objects_empty_len = 0; + uint failed_axis_len = 0; + uint failed_vertices_len = 0; + + turns = RNA_int_get(op->ptr, "turns"); + steps = RNA_int_get(op->ptr, "steps"); + RNA_float_get_array(op->ptr, "center", cent); + RNA_float_get_array(op->ptr, "axis", axis); + + uint objects_len = 0; + ViewLayer *view_layer = CTX_data_view_layer(C); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if (bm->totvertsel < 2) { + if (bm->totvertsel == 0) { + objects_empty_len++; + } + continue; + } + + if (is_zero_v3(axis)) { + failed_axis_len++; + continue; + } + + /* find two vertices with valence count == 1, more or less is wrong */ + v1 = NULL; + v2 = NULL; + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + valence = 0; + BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + valence++; + } + } + + if (valence == 1) { + if (v1 == NULL) { + v1 = eve; + } + else if (v2 == NULL) { + v2 = eve; + } + else { + v1 = NULL; + break; + } + } + } + + if (v1 == NULL || v2 == NULL) { + failed_vertices_len++; + continue; + } + + copy_v3_v3(nor, obedit->obmat[2]); + + /* calculate dvec */ + mul_v3_m4v3(v1_co_global, obedit->obmat, v1->co); + mul_v3_m4v3(v2_co_global, obedit->obmat, v2->co); + sub_v3_v3v3(dvec, v1_co_global, v2_co_global); + mul_v3_fl(dvec, 1.0f / steps); + + if (dot_v3v3(nor, dvec) > 0.0f) + negate_v3(dvec); + + BMOperator spinop; + if (!EDBM_op_init( + em, + &spinop, + op, + "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 use_duplicate=%b", + BM_ELEM_SELECT, + cent, + axis, + dvec, + turns * steps, + DEG2RADF(360.0f * turns), + obedit->obmat, + false)) { + continue; + } + + BMO_op_exec(bm, &spinop); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable( + bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + + if (!EDBM_op_finish(em, &spinop, op, true)) { + continue; + } + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + + if (failed_axis_len == objects_len - objects_empty_len) { + BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis"); + } + else if (failed_vertices_len == objects_len - objects_empty_len) { + BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too"); + } + + return OPERATOR_FINISHED; } /* get center and axis, in global coords */ static int edbm_screw_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Scene *scene = CTX_data_scene(C); - RegionView3D *rv3d = ED_view3d_context_rv3d(C); - - PropertyRNA *prop; - prop = RNA_struct_find_property(op->ptr, "center"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_set_array(op->ptr, prop, scene->cursor.location); - } - if (rv3d) { - prop = RNA_struct_find_property(op->ptr, "axis"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[1]); - } - } - - return edbm_screw_exec(C, op); + Scene *scene = CTX_data_scene(C); + RegionView3D *rv3d = ED_view3d_context_rv3d(C); + + PropertyRNA *prop; + prop = RNA_struct_find_property(op->ptr, "center"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set_array(op->ptr, prop, scene->cursor.location); + } + if (rv3d) { + prop = RNA_struct_find_property(op->ptr, "axis"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[1]); + } + } + + return edbm_screw_exec(C, op); } void MESH_OT_screw(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Screw"; - ot->description = "Extrude selected vertices in screw-shaped rotation around the cursor in indicated viewport"; - ot->idname = "MESH_OT_screw"; - - /* api callbacks */ - ot->invoke = edbm_screw_invoke; - ot->exec = edbm_screw_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "steps", 9, 1, 100000, "Steps", "Steps", 3, 256); - RNA_def_int(ot->srna, "turns", 1, 1, 100000, "Turns", "Turns", 1, 256); - - RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -1e12f, 1e12f, - "Center", "Center in global view space", -1e4f, 1e4f); - RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, - "Axis", "Axis in global view space", -1.0f, 1.0f); + /* identifiers */ + ot->name = "Screw"; + ot->description = + "Extrude selected vertices in screw-shaped rotation around the cursor in indicated viewport"; + ot->idname = "MESH_OT_screw"; + + /* api callbacks */ + ot->invoke = edbm_screw_invoke; + ot->exec = edbm_screw_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "steps", 9, 1, 100000, "Steps", "Steps", 3, 256); + RNA_def_int(ot->srna, "turns", 1, 1, 100000, "Turns", "Turns", 1, 256); + + RNA_def_float_vector_xyz(ot->srna, + "center", + 3, + NULL, + -1e12f, + 1e12f, + "Center", + "Center in global view space", + -1e4f, + 1e4f); + RNA_def_float_vector( + ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f); } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index a098751fd21..c546e9b866f 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -45,7 +45,7 @@ #include "MEM_guardedalloc.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ #define USE_GIZMO @@ -55,158 +55,185 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - float cent[3], axis[3]; - float d[3] = {0.0f, 0.0f, 0.0f}; - - RNA_float_get_array(op->ptr, "center", cent); - RNA_float_get_array(op->ptr, "axis", axis); - const int steps = RNA_int_get(op->ptr, "steps"); - const float angle = RNA_float_get(op->ptr, "angle"); - const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip"); - const bool dupli = RNA_boolean_get(op->ptr, "dupli"); - const bool use_auto_merge = ( - RNA_boolean_get(op->ptr, "use_auto_merge") && - (dupli == false) && - (steps >= 3) && - fabsf((fabsf(angle) - (float)(M_PI * 2))) <= 1e-6f); - - if (is_zero_v3(axis)) { - BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis"); - return OPERATOR_CANCELLED; - } - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMOperator spinop; - - /* keep the values in worldspace since we're passing the obmat */ - if (!EDBM_op_init( - em, &spinop, op, - "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 " - "use_normal_flip=%b use_duplicate=%b use_merge=%b", - BM_ELEM_SELECT, cent, axis, d, steps, -angle, obedit->obmat, - use_normal_flip, dupli, use_auto_merge)) - { - continue; - } - BMO_op_exec(bm, &spinop); - if (use_auto_merge == false) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); - } - if (!EDBM_op_finish(em, &spinop, op, true)) { - continue; - } - - EDBM_update_generic(em, true, true); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + float cent[3], axis[3]; + float d[3] = {0.0f, 0.0f, 0.0f}; + + RNA_float_get_array(op->ptr, "center", cent); + RNA_float_get_array(op->ptr, "axis", axis); + const int steps = RNA_int_get(op->ptr, "steps"); + const float angle = RNA_float_get(op->ptr, "angle"); + const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip"); + const bool dupli = RNA_boolean_get(op->ptr, "dupli"); + const bool use_auto_merge = (RNA_boolean_get(op->ptr, "use_auto_merge") && (dupli == false) && + (steps >= 3) && fabsf((fabsf(angle) - (float)(M_PI * 2))) <= 1e-6f); + + if (is_zero_v3(axis)) { + BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis"); + return OPERATOR_CANCELLED; + } + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMOperator spinop; + + /* keep the values in worldspace since we're passing the obmat */ + if (!EDBM_op_init(em, + &spinop, + op, + "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 " + "use_normal_flip=%b use_duplicate=%b use_merge=%b", + BM_ELEM_SELECT, + cent, + axis, + d, + steps, + -angle, + obedit->obmat, + use_normal_flip, + dupli, + use_auto_merge)) { + continue; + } + BMO_op_exec(bm, &spinop); + if (use_auto_merge == false) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable( + bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + } + if (!EDBM_op_finish(em, &spinop, op, true)) { + continue; + } + + EDBM_update_generic(em, true, true); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } /* get center and axis, in global coords */ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = ED_view3d_context_rv3d(C); - - PropertyRNA *prop; - prop = RNA_struct_find_property(op->ptr, "center"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_set_array(op->ptr, prop, scene->cursor.location); - } - if (rv3d) { - prop = RNA_struct_find_property(op->ptr, "axis"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[2]); - } - } - + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ED_view3d_context_rv3d(C); + + PropertyRNA *prop; + prop = RNA_struct_find_property(op->ptr, "center"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set_array(op->ptr, prop, scene->cursor.location); + } + if (rv3d) { + prop = RNA_struct_find_property(op->ptr, "axis"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[2]); + } + } #ifdef USE_GIZMO - /* Start with zero angle, drag out the value. */ - prop = RNA_struct_find_property(op->ptr, "angle"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_set(op->ptr, prop, 0.0f); - } + /* Start with zero angle, drag out the value. */ + prop = RNA_struct_find_property(op->ptr, "angle"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set(op->ptr, prop, 0.0f); + } #endif - int ret = edbm_spin_exec(C, op); + int ret = edbm_spin_exec(C, op); #ifdef USE_GIZMO - if (ret & OPERATOR_FINISHED) { - /* Setup gizmos */ - if (v3d && ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0)) { - wmGizmoGroupType *gzgt = WM_gizmogrouptype_find("MESH_GGT_spin_redo", false); - if (!WM_gizmo_group_type_ensure_ptr(gzgt)) { - struct Main *bmain = CTX_data_main(C); - WM_gizmo_group_type_reinit_ptr(bmain, gzgt); - } - } - } + if (ret & OPERATOR_FINISHED) { + /* Setup gizmos */ + if (v3d && ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0)) { + wmGizmoGroupType *gzgt = WM_gizmogrouptype_find("MESH_GGT_spin_redo", false); + if (!WM_gizmo_group_type_ensure_ptr(gzgt)) { + struct Main *bmain = CTX_data_main(C); + WM_gizmo_group_type_reinit_ptr(bmain, gzgt); + } + } + } #endif - return ret; + return ret; } -static bool edbm_spin_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) +static bool edbm_spin_poll_property(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) { - const char *prop_id = RNA_property_identifier(prop); - const bool dupli = RNA_boolean_get(op->ptr, "dupli"); - - if (dupli) { - if (STREQ(prop_id, "use_auto_merge") || - STREQ(prop_id, "use_normal_flip")) - { - return false; - } - } - return true; + const char *prop_id = RNA_property_identifier(prop); + const bool dupli = RNA_boolean_get(op->ptr, "dupli"); + + if (dupli) { + if (STREQ(prop_id, "use_auto_merge") || STREQ(prop_id, "use_normal_flip")) { + return false; + } + } + return true; } void MESH_OT_spin(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Spin"; - ot->description = "Extrude selected vertices in a circle around the cursor in indicated viewport"; - ot->idname = "MESH_OT_spin"; - - /* api callbacks */ - ot->invoke = edbm_spin_invoke; - ot->exec = edbm_spin_exec; - ot->poll = ED_operator_editmesh; - ot->poll_property = edbm_spin_poll_property; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000); - RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates"); - prop = RNA_def_float(ot->srna, "angle", DEG2RADF(90.0f), -1e12f, 1e12f, "Angle", "Rotation for each step", - DEG2RADF(-360.0f), DEG2RADF(360.0f)); - RNA_def_property_subtype(prop, PROP_ANGLE); - RNA_def_boolean(ot->srna, "use_auto_merge", true, "Auto Merge", "Merge first/last when the angle is a full revolution"); - RNA_def_boolean(ot->srna, "use_normal_flip", 0, "Flip Normals", ""); - - RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -1e12f, 1e12f, - "Center", "Center in global view space", -1e4f, 1e4f); - RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f); - - WM_gizmogrouptype_append(MESH_GGT_spin); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Spin"; + ot->description = + "Extrude selected vertices in a circle around the cursor in indicated viewport"; + ot->idname = "MESH_OT_spin"; + + /* api callbacks */ + ot->invoke = edbm_spin_invoke; + ot->exec = edbm_spin_exec; + ot->poll = ED_operator_editmesh; + ot->poll_property = edbm_spin_poll_property; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000); + RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates"); + prop = RNA_def_float(ot->srna, + "angle", + DEG2RADF(90.0f), + -1e12f, + 1e12f, + "Angle", + "Rotation for each step", + DEG2RADF(-360.0f), + DEG2RADF(360.0f)); + RNA_def_property_subtype(prop, PROP_ANGLE); + RNA_def_boolean(ot->srna, + "use_auto_merge", + true, + "Auto Merge", + "Merge first/last when the angle is a full revolution"); + RNA_def_boolean(ot->srna, "use_normal_flip", 0, "Flip Normals", ""); + + RNA_def_float_vector_xyz(ot->srna, + "center", + 3, + NULL, + -1e12f, + 1e12f, + "Center", + "Center in global view space", + -1e4f, + 1e4f); + RNA_def_float_vector( + ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f); + + WM_gizmogrouptype_append(MESH_GGT_spin); #ifdef USE_GIZMO - WM_gizmogrouptype_append(MESH_GGT_spin_redo); + WM_gizmogrouptype_append(MESH_GGT_spin_redo); #endif } diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c index 1ff7d835aad..85be7d902ad 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c @@ -40,7 +40,7 @@ #include "MEM_guardedalloc.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ #include "ED_transform.h" @@ -67,32 +67,32 @@ static const float dial_angle_partial_margin = 0.92f; * \{ */ typedef struct GizmoGroupData_SpinInit { - struct { - wmGizmo *xyz_view[4]; - wmGizmo *icon_button[3][2]; - } gizmos; - - /* Only for view orientation. */ - struct { - float viewinv_m3[3][3]; - } prev; - - /* We could store more vars here! */ - struct { - wmOperatorType *ot_spin; - PropertyRNA *gzgt_axis_prop; - float orient_mat[3][3]; + struct { + wmGizmo *xyz_view[4]; + wmGizmo *icon_button[3][2]; + } gizmos; + + /* Only for view orientation. */ + struct { + float viewinv_m3[3][3]; + } prev; + + /* We could store more vars here! */ + struct { + wmOperatorType *ot_spin; + PropertyRNA *gzgt_axis_prop; + float orient_mat[3][3]; #ifdef USE_SELECT_CENTER - float select_center[3]; - float select_center_ortho_axis[3][3]; - bool use_select_center; + float select_center[3]; + float select_center_ortho_axis[3][3]; + bool use_select_center; #endif - } data; + } data; - /* Store data for invoke. */ - struct { - int ortho_axis_active; - } invoke; + /* Store data for invoke. */ + struct { + int ortho_axis_active; + } invoke; } GizmoGroupData_SpinInit; @@ -103,374 +103,376 @@ typedef struct GizmoGroupData_SpinInit { #define INIT_SCALE_BUTTON 0.15f static const uchar shape_plus[] = { - 0x5f, 0xfb, 0x40, 0xee, 0x25, 0xda, 0x11, 0xbf, 0x4, 0xa0, 0x0, 0x80, 0x4, 0x5f, 0x11, - 0x40, 0x25, 0x25, 0x40, 0x11, 0x5f, 0x4, 0x7f, 0x0, 0xa0, 0x4, 0xbf, 0x11, 0xda, 0x25, - 0xee, 0x40, 0xfb, 0x5f, 0xff, 0x7f, 0xfb, 0xa0, 0xee, 0xbf, 0xda, 0xda, 0xbf, 0xee, - 0xa0, 0xfb, 0x80, 0xff, 0x6e, 0xd7, 0x92, 0xd7, 0x92, 0x90, 0xd8, 0x90, 0xd8, 0x6d, - 0x92, 0x6d, 0x92, 0x27, 0x6e, 0x27, 0x6e, 0x6d, 0x28, 0x6d, 0x28, 0x90, 0x6e, - 0x90, 0x6e, 0xd7, 0x80, 0xff, 0x5f, 0xfb, 0x5f, 0xfb, + 0x5f, 0xfb, 0x40, 0xee, 0x25, 0xda, 0x11, 0xbf, 0x4, 0xa0, 0x0, 0x80, 0x4, 0x5f, 0x11, 0x40, + 0x25, 0x25, 0x40, 0x11, 0x5f, 0x4, 0x7f, 0x0, 0xa0, 0x4, 0xbf, 0x11, 0xda, 0x25, 0xee, 0x40, + 0xfb, 0x5f, 0xff, 0x7f, 0xfb, 0xa0, 0xee, 0xbf, 0xda, 0xda, 0xbf, 0xee, 0xa0, 0xfb, 0x80, 0xff, + 0x6e, 0xd7, 0x92, 0xd7, 0x92, 0x90, 0xd8, 0x90, 0xd8, 0x6d, 0x92, 0x6d, 0x92, 0x27, 0x6e, 0x27, + 0x6e, 0x6d, 0x28, 0x6d, 0x28, 0x90, 0x6e, 0x90, 0x6e, 0xd7, 0x80, 0xff, 0x5f, 0xfb, 0x5f, 0xfb, }; static void gizmo_mesh_spin_init_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - /* alpha values for normal/highlighted states */ - const float alpha = 0.6f; - const float alpha_hi = 1.0f; - const float scale_base = INIT_SCALE_BASE; - const float scale_button = INIT_SCALE_BUTTON; - - GizmoGroupData_SpinInit *ggd = MEM_callocN(sizeof(*ggd), __func__); - gzgroup->customdata = ggd; - const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); - const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - wmGizmo *gz = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL); - PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "shape"); - RNA_property_string_set_bytes( - gz->ptr, prop, - (const char *)shape_plus, ARRAY_SIZE(shape_plus)); - - float color[4]; - UI_GetThemeColor3fv(TH_AXIS_X + i, color); - color[3] = alpha; - WM_gizmo_set_color(gz, color); - - WM_gizmo_set_scale(gz, scale_button); - gz->color[3] = 0.6f; - - gz->flag |= WM_GIZMO_DRAW_OFFSET_SCALE | WM_GIZMO_OPERATOR_TOOL_INIT; - - ggd->gizmos.icon_button[i][j] = gz; - } - } - - for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.xyz_view); i++) { - wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); - WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE | WM_GIZMO_HIDDEN_SELECT, true); - ggd->gizmos.xyz_view[i] = gz; - } - - for (int i = 0; i < 3; i++) { - wmGizmo *gz = ggd->gizmos.xyz_view[i]; + /* alpha values for normal/highlighted states */ + const float alpha = 0.6f; + const float alpha_hi = 1.0f; + const float scale_base = INIT_SCALE_BASE; + const float scale_button = INIT_SCALE_BUTTON; + + GizmoGroupData_SpinInit *ggd = MEM_callocN(sizeof(*ggd), __func__); + gzgroup->customdata = ggd; + const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); + const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL); + PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "shape"); + RNA_property_string_set_bytes( + gz->ptr, prop, (const char *)shape_plus, ARRAY_SIZE(shape_plus)); + + float color[4]; + UI_GetThemeColor3fv(TH_AXIS_X + i, color); + color[3] = alpha; + WM_gizmo_set_color(gz, color); + + WM_gizmo_set_scale(gz, scale_button); + gz->color[3] = 0.6f; + + gz->flag |= WM_GIZMO_DRAW_OFFSET_SCALE | WM_GIZMO_OPERATOR_TOOL_INIT; + + ggd->gizmos.icon_button[i][j] = gz; + } + } + + for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.xyz_view); i++) { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE | WM_GIZMO_HIDDEN_SELECT, true); + ggd->gizmos.xyz_view[i] = gz; + } + + for (int i = 0; i < 3; i++) { + wmGizmo *gz = ggd->gizmos.xyz_view[i]; #ifndef USE_DIAL_HOVER - RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_CLIP); + RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_CLIP); #endif - WM_gizmo_set_line_width(gz, 2.0f); - float color[4]; - UI_GetThemeColor3fv(TH_AXIS_X + i, color); - color[3] = alpha; - WM_gizmo_set_color(gz, color); - color[3] = alpha_hi; - WM_gizmo_set_color_highlight(gz, color); - WM_gizmo_set_scale(gz, INIT_SCALE_BASE); - RNA_float_set(gz->ptr, "arc_partial_angle", (M_PI * 2) - (dial_angle_partial * dial_angle_partial_margin)); - } - - { - wmGizmo *gz = ggd->gizmos.xyz_view[3]; - WM_gizmo_set_line_width(gz, 2.0f); - float color[4]; - copy_v3_fl(color, 1.0f); - color[3] = alpha; - WM_gizmo_set_color(gz, color); - color[3] = alpha_hi; - WM_gizmo_set_color_highlight(gz, color); - WM_gizmo_set_scale(gz, scale_base); - } - + WM_gizmo_set_line_width(gz, 2.0f); + float color[4]; + UI_GetThemeColor3fv(TH_AXIS_X + i, color); + color[3] = alpha; + WM_gizmo_set_color(gz, color); + color[3] = alpha_hi; + WM_gizmo_set_color_highlight(gz, color); + WM_gizmo_set_scale(gz, INIT_SCALE_BASE); + RNA_float_set(gz->ptr, + "arc_partial_angle", + (M_PI * 2) - (dial_angle_partial * dial_angle_partial_margin)); + } + + { + wmGizmo *gz = ggd->gizmos.xyz_view[3]; + WM_gizmo_set_line_width(gz, 2.0f); + float color[4]; + copy_v3_fl(color, 1.0f); + color[3] = alpha; + WM_gizmo_set_color(gz, color); + color[3] = alpha_hi; + WM_gizmo_set_color_highlight(gz, color); + WM_gizmo_set_scale(gz, scale_base); + } #ifdef USE_DIAL_HOVER - for (int i = 0; i < 4; i++) { - wmGizmo *gz = ggd->gizmos.xyz_view[i]; - WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); - } + for (int i = 0; i < 4; i++) { + wmGizmo *gz = ggd->gizmos.xyz_view[i]; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); + } #endif - ggd->data.ot_spin = WM_operatortype_find("MESH_OT_spin", true); - ggd->data.gzgt_axis_prop = RNA_struct_type_find_property(gzgroup->type->srna, "axis"); + ggd->data.ot_spin = WM_operatortype_find("MESH_OT_spin", true); + ggd->data.gzgt_axis_prop = RNA_struct_type_find_property(gzgroup->type->srna, "axis"); } static void gizmo_mesh_spin_init_refresh(const bContext *C, wmGizmoGroup *gzgroup); -static void gizmo_mesh_spin_init_refresh_axis_orientation( - wmGizmoGroup *gzgroup, - int axis_index, const float axis_vec[3], const float axis_tan[3]) +static void gizmo_mesh_spin_init_refresh_axis_orientation(wmGizmoGroup *gzgroup, + int axis_index, + const float axis_vec[3], + const float axis_tan[3]) { - GizmoGroupData_SpinInit *ggd = gzgroup->customdata; - wmGizmo *gz = ggd->gizmos.xyz_view[axis_index]; - if (axis_tan != NULL) { - WM_gizmo_set_matrix_rotation_from_yz_axis(gz, axis_tan, axis_vec); - } - else { - WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis_vec); - } - - /* Only for display, use icons to access. */ + GizmoGroupData_SpinInit *ggd = gzgroup->customdata; + wmGizmo *gz = ggd->gizmos.xyz_view[axis_index]; + if (axis_tan != NULL) { + WM_gizmo_set_matrix_rotation_from_yz_axis(gz, axis_tan, axis_vec); + } + else { + WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis_vec); + } + + /* Only for display, use icons to access. */ #ifndef USE_DIAL_HOVER - { - PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ggd->data.ot_spin, NULL); - RNA_float_set_array(ptr, "axis", axis_vec); - } + { + PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ggd->data.ot_spin, NULL); + RNA_float_set_array(ptr, "axis", axis_vec); + } #endif - if (axis_index < 3) { - for (int j = 0; j < 2; j++) { - gz = ggd->gizmos.icon_button[axis_index][j]; - PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ggd->data.ot_spin, NULL); - float axis_vec_flip[3]; - if (0 == j) { - negate_v3_v3(axis_vec_flip, axis_vec); - } - else { - copy_v3_v3(axis_vec_flip, axis_vec); - } - RNA_float_set_array(ptr, "axis", axis_vec_flip); - } - } + if (axis_index < 3) { + for (int j = 0; j < 2; j++) { + gz = ggd->gizmos.icon_button[axis_index][j]; + PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ggd->data.ot_spin, NULL); + float axis_vec_flip[3]; + if (0 == j) { + negate_v3_v3(axis_vec_flip, axis_vec); + } + else { + copy_v3_v3(axis_vec_flip, axis_vec); + } + RNA_float_set_array(ptr, "axis", axis_vec_flip); + } + } } -static void gizmo_mesh_spin_init_draw_prepare( - const bContext *C, wmGizmoGroup *gzgroup) +static void gizmo_mesh_spin_init_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - GizmoGroupData_SpinInit *ggd = gzgroup->customdata; - RegionView3D *rv3d = CTX_wm_region_view3d(C); - float viewinv_m3[3][3]; - copy_m3_m4(viewinv_m3, rv3d->viewinv); - - { - Scene *scene = CTX_data_scene(C); - const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene, SCE_ORIENT_ROTATE); - switch (orient_slot->type) { - case V3D_ORIENT_VIEW: - { - if (!equals_m3m3(viewinv_m3, ggd->prev.viewinv_m3)) { - /* Take care calling refresh from draw_prepare, - * this should be OK because it's only adjusting the cage orientation. */ - gizmo_mesh_spin_init_refresh(C, gzgroup); - } - break; - } - } - } - - /* Refresh handled above when using view orientation. */ - if (!equals_m3m3(viewinv_m3, ggd->prev.viewinv_m3)) { - gizmo_mesh_spin_init_refresh_axis_orientation(gzgroup, 3, rv3d->viewinv[2], NULL); - copy_m3_m4(ggd->prev.viewinv_m3, rv3d->viewinv); - } - - /* Hack! highlight XYZ dials based on buttons */ + GizmoGroupData_SpinInit *ggd = gzgroup->customdata; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + float viewinv_m3[3][3]; + copy_m3_m4(viewinv_m3, rv3d->viewinv); + + { + Scene *scene = CTX_data_scene(C); + const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get( + scene, SCE_ORIENT_ROTATE); + switch (orient_slot->type) { + case V3D_ORIENT_VIEW: { + if (!equals_m3m3(viewinv_m3, ggd->prev.viewinv_m3)) { + /* Take care calling refresh from draw_prepare, + * this should be OK because it's only adjusting the cage orientation. */ + gizmo_mesh_spin_init_refresh(C, gzgroup); + } + break; + } + } + } + + /* Refresh handled above when using view orientation. */ + if (!equals_m3m3(viewinv_m3, ggd->prev.viewinv_m3)) { + gizmo_mesh_spin_init_refresh_axis_orientation(gzgroup, 3, rv3d->viewinv[2], NULL); + copy_m3_m4(ggd->prev.viewinv_m3, rv3d->viewinv); + } + + /* Hack! highlight XYZ dials based on buttons */ #ifdef USE_DIAL_HOVER - { - PointerRNA ptr; - bToolRef *tref = WM_toolsystem_ref_from_context((bContext *)C); - WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgroup->type, &ptr); - const int axis_flag = RNA_property_enum_get(&ptr, ggd->data.gzgt_axis_prop); - for (int i = 0; i < 4; i++) { - bool hide = (axis_flag & (1 << i)) == 0; - wmGizmo *gz = ggd->gizmos.xyz_view[i]; - WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, hide); - if (!hide) { - RNA_float_set(gz->ptr, "arc_partial_angle", (M_PI * 2) - (dial_angle_partial * dial_angle_partial_margin)); - } - } - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - wmGizmo *gz = ggd->gizmos.icon_button[i][j]; - if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) { - WM_gizmo_set_flag(ggd->gizmos.xyz_view[i], WM_GIZMO_HIDDEN, false); - RNA_float_set(ggd->gizmos.xyz_view[i]->ptr, "arc_partial_angle", 0.0f); - i = 3; - break; - } - } - } - } + { + PointerRNA ptr; + bToolRef *tref = WM_toolsystem_ref_from_context((bContext *)C); + WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgroup->type, &ptr); + const int axis_flag = RNA_property_enum_get(&ptr, ggd->data.gzgt_axis_prop); + for (int i = 0; i < 4; i++) { + bool hide = (axis_flag & (1 << i)) == 0; + wmGizmo *gz = ggd->gizmos.xyz_view[i]; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, hide); + if (!hide) { + RNA_float_set(gz->ptr, + "arc_partial_angle", + (M_PI * 2) - (dial_angle_partial * dial_angle_partial_margin)); + } + } + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + wmGizmo *gz = ggd->gizmos.icon_button[i][j]; + if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) { + WM_gizmo_set_flag(ggd->gizmos.xyz_view[i], WM_GIZMO_HIDDEN, false); + RNA_float_set(ggd->gizmos.xyz_view[i]->ptr, "arc_partial_angle", 0.0f); + i = 3; + break; + } + } + } + } #endif - } -static void gizmo_mesh_spin_init_invoke_prepare( - const bContext *UNUSED(C), wmGizmoGroup *gzgroup, wmGizmo *gz) +static void gizmo_mesh_spin_init_invoke_prepare(const bContext *UNUSED(C), + wmGizmoGroup *gzgroup, + wmGizmo *gz) { - /* Set the initial ortho axis. */ - GizmoGroupData_SpinInit *ggd = gzgroup->customdata; - ggd->invoke.ortho_axis_active = -1; - for (int i = 0; i < 3; i++) { - if (ELEM(gz, UNPACK2(ggd->gizmos.icon_button[i]))) { - ggd->invoke.ortho_axis_active = i; - break; - } - } + /* Set the initial ortho axis. */ + GizmoGroupData_SpinInit *ggd = gzgroup->customdata; + ggd->invoke.ortho_axis_active = -1; + for (int i = 0; i < 3; i++) { + if (ELEM(gz, UNPACK2(ggd->gizmos.icon_button[i]))) { + ggd->invoke.ortho_axis_active = i; + break; + } + } } static void gizmo_mesh_spin_init_refresh(const bContext *C, wmGizmoGroup *gzgroup) { - GizmoGroupData_SpinInit *ggd = gzgroup->customdata; - RegionView3D *rv3d = ED_view3d_context_rv3d((bContext *)C); - const float *gizmo_center = NULL; - { - Scene *scene = CTX_data_scene(C); - const View3DCursor *cursor = &scene->cursor; - gizmo_center = cursor->location; - } - - for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.xyz_view); i++) { - wmGizmo *gz = ggd->gizmos.xyz_view[i]; - WM_gizmo_set_matrix_location(gz, gizmo_center); - } - - for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.icon_button); i++) { - for (int j = 0; j < 2; j++) { - wmGizmo *gz = ggd->gizmos.icon_button[i][j]; - WM_gizmo_set_matrix_location(gz, gizmo_center); - } - } - - ED_transform_calc_orientation_from_type(C, ggd->data.orient_mat); - for (int i = 0; i < 3; i++) { - const int axis_ortho = (i + ORTHO_AXIS_OFFSET) % 3; - const float *axis_ortho_vec = ggd->data.orient_mat[axis_ortho]; + GizmoGroupData_SpinInit *ggd = gzgroup->customdata; + RegionView3D *rv3d = ED_view3d_context_rv3d((bContext *)C); + const float *gizmo_center = NULL; + { + Scene *scene = CTX_data_scene(C); + const View3DCursor *cursor = &scene->cursor; + gizmo_center = cursor->location; + } + + for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.xyz_view); i++) { + wmGizmo *gz = ggd->gizmos.xyz_view[i]; + WM_gizmo_set_matrix_location(gz, gizmo_center); + } + + for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.icon_button); i++) { + for (int j = 0; j < 2; j++) { + wmGizmo *gz = ggd->gizmos.icon_button[i][j]; + WM_gizmo_set_matrix_location(gz, gizmo_center); + } + } + + ED_transform_calc_orientation_from_type(C, ggd->data.orient_mat); + for (int i = 0; i < 3; i++) { + const int axis_ortho = (i + ORTHO_AXIS_OFFSET) % 3; + const float *axis_ortho_vec = ggd->data.orient_mat[axis_ortho]; #ifdef USE_SELECT_CENTER - if (ggd->data.use_select_center) { - float delta[3]; - sub_v3_v3v3(delta, ggd->data.select_center, gizmo_center); - project_plane_normalized_v3_v3v3(ggd->data.select_center_ortho_axis[i], delta, ggd->data.orient_mat[i]); - if (normalize_v3(ggd->data.select_center_ortho_axis[i]) != 0.0f) { - axis_ortho_vec = ggd->data.select_center_ortho_axis[i]; - } - } + if (ggd->data.use_select_center) { + float delta[3]; + sub_v3_v3v3(delta, ggd->data.select_center, gizmo_center); + project_plane_normalized_v3_v3v3( + ggd->data.select_center_ortho_axis[i], delta, ggd->data.orient_mat[i]); + if (normalize_v3(ggd->data.select_center_ortho_axis[i]) != 0.0f) { + axis_ortho_vec = ggd->data.select_center_ortho_axis[i]; + } + } #endif - gizmo_mesh_spin_init_refresh_axis_orientation( - gzgroup, i, ggd->data.orient_mat[i], axis_ortho_vec); - } - - { - gizmo_mesh_spin_init_refresh_axis_orientation( - gzgroup, 3, rv3d->viewinv[2], NULL); - } + gizmo_mesh_spin_init_refresh_axis_orientation( + gzgroup, i, ggd->data.orient_mat[i], axis_ortho_vec); + } + { + gizmo_mesh_spin_init_refresh_axis_orientation(gzgroup, 3, rv3d->viewinv[2], NULL); + } #ifdef USE_SELECT_CENTER - { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - float select_center[3] = {0}; - int totsel = 0; - - BMesh *bm = em->bm; - BMVert *eve; - BMIter iter; - - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - totsel++; - add_v3_v3(select_center, eve->co); - } - } - } - if (totsel) { - mul_v3_fl(select_center, 1.0f / totsel); - mul_m4_v3(obedit->obmat, select_center); - copy_v3_v3(ggd->data.select_center, select_center); - ggd->data.use_select_center = true; - } - else { - ggd->data.use_select_center = false; - } - } + { + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + float select_center[3] = {0}; + int totsel = 0; + + BMesh *bm = em->bm; + BMVert *eve; + BMIter iter; + + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + totsel++; + add_v3_v3(select_center, eve->co); + } + } + } + if (totsel) { + mul_v3_fl(select_center, 1.0f / totsel); + mul_m4_v3(obedit->obmat, select_center); + copy_v3_v3(ggd->data.select_center, select_center); + ggd->data.use_select_center = true; + } + else { + ggd->data.use_select_center = false; + } + } #endif - for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.icon_button); i++) { - const int axis_ortho = (i + ORTHO_AXIS_OFFSET) % 3; - const float *axis_ortho_vec = ggd->data.orient_mat[axis_ortho]; - float offset = INIT_SCALE_BASE / INIT_SCALE_BUTTON; - float offset_vec[3]; + for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.icon_button); i++) { + const int axis_ortho = (i + ORTHO_AXIS_OFFSET) % 3; + const float *axis_ortho_vec = ggd->data.orient_mat[axis_ortho]; + float offset = INIT_SCALE_BASE / INIT_SCALE_BUTTON; + float offset_vec[3]; #ifdef USE_SELECT_CENTER - if (ggd->data.use_select_center && !is_zero_v3(ggd->data.select_center_ortho_axis[i])) { - axis_ortho_vec = ggd->data.select_center_ortho_axis[i]; - } + if (ggd->data.use_select_center && !is_zero_v3(ggd->data.select_center_ortho_axis[i])) { + axis_ortho_vec = ggd->data.select_center_ortho_axis[i]; + } #endif - mul_v3_v3fl(offset_vec, axis_ortho_vec, offset); - for (int j = 0; j < 2; j++) { - wmGizmo *gz = ggd->gizmos.icon_button[i][j]; - float mat3[3][3]; - axis_angle_to_mat3(mat3, ggd->data.orient_mat[i], dial_angle_partial * (j ? -0.5f : 0.5f)); - mul_v3_m3v3(gz->matrix_offset[3], mat3, offset_vec); - } - } - - { - PointerRNA ptr; - bToolRef *tref = WM_toolsystem_ref_from_context((bContext *)C); - WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgroup->type, &ptr); - const int axis_flag = RNA_property_enum_get(&ptr, ggd->data.gzgt_axis_prop); - for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.icon_button); i++) { - for (int j = 0; j < 2; j++) { - wmGizmo *gz = ggd->gizmos.icon_button[i][j]; - WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, (axis_flag & (1 << i)) == 0); - } - } - } - - /* Needed to test view orientation changes. */ - copy_m3_m4(ggd->prev.viewinv_m3, rv3d->viewinv); + mul_v3_v3fl(offset_vec, axis_ortho_vec, offset); + for (int j = 0; j < 2; j++) { + wmGizmo *gz = ggd->gizmos.icon_button[i][j]; + float mat3[3][3]; + axis_angle_to_mat3(mat3, ggd->data.orient_mat[i], dial_angle_partial * (j ? -0.5f : 0.5f)); + mul_v3_m3v3(gz->matrix_offset[3], mat3, offset_vec); + } + } + + { + PointerRNA ptr; + bToolRef *tref = WM_toolsystem_ref_from_context((bContext *)C); + WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgroup->type, &ptr); + const int axis_flag = RNA_property_enum_get(&ptr, ggd->data.gzgt_axis_prop); + for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.icon_button); i++) { + for (int j = 0; j < 2; j++) { + wmGizmo *gz = ggd->gizmos.icon_button[i][j]; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, (axis_flag & (1 << i)) == 0); + } + } + } + + /* Needed to test view orientation changes. */ + copy_m3_m4(ggd->prev.viewinv_m3, rv3d->viewinv); } - -static void gizmo_mesh_spin_init_message_subscribe( - const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus) +static void gizmo_mesh_spin_init_message_subscribe(const bContext *C, + wmGizmoGroup *gzgroup, + struct wmMsgBus *mbus) { - GizmoGroupData_SpinInit *ggd = gzgroup->customdata; - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - - /* Subscribe to view properties */ - wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = { - .owner = ar, - .user_data = gzgroup->parent_gzmap, - .notify = WM_gizmo_do_msg_notify_tag_refresh, - }; - - PointerRNA cursor_ptr; - RNA_pointer_create(&scene->id, &RNA_View3DCursor, &scene->cursor, &cursor_ptr); - /* All cursor properties. */ - WM_msg_subscribe_rna(mbus, &cursor_ptr, NULL, &msg_sub_value_gz_tag_refresh, __func__); - - WM_msg_subscribe_rna_params( - mbus, - &(const wmMsgParams_RNA){ - .ptr = (PointerRNA){ .type = gzgroup->type->srna, }, - .prop = ggd->data.gzgt_axis_prop, - }, - &msg_sub_value_gz_tag_refresh, __func__); - + GizmoGroupData_SpinInit *ggd = gzgroup->customdata; + Scene *scene = CTX_data_scene(C); + ARegion *ar = CTX_wm_region(C); + + /* Subscribe to view properties */ + wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = { + .owner = ar, + .user_data = gzgroup->parent_gzmap, + .notify = WM_gizmo_do_msg_notify_tag_refresh, + }; + + PointerRNA cursor_ptr; + RNA_pointer_create(&scene->id, &RNA_View3DCursor, &scene->cursor, &cursor_ptr); + /* All cursor properties. */ + WM_msg_subscribe_rna(mbus, &cursor_ptr, NULL, &msg_sub_value_gz_tag_refresh, __func__); + + WM_msg_subscribe_rna_params(mbus, + &(const wmMsgParams_RNA){ + .ptr = + (PointerRNA){ + .type = gzgroup->type->srna, + }, + .prop = ggd->data.gzgt_axis_prop, + }, + &msg_sub_value_gz_tag_refresh, + __func__); } void MESH_GGT_spin(struct wmGizmoGroupType *gzgt) { - gzgt->name = "Mesh Spin Init"; - gzgt->idname = "MESH_GGT_spin"; + gzgt->name = "Mesh Spin Init"; + gzgt->idname = "MESH_GGT_spin"; - gzgt->flag = WM_GIZMOGROUPTYPE_3D; + gzgt->flag = WM_GIZMOGROUPTYPE_3D; - gzgt->gzmap_params.spaceid = SPACE_VIEW3D; - gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; - gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; - gzgt->setup = gizmo_mesh_spin_init_setup; - gzgt->refresh = gizmo_mesh_spin_init_refresh; - gzgt->message_subscribe = gizmo_mesh_spin_init_message_subscribe; - gzgt->draw_prepare = gizmo_mesh_spin_init_draw_prepare; - gzgt->invoke_prepare = gizmo_mesh_spin_init_invoke_prepare; + gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; + gzgt->setup = gizmo_mesh_spin_init_setup; + gzgt->refresh = gizmo_mesh_spin_init_refresh; + gzgt->message_subscribe = gizmo_mesh_spin_init_message_subscribe; + gzgt->draw_prepare = gizmo_mesh_spin_init_draw_prepare; + gzgt->invoke_prepare = gizmo_mesh_spin_init_invoke_prepare; - RNA_def_enum_flag(gzgt->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 2), "Axis", ""); + RNA_def_enum_flag(gzgt->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 2), "Axis", ""); } #undef INIT_SCALE_BASE @@ -490,49 +492,49 @@ void MESH_GGT_spin(struct wmGizmoGroupType *gzgt) #define USE_ANGLE_Z_ORIENT typedef struct GizmoGroupData_SpinRedo { - /* Translate XYZ. */ - struct wmGizmo *translate_c; - /* Spin angle */ - struct wmGizmo *angle_z; - - /* Translate XY constrained ('orient_mat'). */ - struct wmGizmo *translate_xy[2]; - /* Rotate XY constrained ('orient_mat'). */ - struct wmGizmo *rotate_xy[2]; - - /* Rotate on view axis. */ - struct wmGizmo *rotate_view; - - struct { - float plane_co[3]; - float plane_no[3]; - } prev; - - bool is_init; - - /* We could store more vars here! */ - struct { - bContext *context; - wmOperatorType *ot; - wmOperator *op; - PropertyRNA *prop_axis_co; - PropertyRNA *prop_axis_no; - PropertyRNA *prop_angle; - - float rotate_axis[3]; + /* Translate XYZ. */ + struct wmGizmo *translate_c; + /* Spin angle */ + struct wmGizmo *angle_z; + + /* Translate XY constrained ('orient_mat'). */ + struct wmGizmo *translate_xy[2]; + /* Rotate XY constrained ('orient_mat'). */ + struct wmGizmo *rotate_xy[2]; + + /* Rotate on view axis. */ + struct wmGizmo *rotate_view; + + struct { + float plane_co[3]; + float plane_no[3]; + } prev; + + bool is_init; + + /* We could store more vars here! */ + struct { + bContext *context; + wmOperatorType *ot; + wmOperator *op; + PropertyRNA *prop_axis_co; + PropertyRNA *prop_axis_no; + PropertyRNA *prop_angle; + + float rotate_axis[3]; #ifdef USE_ANGLE_Z_ORIENT - /* Apply 'orient_mat' for the final value. */ - float orient_axis_relative[3]; + /* Apply 'orient_mat' for the final value. */ + float orient_axis_relative[3]; #endif - /* The orientation, since the operator doesn't store this, we store our own. - * this is kept in sync with the operator, - * rotating the orientation when it doesn't match. - * - * Initialize to a sensible value where possible. - */ - float orient_mat[3][3]; - - } data; + /* The orientation, since the operator doesn't store this, we store our own. + * this is kept in sync with the operator, + * rotating the orientation when it doesn't match. + * + * Initialize to a sensible value where possible. + */ + float orient_mat[3][3]; + + } data; } GizmoGroupData_SpinRedo; /** @@ -542,526 +544,520 @@ typedef struct GizmoGroupData_SpinRedo { */ static void gizmo_spin_exec(GizmoGroupData_SpinRedo *ggd) { - if (ggd->is_init) { - wmGizmo *gz = ggd->angle_z; - PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value"); - RNA_property_unset(gz->ptr, prop); - ggd->is_init = false; - } - - wmOperator *op = ggd->data.op; - if (op == WM_operator_last_redo((bContext *)ggd->data.context)) { - ED_undo_operator_repeat((bContext *)ggd->data.context, op); - } + if (ggd->is_init) { + wmGizmo *gz = ggd->angle_z; + PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value"); + RNA_property_unset(gz->ptr, prop); + ggd->is_init = false; + } + + wmOperator *op = ggd->data.op; + if (op == WM_operator_last_redo((bContext *)ggd->data.context)) { + ED_undo_operator_repeat((bContext *)ggd->data.context, op); + } } -static void gizmo_mesh_spin_redo_update_orient_axis(GizmoGroupData_SpinRedo *ggd, const float plane_no[3]) +static void gizmo_mesh_spin_redo_update_orient_axis(GizmoGroupData_SpinRedo *ggd, + const float plane_no[3]) { - float mat[3][3]; - rotation_between_vecs_to_mat3(mat, ggd->data.orient_mat[2], plane_no); - mul_m3_m3m3(ggd->data.orient_mat, mat, ggd->data.orient_mat); - /* Not needed, just set for numeric stability. */ - copy_v3_v3(ggd->data.orient_mat[2], plane_no); + float mat[3][3]; + rotation_between_vecs_to_mat3(mat, ggd->data.orient_mat[2], plane_no); + mul_m3_m3m3(ggd->data.orient_mat, mat, ggd->data.orient_mat); + /* Not needed, just set for numeric stability. */ + copy_v3_v3(ggd->data.orient_mat[2], plane_no); } static void gizmo_mesh_spin_redo_update_from_op(GizmoGroupData_SpinRedo *ggd) { - wmOperator *op = ggd->data.op; - float plane_co[3], plane_no[3]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); - if (UNLIKELY(normalize_v3(plane_no) == 0.0f)) { - return; - } - const bool is_plane_co_eq = equals_v3v3(plane_co, ggd->prev.plane_co); - const bool is_plane_no_eq = equals_v3v3(plane_no, ggd->prev.plane_no); - if (is_plane_co_eq && is_plane_no_eq) { - return; - } - copy_v3_v3(ggd->prev.plane_co, plane_co); - copy_v3_v3(ggd->prev.plane_no, plane_no); - - if (is_plane_no_eq == false) { - gizmo_mesh_spin_redo_update_orient_axis(ggd, plane_no); - } - - for (int i = 0; i < 2; i++) { - WM_gizmo_set_matrix_location(ggd->rotate_xy[i], plane_co); - WM_gizmo_set_matrix_location(ggd->translate_xy[i], plane_co); - } - WM_gizmo_set_matrix_location(ggd->angle_z, plane_co); - WM_gizmo_set_matrix_location(ggd->rotate_view, plane_co); - /* translate_c location comes from the property. */ - - for (int i = 0; i < 2; i++) { - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_xy[i], ggd->data.orient_mat[i]); - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->rotate_xy[i], ggd->data.orient_mat[i]); - } + wmOperator *op = ggd->data.op; + float plane_co[3], plane_no[3]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); + RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); + if (UNLIKELY(normalize_v3(plane_no) == 0.0f)) { + return; + } + const bool is_plane_co_eq = equals_v3v3(plane_co, ggd->prev.plane_co); + const bool is_plane_no_eq = equals_v3v3(plane_no, ggd->prev.plane_no); + if (is_plane_co_eq && is_plane_no_eq) { + return; + } + copy_v3_v3(ggd->prev.plane_co, plane_co); + copy_v3_v3(ggd->prev.plane_no, plane_no); + + if (is_plane_no_eq == false) { + gizmo_mesh_spin_redo_update_orient_axis(ggd, plane_no); + } + + for (int i = 0; i < 2; i++) { + WM_gizmo_set_matrix_location(ggd->rotate_xy[i], plane_co); + WM_gizmo_set_matrix_location(ggd->translate_xy[i], plane_co); + } + WM_gizmo_set_matrix_location(ggd->angle_z, plane_co); + WM_gizmo_set_matrix_location(ggd->rotate_view, plane_co); + /* translate_c location comes from the property. */ + + for (int i = 0; i < 2; i++) { + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_xy[i], ggd->data.orient_mat[i]); + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->rotate_xy[i], ggd->data.orient_mat[i]); + } #ifdef USE_ANGLE_Z_ORIENT - { - float plane_tan[3]; - float orient_axis[3]; - mul_v3_m3v3(orient_axis, ggd->data.orient_mat, ggd->data.orient_axis_relative); - project_plane_normalized_v3_v3v3(plane_tan, orient_axis, plane_no); - if (normalize_v3(plane_tan) != 0.0f) { - WM_gizmo_set_matrix_rotation_from_yz_axis(ggd->angle_z, plane_tan, plane_no); - } - else { - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->angle_z, plane_no); - } - } + { + float plane_tan[3]; + float orient_axis[3]; + mul_v3_m3v3(orient_axis, ggd->data.orient_mat, ggd->data.orient_axis_relative); + project_plane_normalized_v3_v3v3(plane_tan, orient_axis, plane_no); + if (normalize_v3(plane_tan) != 0.0f) { + WM_gizmo_set_matrix_rotation_from_yz_axis(ggd->angle_z, plane_tan, plane_no); + } + else { + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->angle_z, plane_no); + } + } #else - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->angle_z, plane_no); + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->angle_z, plane_no); #endif } /* depth callbacks */ -static void gizmo_spin_prop_depth_get( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - void *value_p) +static void gizmo_spin_prop_depth_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - float *value = value_p; + GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + float *value = value_p; - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); - const float *plane_no = gz->matrix_basis[2]; - float plane_co[3]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); + const float *plane_no = gz->matrix_basis[2]; + float plane_co[3]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); - value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]); + value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]); } -static void gizmo_spin_prop_depth_set( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - const void *value_p) +static void gizmo_spin_prop_depth_set(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + const void *value_p) { - GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - const float *value = value_p; + GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + const float *value = value_p; - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); - float plane_co[3], plane[4]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); - normalize_v3_v3(plane, gz->matrix_basis[2]); + float plane_co[3], plane[4]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); + normalize_v3_v3(plane, gz->matrix_basis[2]); - plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]); + plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]); - /* Keep our location, may be offset simply to be inside the viewport. */ - closest_to_plane_normalized_v3(plane_co, plane, plane_co); + /* Keep our location, may be offset simply to be inside the viewport. */ + closest_to_plane_normalized_v3(plane_co, plane, plane_co); - RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_co, plane_co); + RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_co, plane_co); - gizmo_spin_exec(ggd); + gizmo_spin_exec(ggd); } /* translate callbacks */ -static void gizmo_spin_prop_translate_get( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - void *value_p) +static void gizmo_spin_prop_translate_get(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + void *value_p) { - GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - float *value = value_p; + GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + float *value = value_p; - BLI_assert(gz_prop->type->array_length == 3); - UNUSED_VARS_NDEBUG(gz_prop); + BLI_assert(gz_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(gz_prop); - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, value); + RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, value); } -static void gizmo_spin_prop_translate_set( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - const void *value) +static void gizmo_spin_prop_translate_set(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + const void *value) { - GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; + GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; - BLI_assert(gz_prop->type->array_length == 3); - UNUSED_VARS_NDEBUG(gz_prop); + BLI_assert(gz_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(gz_prop); - RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_co, value); + RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_co, value); - gizmo_spin_exec(ggd); + gizmo_spin_exec(ggd); } /* angle callbacks */ -static void gizmo_spin_prop_axis_angle_get( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - void *value_p) +static void gizmo_spin_prop_axis_angle_get(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + void *value_p) { - GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - float *value = value_p; - - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); - - float plane_no[4]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); - normalize_v3(plane_no); - - const float *rotate_axis = gz->matrix_basis[2]; - float rotate_up[3]; - ortho_v3_v3(rotate_up, rotate_axis); - - float plane_no_proj[3]; - project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, rotate_axis); - - if (!is_zero_v3(plane_no_proj)) { - const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, rotate_up, rotate_axis); - value[0] = angle; - } - else { - value[0] = 0.0f; - } + GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + float *value = value_p; + + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); + + float plane_no[4]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); + normalize_v3(plane_no); + + const float *rotate_axis = gz->matrix_basis[2]; + float rotate_up[3]; + ortho_v3_v3(rotate_up, rotate_axis); + + float plane_no_proj[3]; + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, rotate_axis); + + if (!is_zero_v3(plane_no_proj)) { + const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, rotate_up, rotate_axis); + value[0] = angle; + } + else { + value[0] = 0.0f; + } } -static void gizmo_spin_prop_axis_angle_set( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - const void *value_p) +static void gizmo_spin_prop_axis_angle_set(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + const void *value_p) { - GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - const float *value = value_p; - - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); - - float plane_no[4]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); - normalize_v3(plane_no); - - const float *rotate_axis = gz->matrix_basis[2]; - float rotate_up[3]; - ortho_v3_v3(rotate_up, rotate_axis); - - float plane_no_proj[3]; - project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, rotate_axis); - - if (!is_zero_v3(plane_no_proj)) { - const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, rotate_up, rotate_axis); - const float angle_delta = angle - angle_compat_rad(value[0], angle); - if (angle_delta != 0.0f) { - float mat[3][3]; - axis_angle_normalized_to_mat3(mat, rotate_axis, angle_delta); - mul_m3_v3(mat, plane_no); - - /* re-normalize - seems acceptable */ - RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_no, plane_no); - - gizmo_spin_exec(ggd); - } - } + GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + const float *value = value_p; + + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); + + float plane_no[4]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); + normalize_v3(plane_no); + + const float *rotate_axis = gz->matrix_basis[2]; + float rotate_up[3]; + ortho_v3_v3(rotate_up, rotate_axis); + + float plane_no_proj[3]; + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, rotate_axis); + + if (!is_zero_v3(plane_no_proj)) { + const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, rotate_up, rotate_axis); + const float angle_delta = angle - angle_compat_rad(value[0], angle); + if (angle_delta != 0.0f) { + float mat[3][3]; + axis_angle_normalized_to_mat3(mat, rotate_axis, angle_delta); + mul_m3_v3(mat, plane_no); + + /* re-normalize - seems acceptable */ + RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_no, plane_no); + + gizmo_spin_exec(ggd); + } + } } /* angle callbacks */ -static void gizmo_spin_prop_angle_get( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - void *value_p) +static void gizmo_spin_prop_angle_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - float *value = value_p; + GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + float *value = value_p; - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); - value[0] = RNA_property_float_get(op->ptr, ggd->data.prop_angle); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); + value[0] = RNA_property_float_get(op->ptr, ggd->data.prop_angle); } -static void gizmo_spin_prop_angle_set( - const wmGizmo *gz, wmGizmoProperty *gz_prop, - const void *value_p) +static void gizmo_spin_prop_angle_set(const wmGizmo *gz, + wmGizmoProperty *gz_prop, + const void *value_p) { - GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; - wmOperator *op = ggd->data.op; - BLI_assert(gz_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(gz_prop); - const float *value = value_p; - RNA_property_float_set(op->ptr, ggd->data.prop_angle, value[0]); - - gizmo_spin_exec(ggd); + GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata; + wmOperator *op = ggd->data.op; + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); + const float *value = value_p; + RNA_property_float_set(op->ptr, ggd->data.prop_angle, value[0]); + + gizmo_spin_exec(ggd); } static bool gizmo_mesh_spin_redo_poll(const bContext *C, wmGizmoGroupType *gzgt) { - if (ED_gizmo_poll_or_unlink_delayed_from_operator(C, gzgt, "MESH_OT_spin")) { - if (ED_gizmo_poll_or_unlink_delayed_from_tool_ex(C, gzgt, "MESH_GGT_spin")) { - return true; - } - } - return false; + if (ED_gizmo_poll_or_unlink_delayed_from_operator(C, gzgt, "MESH_OT_spin")) { + if (ED_gizmo_poll_or_unlink_delayed_from_tool_ex(C, gzgt, "MESH_GGT_spin")) { + return true; + } + } + return false; } -static void gizmo_mesh_spin_redo_modal_from_setup( - const bContext *C, wmGizmoGroup *gzgroup) +static void gizmo_mesh_spin_redo_modal_from_setup(const bContext *C, wmGizmoGroup *gzgroup) { - /* Start off dragging. */ - GizmoGroupData_SpinRedo *ggd = gzgroup->customdata; - wmWindow *win = CTX_wm_window(C); - wmGizmo *gz = ggd->angle_z; - wmGizmoMap *gzmap = gzgroup->parent_gzmap; + /* Start off dragging. */ + GizmoGroupData_SpinRedo *ggd = gzgroup->customdata; + wmWindow *win = CTX_wm_window(C); + wmGizmo *gz = ggd->angle_z; + wmGizmoMap *gzmap = gzgroup->parent_gzmap; - ggd->is_init = true; + ggd->is_init = true; - WM_gizmo_modal_set_from_setup( - gzmap, (bContext *)C, gz, 0, win->eventstate); + WM_gizmo_modal_set_from_setup(gzmap, (bContext *)C, gz, 0, win->eventstate); } static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup) { - wmOperatorType *ot = WM_operatortype_find("MESH_OT_spin", true); - wmOperator *op = WM_operator_last_redo(C); - - if ((op == NULL) || (op->type != ot)) { - return; - } - - GizmoGroupData_SpinRedo *ggd = MEM_callocN(sizeof(*ggd), __func__); - gzgroup->customdata = ggd; - - const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true); - const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true); - const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); - - /* Rotate View Axis (rotate_view) */ - { - wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); - zero_v4(gz->color); - copy_v3_fl(gz->color_hi, 1.0f); - gz->color_hi[3] = 0.1f; - WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); - RNA_enum_set(gz->ptr, "draw_options", - ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR | - ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y | - ED_GIZMO_DIAL_DRAW_FLAG_FILL); - ggd->rotate_view = gz; - } - - /* Translate Center (translate_c) */ - { - wmGizmo *gz = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL); - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); - gz->color[3] = 0.6f; - RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D); - WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); - WM_gizmo_set_scale(gz, 0.15); - WM_gizmo_set_line_width(gz, 2.0f); - ggd->translate_c = gz; - } - - /* Spin Angle (angle_z) */ - { - wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); - copy_v3_v3(gz->color, gz->color_hi); - gz->color[3] = 0.5f; - RNA_boolean_set(gz->ptr, "wrap_angle", false); - RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE); - RNA_float_set(gz->ptr, "arc_inner_factor", 0.9f); - RNA_float_set(gz->ptr, "click_value", M_PI * 2); - WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); - WM_gizmo_set_scale(gz, 2.0f); - WM_gizmo_set_line_width(gz, 1.0f); - ggd->angle_z = gz; - } - - /* Translate X/Y Tangents (translate_xy) */ - for (int i = 0; i < 2; i++) { - wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); - UI_GetThemeColor3fv(TH_AXIS_X + i, gz->color); - RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL); - RNA_enum_set(gz->ptr, "draw_options", 0); - WM_gizmo_set_scale(gz, 1.2f); - ggd->translate_xy[i] = gz; - } - - /* Rotate X/Y Tangents (rotate_xy) */ - for (int i = 0; i < 2; i++) { - wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); - UI_GetThemeColor3fv(TH_AXIS_X + i, gz->color); - gz->color[3] = 0.6f; - WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); - WM_gizmo_set_line_width(gz, 3.0f); - /* show the axis instead of mouse cursor */ - RNA_enum_set(gz->ptr, "draw_options", - ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR | - ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y | - ED_GIZMO_DIAL_DRAW_FLAG_CLIP); - ggd->rotate_xy[i] = gz; - } - - { - ggd->data.context = (bContext *)C; - ggd->data.ot = ot; - ggd->data.op = op; - ggd->data.prop_axis_co = RNA_struct_type_find_property(ot->srna, "center"); - ggd->data.prop_axis_no = RNA_struct_type_find_property(ot->srna, "axis"); - ggd->data.prop_angle = RNA_struct_type_find_property(ot->srna, "angle"); - } - - /* The spin operator only knows about an axis, - * while the manipulator has X/Y orientation for the gizmos. - * Initialize the orientation from the spin gizmo if possible. - */ - { - ARegion *ar = CTX_wm_region(C); - wmGizmoMap *gzmap = ar->gizmo_map; - wmGizmoGroup *gzgroup_init = WM_gizmomap_group_find(gzmap, "MESH_GGT_spin"); - if (gzgroup_init) { - GizmoGroupData_SpinInit *ggd_init = gzgroup_init->customdata; - copy_m3_m3(ggd->data.orient_mat, ggd_init->data.orient_mat); - if (ggd_init->invoke.ortho_axis_active != -1) { - copy_v3_v3(ggd->data.orient_axis_relative, - ggd_init->gizmos.xyz_view[ggd_init->invoke.ortho_axis_active]->matrix_basis[1]); - ggd_init->invoke.ortho_axis_active = -1; - } - } - else { - unit_m3(ggd->data.orient_mat); - } - } + wmOperatorType *ot = WM_operatortype_find("MESH_OT_spin", true); + wmOperator *op = WM_operator_last_redo(C); + + if ((op == NULL) || (op->type != ot)) { + return; + } + + GizmoGroupData_SpinRedo *ggd = MEM_callocN(sizeof(*ggd), __func__); + gzgroup->customdata = ggd; + + const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true); + const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true); + const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); + + /* Rotate View Axis (rotate_view) */ + { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + zero_v4(gz->color); + copy_v3_fl(gz->color_hi, 1.0f); + gz->color_hi[3] = 0.1f; + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); + RNA_enum_set(gz->ptr, + "draw_options", + ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR | ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y | + ED_GIZMO_DIAL_DRAW_FLAG_FILL); + ggd->rotate_view = gz; + } + + /* Translate Center (translate_c) */ + { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL); + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + gz->color[3] = 0.6f; + RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D); + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); + WM_gizmo_set_scale(gz, 0.15); + WM_gizmo_set_line_width(gz, 2.0f); + ggd->translate_c = gz; + } + + /* Spin Angle (angle_z) */ + { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); + copy_v3_v3(gz->color, gz->color_hi); + gz->color[3] = 0.5f; + RNA_boolean_set(gz->ptr, "wrap_angle", false); + RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE); + RNA_float_set(gz->ptr, "arc_inner_factor", 0.9f); + RNA_float_set(gz->ptr, "click_value", M_PI * 2); + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); + WM_gizmo_set_scale(gz, 2.0f); + WM_gizmo_set_line_width(gz, 1.0f); + ggd->angle_z = gz; + } + + /* Translate X/Y Tangents (translate_xy) */ + for (int i = 0; i < 2; i++) { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); + UI_GetThemeColor3fv(TH_AXIS_X + i, gz->color); + RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL); + RNA_enum_set(gz->ptr, "draw_options", 0); + WM_gizmo_set_scale(gz, 1.2f); + ggd->translate_xy[i] = gz; + } + + /* Rotate X/Y Tangents (rotate_xy) */ + for (int i = 0; i < 2; i++) { + wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); + UI_GetThemeColor3fv(TH_AXIS_X + i, gz->color); + gz->color[3] = 0.6f; + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); + WM_gizmo_set_line_width(gz, 3.0f); + /* show the axis instead of mouse cursor */ + RNA_enum_set(gz->ptr, + "draw_options", + ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR | ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y | + ED_GIZMO_DIAL_DRAW_FLAG_CLIP); + ggd->rotate_xy[i] = gz; + } + + { + ggd->data.context = (bContext *)C; + ggd->data.ot = ot; + ggd->data.op = op; + ggd->data.prop_axis_co = RNA_struct_type_find_property(ot->srna, "center"); + ggd->data.prop_axis_no = RNA_struct_type_find_property(ot->srna, "axis"); + ggd->data.prop_angle = RNA_struct_type_find_property(ot->srna, "angle"); + } + + /* The spin operator only knows about an axis, + * while the manipulator has X/Y orientation for the gizmos. + * Initialize the orientation from the spin gizmo if possible. + */ + { + ARegion *ar = CTX_wm_region(C); + wmGizmoMap *gzmap = ar->gizmo_map; + wmGizmoGroup *gzgroup_init = WM_gizmomap_group_find(gzmap, "MESH_GGT_spin"); + if (gzgroup_init) { + GizmoGroupData_SpinInit *ggd_init = gzgroup_init->customdata; + copy_m3_m3(ggd->data.orient_mat, ggd_init->data.orient_mat); + if (ggd_init->invoke.ortho_axis_active != -1) { + copy_v3_v3(ggd->data.orient_axis_relative, + ggd_init->gizmos.xyz_view[ggd_init->invoke.ortho_axis_active]->matrix_basis[1]); + ggd_init->invoke.ortho_axis_active = -1; + } + } + else { + unit_m3(ggd->data.orient_mat); + } + } #ifdef USE_ANGLE_Z_ORIENT - { - wmWindow *win = CTX_wm_window(C); - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - const wmEvent *event = win->eventstate; - float plane_co[3], plane_no[3]; - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); - RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); - - gizmo_mesh_spin_redo_update_orient_axis(ggd, plane_no); - - /* Use cursor as fallback if it's not set by the 'ortho_axis_active'. */ - if (is_zero_v3(ggd->data.orient_axis_relative)) { - float cursor_co[3]; - const int mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin}; - float plane[4]; - plane_from_point_normal_v3(plane, plane_co, plane_no); - if (UNLIKELY(!ED_view3d_win_to_3d_on_plane_int(ar, plane, mval, false, cursor_co))) { - ED_view3d_win_to_3d_int(v3d, ar, plane, mval, cursor_co); - } - sub_v3_v3v3(ggd->data.orient_axis_relative, cursor_co, plane_co); - } - - if (!is_zero_v3(ggd->data.orient_axis_relative)) { - normalize_v3(ggd->data.orient_axis_relative); - float imat3[3][3]; - invert_m3_m3(imat3, ggd->data.orient_mat); - mul_m3_v3(imat3, ggd->data.orient_axis_relative); - } - } + { + wmWindow *win = CTX_wm_window(C); + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + const wmEvent *event = win->eventstate; + float plane_co[3], plane_no[3]; + RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co); + RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no); + + gizmo_mesh_spin_redo_update_orient_axis(ggd, plane_no); + + /* Use cursor as fallback if it's not set by the 'ortho_axis_active'. */ + if (is_zero_v3(ggd->data.orient_axis_relative)) { + float cursor_co[3]; + const int mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin}; + float plane[4]; + plane_from_point_normal_v3(plane, plane_co, plane_no); + if (UNLIKELY(!ED_view3d_win_to_3d_on_plane_int(ar, plane, mval, false, cursor_co))) { + ED_view3d_win_to_3d_int(v3d, ar, plane, mval, cursor_co); + } + sub_v3_v3v3(ggd->data.orient_axis_relative, cursor_co, plane_co); + } + + if (!is_zero_v3(ggd->data.orient_axis_relative)) { + normalize_v3(ggd->data.orient_axis_relative); + float imat3[3][3]; + invert_m3_m3(imat3, ggd->data.orient_mat); + mul_m3_v3(imat3, ggd->data.orient_axis_relative); + } + } #endif - gizmo_mesh_spin_redo_update_from_op(ggd); - - /* Setup property callbacks */ - { - WM_gizmo_target_property_def_func( - ggd->translate_c, "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_spin_prop_translate_get, - .value_set_fn = gizmo_spin_prop_translate_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - - WM_gizmo_target_property_def_func( - ggd->rotate_view, "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_spin_prop_axis_angle_get, - .value_set_fn = gizmo_spin_prop_axis_angle_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - - for (int i = 0; i < 2; i++) { - WM_gizmo_target_property_def_func( - ggd->rotate_xy[i], "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_spin_prop_axis_angle_get, - .value_set_fn = gizmo_spin_prop_axis_angle_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - WM_gizmo_target_property_def_func( - ggd->translate_xy[i], "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_spin_prop_depth_get, - .value_set_fn = gizmo_spin_prop_depth_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - } - - WM_gizmo_target_property_def_func( - ggd->angle_z, "offset", - &(const struct wmGizmoPropertyFnParams) { - .value_get_fn = gizmo_spin_prop_angle_get, - .value_set_fn = gizmo_spin_prop_angle_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - } - - /* Become modal as soon as it's started. */ - gizmo_mesh_spin_redo_modal_from_setup(C, gzgroup); + gizmo_mesh_spin_redo_update_from_op(ggd); + + /* Setup property callbacks */ + { + WM_gizmo_target_property_def_func(ggd->translate_c, + "offset", + &(const struct wmGizmoPropertyFnParams){ + .value_get_fn = gizmo_spin_prop_translate_get, + .value_set_fn = gizmo_spin_prop_translate_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + WM_gizmo_target_property_def_func(ggd->rotate_view, + "offset", + &(const struct wmGizmoPropertyFnParams){ + .value_get_fn = gizmo_spin_prop_axis_angle_get, + .value_set_fn = gizmo_spin_prop_axis_angle_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + for (int i = 0; i < 2; i++) { + WM_gizmo_target_property_def_func(ggd->rotate_xy[i], + "offset", + &(const struct wmGizmoPropertyFnParams){ + .value_get_fn = gizmo_spin_prop_axis_angle_get, + .value_set_fn = gizmo_spin_prop_axis_angle_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + WM_gizmo_target_property_def_func(ggd->translate_xy[i], + "offset", + &(const struct wmGizmoPropertyFnParams){ + .value_get_fn = gizmo_spin_prop_depth_get, + .value_set_fn = gizmo_spin_prop_depth_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + } + + WM_gizmo_target_property_def_func(ggd->angle_z, + "offset", + &(const struct wmGizmoPropertyFnParams){ + .value_get_fn = gizmo_spin_prop_angle_get, + .value_set_fn = gizmo_spin_prop_angle_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + } + + /* 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) +static void gizmo_mesh_spin_redo_draw_prepare(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - GizmoGroupData_SpinRedo *ggd = gzgroup->customdata; - if (ggd->data.op->next) { - ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context); - } - - /* Not essential, just avoids feedback loop where matrices could shift because of float precision. - * Updates in this case are also redundant. */ - bool is_modal = false; - for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { - if (gz->state & WM_GIZMO_STATE_MODAL) { - is_modal = true; - break; - } - } - if (!is_modal) { - gizmo_mesh_spin_redo_update_from_op(ggd); - } - - RegionView3D *rv3d = ED_view3d_context_rv3d(ggd->data.context); - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_c, rv3d->viewinv[2]); - { - float view_up[3]; - project_plane_normalized_v3_v3v3(view_up, ggd->data.orient_mat[2], rv3d->viewinv[2]); - if (normalize_v3(view_up) != 0.0f) { - WM_gizmo_set_matrix_rotation_from_yz_axis(ggd->rotate_view, view_up, rv3d->viewinv[2]); - } - else { - WM_gizmo_set_matrix_rotation_from_z_axis(ggd->rotate_view, rv3d->viewinv[2]); - } - } + GizmoGroupData_SpinRedo *ggd = gzgroup->customdata; + if (ggd->data.op->next) { + ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context); + } + + /* Not essential, just avoids feedback loop where matrices could shift because of float precision. + * Updates in this case are also redundant. */ + bool is_modal = false; + for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + if (gz->state & WM_GIZMO_STATE_MODAL) { + is_modal = true; + break; + } + } + if (!is_modal) { + gizmo_mesh_spin_redo_update_from_op(ggd); + } + + RegionView3D *rv3d = ED_view3d_context_rv3d(ggd->data.context); + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_c, rv3d->viewinv[2]); + { + float view_up[3]; + project_plane_normalized_v3_v3v3(view_up, ggd->data.orient_mat[2], rv3d->viewinv[2]); + if (normalize_v3(view_up) != 0.0f) { + WM_gizmo_set_matrix_rotation_from_yz_axis(ggd->rotate_view, view_up, rv3d->viewinv[2]); + } + else { + WM_gizmo_set_matrix_rotation_from_z_axis(ggd->rotate_view, rv3d->viewinv[2]); + } + } } void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt) { - gzgt->name = "Mesh Spin Redo"; - gzgt->idname = "MESH_GGT_spin_redo"; + gzgt->name = "Mesh Spin Redo"; + gzgt->idname = "MESH_GGT_spin_redo"; - gzgt->flag = WM_GIZMOGROUPTYPE_3D; + gzgt->flag = WM_GIZMOGROUPTYPE_3D; - gzgt->gzmap_params.spaceid = SPACE_VIEW3D; - gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; - gzgt->poll = gizmo_mesh_spin_redo_poll; - gzgt->setup = gizmo_mesh_spin_redo_setup; - gzgt->draw_prepare = gizmo_mesh_spin_redo_draw_prepare; + gzgt->poll = gizmo_mesh_spin_redo_poll; + gzgt->setup = gizmo_mesh_spin_redo_setup; + gzgt->draw_prepare = gizmo_mesh_spin_redo_draw_prepare; } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 3b48c4e29b0..7bee030bb46 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -48,539 +48,560 @@ #include "ED_transform.h" #include "ED_view3d.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ typedef struct { - BMEditMesh *em; - BMBackup mesh_backup; + BMEditMesh *em; + BMBackup mesh_backup; } InsetObjectStore; typedef struct { - float old_thickness; - float old_depth; - bool modify_depth; - float initial_length; - float pixel_size; /* use when mouse input is interpreted as spatial distance */ - bool is_modal; - bool shift; - float shift_amount; - float max_obj_scale; - NumInput num_input; - - InsetObjectStore *ob_store; - uint ob_store_len; - - /* modal only */ - float mcenter[2]; - void *draw_handle_pixel; - short gizmo_flag; + float old_thickness; + float old_depth; + bool modify_depth; + float initial_length; + float pixel_size; /* use when mouse input is interpreted as spatial distance */ + bool is_modal; + bool shift; + float shift_amount; + float max_obj_scale; + NumInput num_input; + + InsetObjectStore *ob_store; + uint ob_store_len; + + /* modal only */ + float mcenter[2]; + void *draw_handle_pixel; + short gizmo_flag; } InsetData; - static void edbm_inset_update_header(wmOperator *op, bContext *C) { - InsetData *opdata = op->customdata; - - const char *str = IFACE_( - "Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, " - "Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)" - ); - - char msg[UI_MAX_DRAW_STR]; - ScrArea *sa = CTX_wm_area(C); - Scene *sce = CTX_data_scene(C); - - if (sa) { - char flts_str[NUM_STR_REP_LEN * 2]; - if (hasNumInput(&opdata->num_input)) - outputNumInput(&opdata->num_input, flts_str, &sce->unit); - else { - BLI_snprintf(flts_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "thickness")); - BLI_snprintf(flts_str + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "depth")); - } - BLI_snprintf(msg, sizeof(msg), str, - flts_str, - flts_str + NUM_STR_REP_LEN, - WM_bool_as_string(opdata->modify_depth), - WM_bool_as_string(RNA_boolean_get(op->ptr, "use_outset")), - WM_bool_as_string(RNA_boolean_get(op->ptr, "use_boundary")), - WM_bool_as_string(RNA_boolean_get(op->ptr, "use_individual")) - ); - - ED_area_status_text(sa, msg); - } + InsetData *opdata = op->customdata; + + const char *str = IFACE_( + "Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, " + "Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): " + "(%s)"); + + char msg[UI_MAX_DRAW_STR]; + ScrArea *sa = CTX_wm_area(C); + Scene *sce = CTX_data_scene(C); + + if (sa) { + char flts_str[NUM_STR_REP_LEN * 2]; + if (hasNumInput(&opdata->num_input)) + outputNumInput(&opdata->num_input, flts_str, &sce->unit); + else { + BLI_snprintf(flts_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "thickness")); + BLI_snprintf( + flts_str + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "depth")); + } + BLI_snprintf(msg, + sizeof(msg), + str, + flts_str, + flts_str + NUM_STR_REP_LEN, + WM_bool_as_string(opdata->modify_depth), + WM_bool_as_string(RNA_boolean_get(op->ptr, "use_outset")), + WM_bool_as_string(RNA_boolean_get(op->ptr, "use_boundary")), + WM_bool_as_string(RNA_boolean_get(op->ptr, "use_individual"))); + + ED_area_status_text(sa, msg); + } } - static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) { - InsetData *opdata; - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - if (is_modal) { - RNA_float_set(op->ptr, "thickness", 0.0f); - RNA_float_set(op->ptr, "depth", 0.0f); - } - - op->customdata = opdata = MEM_mallocN(sizeof(InsetData), "inset_operator_data"); - - uint objects_used_len = 0; - - opdata->max_obj_scale = FLT_MIN; - - { - uint ob_store_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &ob_store_len); - opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); - for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { - Object *obedit = objects[ob_index]; - float scale = mat4_to_scale(obedit->obmat); - opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel > 0) { - opdata->ob_store[objects_used_len].em = em; - objects_used_len++; - } - } - MEM_freeN(objects); - opdata->ob_store_len = objects_used_len; - } - - opdata->old_thickness = 0.0; - opdata->old_depth = 0.0; - opdata->modify_depth = false; - opdata->shift = false; - opdata->shift_amount = 0.0f; - opdata->is_modal = is_modal; - - initNumInput(&opdata->num_input); - opdata->num_input.idx_max = 1; /* Two elements. */ - opdata->num_input.unit_sys = scene->unit.system; - opdata->num_input.unit_type[0] = B_UNIT_LENGTH; - opdata->num_input.unit_type[1] = B_UNIT_LENGTH; - - if (is_modal) { - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(opdata->ob_store[ob_index].em); - } - - opdata->draw_handle_pixel = ED_region_draw_cb_activate( - ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); - G.moving = G_TRANSFORM_EDIT; - if (v3d) { - opdata->gizmo_flag = v3d->gizmo_flag; - v3d->gizmo_flag = V3D_GIZMO_HIDE; - } - } - - return true; + InsetData *opdata; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + if (is_modal) { + RNA_float_set(op->ptr, "thickness", 0.0f); + RNA_float_set(op->ptr, "depth", 0.0f); + } + + op->customdata = opdata = MEM_mallocN(sizeof(InsetData), "inset_operator_data"); + + uint objects_used_len = 0; + + opdata->max_obj_scale = FLT_MIN; + + { + uint ob_store_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &ob_store_len); + opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); + for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { + Object *obedit = objects[ob_index]; + float scale = mat4_to_scale(obedit->obmat); + opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel > 0) { + opdata->ob_store[objects_used_len].em = em; + objects_used_len++; + } + } + MEM_freeN(objects); + opdata->ob_store_len = objects_used_len; + } + + opdata->old_thickness = 0.0; + opdata->old_depth = 0.0; + opdata->modify_depth = false; + opdata->shift = false; + opdata->shift_amount = 0.0f; + opdata->is_modal = is_modal; + + initNumInput(&opdata->num_input); + opdata->num_input.idx_max = 1; /* Two elements. */ + opdata->num_input.unit_sys = scene->unit.system; + opdata->num_input.unit_type[0] = B_UNIT_LENGTH; + opdata->num_input.unit_type[1] = B_UNIT_LENGTH; + + if (is_modal) { + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store( + opdata->ob_store[ob_index].em); + } + + opdata->draw_handle_pixel = ED_region_draw_cb_activate( + ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); + G.moving = G_TRANSFORM_EDIT; + if (v3d) { + opdata->gizmo_flag = v3d->gizmo_flag; + v3d->gizmo_flag = V3D_GIZMO_HIDE; + } + } + + return true; } static void edbm_inset_exit(bContext *C, wmOperator *op) { - InsetData *opdata; - ScrArea *sa = CTX_wm_area(C); - - opdata = op->customdata; - - if (opdata->is_modal) { - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, NULL, false); - } - ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); - if (v3d) { - v3d->gizmo_flag = opdata->gizmo_flag; - } - G.moving = 0; - } - - if (sa) { - ED_area_status_text(sa, NULL); - } - - MEM_SAFE_FREE(opdata->ob_store); - MEM_SAFE_FREE(op->customdata); + InsetData *opdata; + ScrArea *sa = CTX_wm_area(C); + + opdata = op->customdata; + + if (opdata->is_modal) { + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, NULL, false); + } + ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); + if (v3d) { + v3d->gizmo_flag = opdata->gizmo_flag; + } + G.moving = 0; + } + + if (sa) { + ED_area_status_text(sa, NULL); + } + + MEM_SAFE_FREE(opdata->ob_store); + MEM_SAFE_FREE(op->customdata); } static void edbm_inset_cancel(bContext *C, wmOperator *op) { - InsetData *opdata; + InsetData *opdata; - opdata = op->customdata; - if (opdata->is_modal) { - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true); - EDBM_update_generic(opdata->ob_store[ob_index].em, false, true); - } - } + opdata = op->customdata; + if (opdata->is_modal) { + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + EDBM_redo_state_free( + &opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true); + EDBM_update_generic(opdata->ob_store[ob_index].em, false, true); + } + } - edbm_inset_exit(C, op); + edbm_inset_exit(C, op); - /* need to force redisplay or we may still view the modified result */ - ED_region_tag_redraw(CTX_wm_region(C)); + /* need to force redisplay or we may still view the modified result */ + ED_region_tag_redraw(CTX_wm_region(C)); } static bool edbm_inset_calc(wmOperator *op) { - InsetData *opdata; - BMEditMesh *em; - BMOperator bmop; - bool changed = false; - - const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); - const bool use_even_offset = RNA_boolean_get(op->ptr, "use_even_offset"); - const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset"); - const bool use_edge_rail = RNA_boolean_get(op->ptr, "use_edge_rail"); - const float thickness = RNA_float_get(op->ptr, "thickness"); - const float depth = RNA_float_get(op->ptr, "depth"); - const bool use_outset = RNA_boolean_get(op->ptr, "use_outset"); - /* not passed onto the BMO */ - const bool use_select_inset = RNA_boolean_get(op->ptr, "use_select_inset"); - const bool use_individual = RNA_boolean_get(op->ptr, "use_individual"); - const bool use_interpolate = RNA_boolean_get(op->ptr, "use_interpolate"); - - opdata = op->customdata; - - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - em = opdata->ob_store[ob_index].em; - - if (opdata->is_modal) { - EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false); - } - - if (use_individual) { - EDBM_op_init( - em, &bmop, op, - "inset_individual faces=%hf use_even_offset=%b use_relative_offset=%b " - "use_interpolate=%b thickness=%f depth=%f", - BM_ELEM_SELECT, use_even_offset, use_relative_offset, use_interpolate, - thickness, depth); - } - else { - EDBM_op_init( - em, &bmop, op, - "inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b " - "use_interpolate=%b thickness=%f depth=%f use_outset=%b use_edge_rail=%b", - BM_ELEM_SELECT, use_boundary, use_even_offset, use_relative_offset, use_interpolate, - thickness, depth, use_outset, use_edge_rail); - - if (use_outset) { - BMO_slot_buffer_from_enabled_hflag(em->bm, &bmop, bmop.slots_in, "faces_exclude", BM_FACE, BM_ELEM_HIDDEN); - } - } - BMO_op_exec(em->bm, &bmop); - - if (use_select_inset) { - /* deselect original faces/verts */ - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - } - else { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_in, "faces", BM_FACE, BM_ELEM_SELECT, true); - } - - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - else { - EDBM_update_generic(em, true, true); - changed = true; - } - } - return changed; + InsetData *opdata; + BMEditMesh *em; + BMOperator bmop; + bool changed = false; + + const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); + const bool use_even_offset = RNA_boolean_get(op->ptr, "use_even_offset"); + const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset"); + const bool use_edge_rail = RNA_boolean_get(op->ptr, "use_edge_rail"); + const float thickness = RNA_float_get(op->ptr, "thickness"); + const float depth = RNA_float_get(op->ptr, "depth"); + const bool use_outset = RNA_boolean_get(op->ptr, "use_outset"); + /* not passed onto the BMO */ + const bool use_select_inset = RNA_boolean_get(op->ptr, "use_select_inset"); + const bool use_individual = RNA_boolean_get(op->ptr, "use_individual"); + const bool use_interpolate = RNA_boolean_get(op->ptr, "use_interpolate"); + + opdata = op->customdata; + + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + em = opdata->ob_store[ob_index].em; + + if (opdata->is_modal) { + EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false); + } + + if (use_individual) { + EDBM_op_init(em, + &bmop, + op, + "inset_individual faces=%hf use_even_offset=%b use_relative_offset=%b " + "use_interpolate=%b thickness=%f depth=%f", + BM_ELEM_SELECT, + use_even_offset, + use_relative_offset, + use_interpolate, + thickness, + depth); + } + else { + EDBM_op_init( + em, + &bmop, + op, + "inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b " + "use_interpolate=%b thickness=%f depth=%f use_outset=%b use_edge_rail=%b", + BM_ELEM_SELECT, + use_boundary, + use_even_offset, + use_relative_offset, + use_interpolate, + thickness, + depth, + use_outset, + use_edge_rail); + + if (use_outset) { + BMO_slot_buffer_from_enabled_hflag( + em->bm, &bmop, bmop.slots_in, "faces_exclude", BM_FACE, BM_ELEM_HIDDEN); + } + } + BMO_op_exec(em->bm, &bmop); + + if (use_select_inset) { + /* deselect original faces/verts */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + } + else { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_in, "faces", BM_FACE, BM_ELEM_SELECT, true); + } + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + else { + EDBM_update_generic(em, true, true); + changed = true; + } + } + return changed; } static int edbm_inset_exec(bContext *C, wmOperator *op) { - if (!edbm_inset_init(C, op, false)) { - return OPERATOR_CANCELLED; - } + if (!edbm_inset_init(C, op, false)) { + return OPERATOR_CANCELLED; + } - if (!edbm_inset_calc(op)) { - edbm_inset_exit(C, op); - return OPERATOR_CANCELLED; - } + if (!edbm_inset_calc(op)) { + edbm_inset_exit(C, op); + return OPERATOR_CANCELLED; + } - edbm_inset_exit(C, op); - return OPERATOR_FINISHED; + edbm_inset_exit(C, op); + return OPERATOR_FINISHED; } static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - InsetData *opdata; - float mlen[2]; - float center_3d[3]; - - if (!edbm_inset_init(C, op, true)) { - return OPERATOR_CANCELLED; - } - - opdata = op->customdata; - - /* initialize mouse values */ - if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, center_3d, opdata->mcenter)) { - /* in this case the tool will likely do nothing, - * ideally this will never happen and should be checked for above */ - opdata->mcenter[0] = opdata->mcenter[1] = 0; - } - mlen[0] = opdata->mcenter[0] - event->mval[0]; - mlen[1] = opdata->mcenter[1] - event->mval[1]; - opdata->initial_length = len_v2(mlen); - opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; - - edbm_inset_calc(op); - - edbm_inset_update_header(op, C); - - WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + InsetData *opdata; + float mlen[2]; + float center_3d[3]; + + if (!edbm_inset_init(C, op, true)) { + return OPERATOR_CANCELLED; + } + + opdata = op->customdata; + + /* initialize mouse values */ + if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, center_3d, opdata->mcenter)) { + /* in this case the tool will likely do nothing, + * ideally this will never happen and should be checked for above */ + opdata->mcenter[0] = opdata->mcenter[1] = 0; + } + mlen[0] = opdata->mcenter[0] - event->mval[0]; + mlen[1] = opdata->mcenter[1] - event->mval[1]; + opdata->initial_length = len_v2(mlen); + opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; + + edbm_inset_calc(op); + + edbm_inset_update_header(op, C); + + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; } static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) { - InsetData *opdata = op->customdata; - const bool has_numinput = hasNumInput(&opdata->num_input); - - /* Modal numinput active, try to handle numeric inputs first... */ - if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) { - float amounts[2] = {RNA_float_get(op->ptr, "thickness"), - RNA_float_get(op->ptr, "depth")}; - applyNumInput(&opdata->num_input, amounts); - amounts[0] = max_ff(amounts[0], 0.0f); - RNA_float_set(op->ptr, "thickness", amounts[0]); - RNA_float_set(op->ptr, "depth", amounts[1]); - - if (edbm_inset_calc(op)) { - edbm_inset_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - else { - bool handled = false; - switch (event->type) { - case ESCKEY: - case RIGHTMOUSE: - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - - case MOUSEMOVE: - if (!has_numinput) { - float mdiff[2]; - float amount; - - mdiff[0] = opdata->mcenter[0] - event->mval[0]; - mdiff[1] = opdata->mcenter[1] - event->mval[1]; - - if (opdata->modify_depth) { - amount = opdata->old_depth + - ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) / opdata->max_obj_scale; - } - else { - amount = opdata->old_thickness - - ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) / opdata->max_obj_scale; - } - - /* Fake shift-transform... */ - if (opdata->shift) - amount = (amount - opdata->shift_amount) * 0.1f + opdata->shift_amount; - - if (opdata->modify_depth) - RNA_float_set(op->ptr, "depth", amount); - else { - amount = max_ff(amount, 0.0f); - RNA_float_set(op->ptr, "thickness", amount); - } - - if (edbm_inset_calc(op)) - edbm_inset_update_header(op, C); - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } - handled = true; - } - break; - - case LEFTMOUSE: - case PADENTER: - case RETKEY: - if ((event->val == KM_PRESS) || - ((event->val == KM_RELEASE) && RNA_boolean_get(op->ptr, "release_confirm"))) - { - edbm_inset_calc(op); - edbm_inset_exit(C, op); - return OPERATOR_FINISHED; - } - break; - case LEFTSHIFTKEY: - case RIGHTSHIFTKEY: - if (event->val == KM_PRESS) { - if (opdata->modify_depth) - opdata->shift_amount = RNA_float_get(op->ptr, "depth"); - else - opdata->shift_amount = RNA_float_get(op->ptr, "thickness"); - opdata->shift = true; - handled = true; - } - else { - opdata->shift_amount = 0.0f; - opdata->shift = false; - handled = true; - } - break; - - case LEFTCTRLKEY: - case RIGHTCTRLKEY: - { - float mlen[2]; - - mlen[0] = opdata->mcenter[0] - event->mval[0]; - mlen[1] = opdata->mcenter[1] - event->mval[1]; - - if (event->val == KM_PRESS) { - opdata->old_thickness = RNA_float_get(op->ptr, "thickness"); - if (opdata->shift) - opdata->shift_amount = opdata->old_thickness; - opdata->modify_depth = true; - } - else { - opdata->old_depth = RNA_float_get(op->ptr, "depth"); - if (opdata->shift) - opdata->shift_amount = opdata->old_depth; - opdata->modify_depth = false; - } - opdata->initial_length = len_v2(mlen); - - edbm_inset_update_header(op, C); - handled = true; - break; - } - - case OKEY: - if (event->val == KM_PRESS) { - const bool use_outset = RNA_boolean_get(op->ptr, "use_outset"); - RNA_boolean_set(op->ptr, "use_outset", !use_outset); - if (edbm_inset_calc(op)) { - edbm_inset_update_header(op, C); - } - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } - handled = true; - } - break; - case BKEY: - if (event->val == KM_PRESS) { - const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); - RNA_boolean_set(op->ptr, "use_boundary", !use_boundary); - if (edbm_inset_calc(op)) { - edbm_inset_update_header(op, C); - } - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } - handled = true; - } - break; - case IKEY: - if (event->val == KM_PRESS) { - const bool use_individual = RNA_boolean_get(op->ptr, "use_individual"); - RNA_boolean_set(op->ptr, "use_individual", !use_individual); - if (edbm_inset_calc(op)) { - edbm_inset_update_header(op, C); - } - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } - handled = true; - } - break; - } - - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) { - float amounts[2] = {RNA_float_get(op->ptr, "thickness"), - RNA_float_get(op->ptr, "depth")}; - applyNumInput(&opdata->num_input, amounts); - amounts[0] = max_ff(amounts[0], 0.0f); - RNA_float_set(op->ptr, "thickness", amounts[0]); - RNA_float_set(op->ptr, "depth", amounts[1]); - - if (edbm_inset_calc(op)) { - edbm_inset_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - } - - return OPERATOR_RUNNING_MODAL; + InsetData *opdata = op->customdata; + const bool has_numinput = hasNumInput(&opdata->num_input); + + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) { + float amounts[2] = {RNA_float_get(op->ptr, "thickness"), RNA_float_get(op->ptr, "depth")}; + applyNumInput(&opdata->num_input, amounts); + amounts[0] = max_ff(amounts[0], 0.0f); + RNA_float_set(op->ptr, "thickness", amounts[0]); + RNA_float_set(op->ptr, "depth", amounts[1]); + + if (edbm_inset_calc(op)) { + edbm_inset_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + else { + bool handled = false; + switch (event->type) { + case ESCKEY: + case RIGHTMOUSE: + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; + + case MOUSEMOVE: + if (!has_numinput) { + float mdiff[2]; + float amount; + + mdiff[0] = opdata->mcenter[0] - event->mval[0]; + mdiff[1] = opdata->mcenter[1] - event->mval[1]; + + if (opdata->modify_depth) { + amount = opdata->old_depth + + ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) / + opdata->max_obj_scale; + } + else { + amount = opdata->old_thickness - + ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) / + opdata->max_obj_scale; + } + + /* Fake shift-transform... */ + if (opdata->shift) + amount = (amount - opdata->shift_amount) * 0.1f + opdata->shift_amount; + + if (opdata->modify_depth) + RNA_float_set(op->ptr, "depth", amount); + else { + amount = max_ff(amount, 0.0f); + RNA_float_set(op->ptr, "thickness", amount); + } + + if (edbm_inset_calc(op)) + edbm_inset_update_header(op, C); + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; + } + handled = true; + } + break; + + case LEFTMOUSE: + case PADENTER: + case RETKEY: + if ((event->val == KM_PRESS) || + ((event->val == KM_RELEASE) && RNA_boolean_get(op->ptr, "release_confirm"))) { + edbm_inset_calc(op); + edbm_inset_exit(C, op); + return OPERATOR_FINISHED; + } + break; + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + if (event->val == KM_PRESS) { + if (opdata->modify_depth) + opdata->shift_amount = RNA_float_get(op->ptr, "depth"); + else + opdata->shift_amount = RNA_float_get(op->ptr, "thickness"); + opdata->shift = true; + handled = true; + } + else { + opdata->shift_amount = 0.0f; + opdata->shift = false; + handled = true; + } + break; + + case LEFTCTRLKEY: + case RIGHTCTRLKEY: { + float mlen[2]; + + mlen[0] = opdata->mcenter[0] - event->mval[0]; + mlen[1] = opdata->mcenter[1] - event->mval[1]; + + if (event->val == KM_PRESS) { + opdata->old_thickness = RNA_float_get(op->ptr, "thickness"); + if (opdata->shift) + opdata->shift_amount = opdata->old_thickness; + opdata->modify_depth = true; + } + else { + opdata->old_depth = RNA_float_get(op->ptr, "depth"); + if (opdata->shift) + opdata->shift_amount = opdata->old_depth; + opdata->modify_depth = false; + } + opdata->initial_length = len_v2(mlen); + + edbm_inset_update_header(op, C); + handled = true; + break; + } + + case OKEY: + if (event->val == KM_PRESS) { + const bool use_outset = RNA_boolean_get(op->ptr, "use_outset"); + RNA_boolean_set(op->ptr, "use_outset", !use_outset); + if (edbm_inset_calc(op)) { + edbm_inset_update_header(op, C); + } + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; + } + handled = true; + } + break; + case BKEY: + if (event->val == KM_PRESS) { + const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); + RNA_boolean_set(op->ptr, "use_boundary", !use_boundary); + if (edbm_inset_calc(op)) { + edbm_inset_update_header(op, C); + } + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; + } + handled = true; + } + break; + case IKEY: + if (event->val == KM_PRESS) { + const bool use_individual = RNA_boolean_get(op->ptr, "use_individual"); + RNA_boolean_set(op->ptr, "use_individual", !use_individual); + if (edbm_inset_calc(op)) { + edbm_inset_update_header(op, C); + } + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; + } + handled = true; + } + break; + } + + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) { + float amounts[2] = {RNA_float_get(op->ptr, "thickness"), RNA_float_get(op->ptr, "depth")}; + applyNumInput(&opdata->num_input, amounts); + amounts[0] = max_ff(amounts[0], 0.0f); + RNA_float_set(op->ptr, "thickness", amounts[0]); + RNA_float_set(op->ptr, "depth", amounts[1]); + + if (edbm_inset_calc(op)) { + edbm_inset_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + } + + return OPERATOR_RUNNING_MODAL; } - void MESH_OT_inset(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Inset Faces"; - ot->idname = "MESH_OT_inset"; - ot->description = "Inset new faces into selected faces"; - - /* api callbacks */ - ot->invoke = edbm_inset_invoke; - ot->modal = edbm_inset_modal; - ot->exec = edbm_inset_exec; - ot->cancel = edbm_inset_cancel; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; - - /* properties */ - RNA_def_boolean( - ot->srna, "use_boundary", - true, "Boundary", "Inset face boundaries"); - RNA_def_boolean( - ot->srna, "use_even_offset", - true, "Offset Even", "Scale the offset to give more even thickness"); - RNA_def_boolean( - ot->srna, "use_relative_offset", - false, "Offset Relative", "Scale the offset by surrounding geometry"); - RNA_def_boolean( - ot->srna, "use_edge_rail", - false, "Edge Rail", "Inset the region along existing edges"); - - prop = RNA_def_float_distance(ot->srna, "thickness", 0.0f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f); - /* use 1 rather then 10 for max else dragging the button moves too far */ - RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4); - - prop = RNA_def_float_distance(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f); - RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4); - - RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset"); - RNA_def_boolean(ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces"); - RNA_def_boolean(ot->srna, "use_individual", false, "Individual", "Individual Face Inset"); - RNA_def_boolean(ot->srna, "use_interpolate", true, "Interpolate", "Blend face data across the inset"); - - prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Inset Faces"; + ot->idname = "MESH_OT_inset"; + ot->description = "Inset new faces into selected faces"; + + /* api callbacks */ + ot->invoke = edbm_inset_invoke; + ot->modal = edbm_inset_modal; + ot->exec = edbm_inset_exec; + ot->cancel = edbm_inset_cancel; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; + + /* properties */ + RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries"); + RNA_def_boolean(ot->srna, + "use_even_offset", + true, + "Offset Even", + "Scale the offset to give more even thickness"); + RNA_def_boolean(ot->srna, + "use_relative_offset", + false, + "Offset Relative", + "Scale the offset by surrounding geometry"); + RNA_def_boolean( + ot->srna, "use_edge_rail", false, "Edge Rail", "Inset the region along existing edges"); + + prop = RNA_def_float_distance( + ot->srna, "thickness", 0.0f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f); + /* use 1 rather then 10 for max else dragging the button moves too far */ + RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4); + + prop = RNA_def_float_distance( + ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f); + RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4); + + RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset"); + RNA_def_boolean( + ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces"); + RNA_def_boolean(ot->srna, "use_individual", false, "Individual", "Individual Face Inset"); + RNA_def_boolean( + ot->srna, "use_interpolate", true, "Interpolate", "Blend face data across the inset"); + + prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index c500683a228..06e2ef6e304 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -44,12 +44,11 @@ #include "intern/bmesh_private.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ #include "tools/bmesh_intersect.h" #include "tools/bmesh_separate.h" - /* detect isolated holes and fill them */ #define USE_NET_ISLAND_CONNECT @@ -58,12 +57,12 @@ */ static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data)) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - return 0; - } - else { - return -1; - } + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 0; + } + else { + return -1; + } } /** @@ -71,15 +70,15 @@ static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data)) */ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) { - if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - return -1; - } - else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - return 1; - } - else { - return 0; - } + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + return -1; + } + else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 1; + } + else { + return 0; + } } /** @@ -88,15 +87,15 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) */ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data)) { - if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - return -1; - } - else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - return 0; - } - else { - return 1; - } + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + return -1; + } + else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 0; + } + else { + return 1; + } } /** @@ -104,22 +103,21 @@ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data)) */ static void edbm_intersect_select(BMEditMesh *em) { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - - if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { - BMIter iter; - BMEdge *e; + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BM_edge_select_set(em->bm, e, true); - } - } - } + if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { + BMIter iter; + BMEdge *e; - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BM_edge_select_set(em->bm, e, true); + } + } + } + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); } /* -------------------------------------------------------------------- */ @@ -130,138 +128,148 @@ static void edbm_intersect_select(BMEditMesh *em) */ enum { - ISECT_SEL = 0, - ISECT_SEL_UNSEL = 1, + ISECT_SEL = 0, + ISECT_SEL_UNSEL = 1, }; enum { - ISECT_SEPARATE_ALL = 0, - ISECT_SEPARATE_CUT = 1, - ISECT_SEPARATE_NONE = 2, + ISECT_SEPARATE_ALL = 0, + ISECT_SEPARATE_CUT = 1, + ISECT_SEPARATE_NONE = 2, }; static int edbm_intersect_exec(bContext *C, wmOperator *op) { - const int mode = RNA_enum_get(op->ptr, "mode"); - int (*test_fn)(BMFace *, void *); - bool use_separate_all = false; - bool use_separate_cut = false; - const int separate_mode = RNA_enum_get(op->ptr, "separate_mode"); - const float eps = RNA_float_get(op->ptr, "threshold"); - bool use_self; - bool has_isect; - - switch (mode) { - case ISECT_SEL: - test_fn = bm_face_isect_self; - use_self = true; - break; - default: /* ISECT_SEL_UNSEL */ - test_fn = bm_face_isect_pair; - use_self = false; - break; - } - - switch (separate_mode) { - case ISECT_SEPARATE_ALL: - use_separate_all = true; - break; - case ISECT_SEPARATE_CUT: - if (use_self == false) { - use_separate_cut = true; - } - else { - /* we could support this but would require more advanced logic inside 'BM_mesh_intersect' - * for now just separate all */ - use_separate_all = true; - } - break; - default: /* ISECT_SEPARATE_NONE */ - break; - } - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - uint isect_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totfacesel == 0) { - continue; - } - - has_isect = BM_mesh_intersect( - em->bm, - em->looptris, em->tottri, - test_fn, NULL, - use_self, use_separate_all, true, true, true, true, - -1, - eps); - - if (use_separate_cut) { - /* detach selected/un-selected faces */ - BM_mesh_separate_faces( - em->bm, - BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT)); - } - - if (has_isect) { - edbm_intersect_select(em); - } - else { - isect_len++; - } - } - MEM_freeN(objects); - - if (isect_len == objects_len) { - BKE_report(op->reports, RPT_WARNING, "No intersections found"); - } - return OPERATOR_FINISHED; + const int mode = RNA_enum_get(op->ptr, "mode"); + int (*test_fn)(BMFace *, void *); + bool use_separate_all = false; + bool use_separate_cut = false; + const int separate_mode = RNA_enum_get(op->ptr, "separate_mode"); + const float eps = RNA_float_get(op->ptr, "threshold"); + bool use_self; + bool has_isect; + + switch (mode) { + case ISECT_SEL: + test_fn = bm_face_isect_self; + use_self = true; + break; + default: /* ISECT_SEL_UNSEL */ + test_fn = bm_face_isect_pair; + use_self = false; + break; + } + + switch (separate_mode) { + case ISECT_SEPARATE_ALL: + use_separate_all = true; + break; + case ISECT_SEPARATE_CUT: + if (use_self == false) { + use_separate_cut = true; + } + else { + /* we could support this but would require more advanced logic inside 'BM_mesh_intersect' + * for now just separate all */ + use_separate_all = true; + } + break; + default: /* ISECT_SEPARATE_NONE */ + break; + } + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + uint isect_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totfacesel == 0) { + continue; + } + + has_isect = BM_mesh_intersect(em->bm, + em->looptris, + em->tottri, + test_fn, + NULL, + use_self, + use_separate_all, + true, + true, + true, + true, + -1, + eps); + + if (use_separate_cut) { + /* detach selected/un-selected faces */ + BM_mesh_separate_faces( + em->bm, BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT)); + } + + if (has_isect) { + edbm_intersect_select(em); + } + else { + isect_len++; + } + } + MEM_freeN(objects); + + if (isect_len == objects_len) { + BKE_report(op->reports, RPT_WARNING, "No intersections found"); + } + return OPERATOR_FINISHED; } void MESH_OT_intersect(struct wmOperatorType *ot) { - static const EnumPropertyItem isect_mode_items[] = { - {ISECT_SEL, "SELECT", 0, "Self Intersect", - "Self intersect selected faces"}, - {ISECT_SEL_UNSEL, "SELECT_UNSELECT", 0, "Selected/Unselected", - "Intersect selected with unselected faces"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem isect_separate_items[] = { - {ISECT_SEPARATE_ALL, "ALL", 0, "All", - "Separate all geometry from intersections"}, - {ISECT_SEPARATE_CUT, "CUT", 0, "Cut", - "Cut into geometry keeping each side separate (Selected/Unselected only)"}, - {ISECT_SEPARATE_NONE, "NONE", 0, "Merge", - "Merge all geometry from the intersection"}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Intersect (Knife)"; - ot->description = "Cut an intersection into faces"; - ot->idname = "MESH_OT_intersect"; - - /* api callbacks */ - ot->exec = edbm_intersect_exec; - ot->poll = ED_operator_editmesh; - - /* props */ - RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", ""); - RNA_def_enum(ot->srna, "separate_mode", isect_separate_items, ISECT_SEPARATE_CUT, "Separate Mode", ""); - RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + static const EnumPropertyItem isect_mode_items[] = { + {ISECT_SEL, "SELECT", 0, "Self Intersect", "Self intersect selected faces"}, + {ISECT_SEL_UNSEL, + "SELECT_UNSELECT", + 0, + "Selected/Unselected", + "Intersect selected with unselected faces"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem isect_separate_items[] = { + {ISECT_SEPARATE_ALL, "ALL", 0, "All", "Separate all geometry from intersections"}, + {ISECT_SEPARATE_CUT, + "CUT", + 0, + "Cut", + "Cut into geometry keeping each side separate (Selected/Unselected only)"}, + {ISECT_SEPARATE_NONE, "NONE", 0, "Merge", "Merge all geometry from the intersection"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Intersect (Knife)"; + ot->description = "Cut an intersection into faces"; + ot->idname = "MESH_OT_intersect"; + + /* api callbacks */ + ot->exec = edbm_intersect_exec; + ot->poll = ED_operator_editmesh; + + /* props */ + RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", ""); + RNA_def_enum( + ot->srna, "separate_mode", isect_separate_items, ISECT_SEPARATE_CUT, "Separate Mode", ""); + RNA_def_float_distance( + ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ - /* -------------------------------------------------------------------- */ /* Boolean (a kind of intersect) */ @@ -275,74 +283,90 @@ void MESH_OT_intersect(struct wmOperatorType *ot) static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) { - const int boolean_operation = RNA_enum_get(op->ptr, "operation"); - bool use_swap = RNA_boolean_get(op->ptr, "use_swap"); - const float eps = RNA_float_get(op->ptr, "threshold"); - int (*test_fn)(BMFace *, void *); - bool has_isect; - - test_fn = use_swap ? bm_face_isect_pair_swap : bm_face_isect_pair; - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - uint isect_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totfacesel == 0) { - continue; - } - - has_isect = BM_mesh_intersect( - em->bm, - em->looptris, em->tottri, - test_fn, NULL, - false, false, true, true, false, true, - boolean_operation, - eps); - - - if (has_isect) { - edbm_intersect_select(em); - } - else { - isect_len++; - } - } - MEM_freeN(objects); - - if (isect_len == objects_len) { - BKE_report(op->reports, RPT_WARNING, "No intersections found"); - } - return OPERATOR_FINISHED; + const int boolean_operation = RNA_enum_get(op->ptr, "operation"); + bool use_swap = RNA_boolean_get(op->ptr, "use_swap"); + const float eps = RNA_float_get(op->ptr, "threshold"); + int (*test_fn)(BMFace *, void *); + bool has_isect; + + test_fn = use_swap ? bm_face_isect_pair_swap : bm_face_isect_pair; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + uint isect_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totfacesel == 0) { + continue; + } + + has_isect = BM_mesh_intersect(em->bm, + em->looptris, + em->tottri, + test_fn, + NULL, + false, + false, + true, + true, + false, + true, + boolean_operation, + eps); + + if (has_isect) { + edbm_intersect_select(em); + } + else { + isect_len++; + } + } + MEM_freeN(objects); + + if (isect_len == objects_len) { + BKE_report(op->reports, RPT_WARNING, "No intersections found"); + } + return OPERATOR_FINISHED; } void MESH_OT_intersect_boolean(struct wmOperatorType *ot) { - static const EnumPropertyItem isect_boolean_operation_items[] = { - {BMESH_ISECT_BOOLEAN_ISECT, "INTERSECT", 0, "Intersect", ""}, - {BMESH_ISECT_BOOLEAN_UNION, "UNION", 0, "Union", ""}, - {BMESH_ISECT_BOOLEAN_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Intersect (Boolean)"; - ot->description = "Cut solid geometry from selected to unselected"; - ot->idname = "MESH_OT_intersect_boolean"; - - /* api callbacks */ - ot->exec = edbm_intersect_boolean_exec; - ot->poll = ED_operator_editmesh; - - /* props */ - RNA_def_enum(ot->srna, "operation", isect_boolean_operation_items, BMESH_ISECT_BOOLEAN_DIFFERENCE, "Boolean", ""); - RNA_def_boolean(ot->srna, "use_swap", false, "Swap", "Use with difference intersection to swap which side is kept"); - RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + static const EnumPropertyItem isect_boolean_operation_items[] = { + {BMESH_ISECT_BOOLEAN_ISECT, "INTERSECT", 0, "Intersect", ""}, + {BMESH_ISECT_BOOLEAN_UNION, "UNION", 0, "Union", ""}, + {BMESH_ISECT_BOOLEAN_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Intersect (Boolean)"; + ot->description = "Cut solid geometry from selected to unselected"; + ot->idname = "MESH_OT_intersect_boolean"; + + /* api callbacks */ + ot->exec = edbm_intersect_boolean_exec; + ot->poll = ED_operator_editmesh; + + /* props */ + RNA_def_enum(ot->srna, + "operation", + isect_boolean_operation_items, + BMESH_ISECT_BOOLEAN_DIFFERENCE, + "Boolean", + ""); + RNA_def_boolean(ot->srna, + "use_swap", + false, + "Swap", + "Use with difference intersection to swap which side is kept"); + RNA_def_float_distance( + ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -353,88 +377,82 @@ void MESH_OT_intersect_boolean(struct wmOperatorType *ot) /** \name Face/Edge Split * \{ */ -static void bm_face_split_by_edges( - BMesh *bm, BMFace *f, const char hflag, - /* reusable memory buffer */ - BLI_Buffer *edge_net_temp_buf) +static void bm_face_split_by_edges(BMesh *bm, + BMFace *f, + const char hflag, + /* reusable memory buffer */ + BLI_Buffer *edge_net_temp_buf) { - const int f_index = BM_elem_index_get(f); - - BMLoop *l_iter; - BMLoop *l_first; - BMVert *v; - - BMFace **face_arr; - int face_arr_len; - - /* likely this will stay very small - * all verts pushed into this stack _must_ have their previous edges set! */ - BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *); - BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *); - - BLI_assert(edge_net_temp_buf->count == 0); - - /* collect all edges */ - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BMIter iter; - BMEdge *e; - - BM_ITER_ELEM (e, &iter, l_iter->v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e, hflag) && - (BM_elem_index_get(e) == f_index)) - { - v = BM_edge_other_vert(e, l_iter->v); - v->e = e; - - BLI_SMALLSTACK_PUSH(vert_stack, v); - BLI_buffer_append(edge_net_temp_buf, BMEdge *, e); - } - } - } while ((l_iter = l_iter->next) != l_first); - - - - /* now assign all */ - /* pop free values into the next stack */ - while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { - BMIter eiter; - BMEdge *e_next; - - BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e_next, hflag) && - (BM_elem_index_get(e_next) == -1)) - { - BMVert *v_next; - v_next = BM_edge_other_vert(e_next, v); - BM_elem_index_set(e_next, f_index); - BLI_SMALLSTACK_PUSH(vert_stack_next, v_next); - BLI_buffer_append(edge_net_temp_buf, BMEdge *, e_next); - } - } - - if (BLI_SMALLSTACK_IS_EMPTY(vert_stack)) { - BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next); - } - } - - BM_face_split_edgenet( - bm, f, edge_net_temp_buf->data, edge_net_temp_buf->count, - &face_arr, &face_arr_len); - - BLI_buffer_clear(edge_net_temp_buf); - - if (face_arr_len) { - int i; - for (i = 0; i < face_arr_len; i++) { - BM_face_select_set(bm, face_arr[i], true); - BM_elem_flag_disable(face_arr[i], hflag); - } - } - - if (face_arr) { - MEM_freeN(face_arr); - } + const int f_index = BM_elem_index_get(f); + + BMLoop *l_iter; + BMLoop *l_first; + BMVert *v; + + BMFace **face_arr; + int face_arr_len; + + /* likely this will stay very small + * all verts pushed into this stack _must_ have their previous edges set! */ + BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *); + BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *); + + BLI_assert(edge_net_temp_buf->count == 0); + + /* collect all edges */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMIter iter; + BMEdge *e; + + BM_ITER_ELEM (e, &iter, l_iter->v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e, hflag) && (BM_elem_index_get(e) == f_index)) { + v = BM_edge_other_vert(e, l_iter->v); + v->e = e; + + BLI_SMALLSTACK_PUSH(vert_stack, v); + BLI_buffer_append(edge_net_temp_buf, BMEdge *, e); + } + } + } while ((l_iter = l_iter->next) != l_first); + + /* now assign all */ + /* pop free values into the next stack */ + while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { + BMIter eiter; + BMEdge *e_next; + + BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_next, hflag) && (BM_elem_index_get(e_next) == -1)) { + BMVert *v_next; + v_next = BM_edge_other_vert(e_next, v); + BM_elem_index_set(e_next, f_index); + BLI_SMALLSTACK_PUSH(vert_stack_next, v_next); + BLI_buffer_append(edge_net_temp_buf, BMEdge *, e_next); + } + } + + if (BLI_SMALLSTACK_IS_EMPTY(vert_stack)) { + BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next); + } + } + + BM_face_split_edgenet( + bm, f, edge_net_temp_buf->data, edge_net_temp_buf->count, &face_arr, &face_arr_len); + + BLI_buffer_clear(edge_net_temp_buf); + + if (face_arr_len) { + int i; + for (i = 0; i < face_arr_len; i++) { + BM_face_select_set(bm, face_arr[i], true); + BM_elem_flag_disable(face_arr[i], hflag); + } + } + + if (face_arr) { + MEM_freeN(face_arr); + } } /** @@ -443,113 +461,114 @@ static void bm_face_split_by_edges( */ static bool bm_vert_in_faces_radial(BMVert *v, BMEdge *e_radial, BMFace *f_ignore) { - BLI_assert(BM_vert_in_face(v, f_ignore) == false); - if (e_radial->l) { - BMLoop *l_iter = e_radial->l; - do { - if (l_iter->f != f_ignore) { - if (BM_vert_in_face(v, l_iter->f)) { - return true; - } - } - } while ((l_iter = l_iter->radial_next) != e_radial->l); - } - return false; + BLI_assert(BM_vert_in_face(v, f_ignore) == false); + if (e_radial->l) { + BMLoop *l_iter = e_radial->l; + do { + if (l_iter->f != f_ignore) { + if (BM_vert_in_face(v, l_iter->f)) { + return true; + } + } + } while ((l_iter = l_iter->radial_next) != e_radial->l); + } + return false; } #ifdef USE_NET_ISLAND_CONNECT struct LinkBase { - LinkNode *list; - unsigned int list_len; + LinkNode *list; + unsigned int list_len; }; -static void ghash_insert_face_edge_link( - GHash *gh, BMFace *f_key, BMEdge *e_val, - MemArena *mem_arena) +static void ghash_insert_face_edge_link(GHash *gh, + BMFace *f_key, + BMEdge *e_val, + MemArena *mem_arena) { - void **ls_base_p; - struct LinkBase *ls_base; - LinkNode *ls; - - if (!BLI_ghash_ensure_p(gh, f_key, &ls_base_p)) { - ls_base = *ls_base_p = BLI_memarena_alloc(mem_arena, sizeof(*ls_base)); - ls_base->list = NULL; - ls_base->list_len = 0; - } - else { - ls_base = *ls_base_p; - } - - ls = BLI_memarena_alloc(mem_arena, sizeof(*ls)); - ls->next = ls_base->list; - ls->link = e_val; - ls_base->list = ls; - ls_base->list_len += 1; + void **ls_base_p; + struct LinkBase *ls_base; + LinkNode *ls; + + if (!BLI_ghash_ensure_p(gh, f_key, &ls_base_p)) { + ls_base = *ls_base_p = BLI_memarena_alloc(mem_arena, sizeof(*ls_base)); + ls_base->list = NULL; + ls_base->list_len = 0; + } + else { + ls_base = *ls_base_p; + } + + ls = BLI_memarena_alloc(mem_arena, sizeof(*ls)); + ls->next = ls_base->list; + ls->link = e_val; + ls_base->list = ls; + ls_base->list_len += 1; } static int bm_edge_sort_length_cb(const void *e_a_v, const void *e_b_v) { - const float val_a = -BM_edge_calc_length_squared(*((BMEdge **)e_a_v)); - const float val_b = -BM_edge_calc_length_squared(*((BMEdge **)e_b_v)); - - if (val_a > val_b) return 1; - else if (val_a < val_b) return -1; - else return 0; + const float val_a = -BM_edge_calc_length_squared(*((BMEdge **)e_a_v)); + const float val_b = -BM_edge_calc_length_squared(*((BMEdge **)e_b_v)); + + if (val_a > val_b) + return 1; + else if (val_a < val_b) + return -1; + else + return 0; } static void bm_face_split_by_edges_island_connect( - BMesh *bm, BMFace *f, - LinkNode *e_link, const int e_link_len, - MemArena *mem_arena_edgenet) + BMesh *bm, BMFace *f, LinkNode *e_link, const int e_link_len, MemArena *mem_arena_edgenet) { - BMEdge **edge_arr = BLI_memarena_alloc(mem_arena_edgenet, sizeof(*edge_arr) * e_link_len); - int edge_arr_len = 0; - - while (e_link) { - edge_arr[edge_arr_len++] = e_link->link; - e_link = e_link->next; - } - - { - unsigned int edge_arr_holes_len; - BMEdge **edge_arr_holes; - if (BM_face_split_edgenet_connect_islands( - bm, f, - edge_arr, e_link_len, - true, - mem_arena_edgenet, - &edge_arr_holes, &edge_arr_holes_len)) - { - edge_arr_len = edge_arr_holes_len; - edge_arr = edge_arr_holes; /* owned by the arena */ - } - } - - BM_face_split_edgenet( - bm, f, edge_arr, edge_arr_len, - NULL, NULL); - - for (int i = e_link_len; i < edge_arr_len; i++) { - BM_edge_select_set(bm, edge_arr[i], true); - } - - if (e_link_len != edge_arr_len) { - /* connecting partial islands can add redundant edges - * sort before removal to give deterministic outcome */ - qsort(edge_arr, edge_arr_len - e_link_len, sizeof(*edge_arr), bm_edge_sort_length_cb); - for (int i = e_link_len; i < edge_arr_len; i++) { - BMFace *f_pair[2]; - if (BM_edge_face_pair(edge_arr[i], &f_pair[0], &f_pair[1])) { - if (BM_face_share_vert_count(f_pair[0], f_pair[1]) == 2) { - BMFace *f_new = BM_faces_join(bm, f_pair, 2, true); - if (f_new) { - BM_face_select_set(bm, f_new, true); - } - } - } - } - } + BMEdge **edge_arr = BLI_memarena_alloc(mem_arena_edgenet, sizeof(*edge_arr) * e_link_len); + int edge_arr_len = 0; + + while (e_link) { + edge_arr[edge_arr_len++] = e_link->link; + e_link = e_link->next; + } + + { + unsigned int edge_arr_holes_len; + BMEdge **edge_arr_holes; + if (BM_face_split_edgenet_connect_islands(bm, + f, + edge_arr, + e_link_len, + true, + mem_arena_edgenet, + &edge_arr_holes, + &edge_arr_holes_len)) { + edge_arr_len = edge_arr_holes_len; + edge_arr = edge_arr_holes; /* owned by the arena */ + } + } + + BM_face_split_edgenet(bm, f, edge_arr, edge_arr_len, NULL, NULL); + + for (int i = e_link_len; i < edge_arr_len; i++) { + BM_edge_select_set(bm, edge_arr[i], true); + } + + if (e_link_len != edge_arr_len) { + /* connecting partial islands can add redundant edges + * sort before removal to give deterministic outcome */ + qsort(edge_arr, edge_arr_len - e_link_len, sizeof(*edge_arr), bm_edge_sort_length_cb); + for (int i = e_link_len; i < edge_arr_len; i++) { + BMFace *f_pair[2]; + if (BM_edge_face_pair(edge_arr[i], &f_pair[0], &f_pair[1])) { + if (BM_face_share_vert_count(f_pair[0], f_pair[1]) == 2) { + BMFace *f_new = BM_faces_join(bm, f_pair, 2, true); + if (f_new) { + BM_face_select_set(bm, f_new, true); + } + } + } + } + } } /** @@ -570,394 +589,389 @@ static void bm_face_split_by_edges_island_connect( * * \note Currently we don't snap to verts or split chains by verts on-edges. */ -static BMEdge *bm_face_split_edge_find( - BMEdge *e_a, BMFace *f_a, BMVert *v_pivot, BMFace **ftable, const int ftable_len, - float r_v_pivot_co[3], float *r_v_pivot_fac) +static BMEdge *bm_face_split_edge_find(BMEdge *e_a, + BMFace *f_a, + BMVert *v_pivot, + BMFace **ftable, + const int ftable_len, + float r_v_pivot_co[3], + float *r_v_pivot_fac) { - const int f_a_index = BM_elem_index_get(e_a); - bool found_other_self = false; - int found_other_face = 0; - BLI_SMALLSTACK_DECLARE(face_stack, BMFace *); - - /* loop over surrounding edges to check if we're part of a chain or a delimiter vertex */ - BMEdge *e_b = v_pivot->e; - do { - if (e_b != e_a) { - const int f_b_index = BM_elem_index_get(e_b); - if (f_b_index == f_a_index) { - /* not an endpoint */ - found_other_self = true; - } - else if (f_b_index != -1) { - BLI_assert(f_b_index < ftable_len); - UNUSED_VARS_NDEBUG(ftable_len); - - /* 'v_pivot' spans 2+ faces, - * tag to ensure we pick an edge that includes this face */ - BMFace *f_b = ftable[f_b_index]; - if (!BM_elem_flag_test(f_b, BM_ELEM_INTERNAL_TAG)) { - BM_elem_flag_enable(f_b, BM_ELEM_INTERNAL_TAG); - BLI_SMALLSTACK_PUSH(face_stack, f_b); - found_other_face++; - } - } - } - } while ((e_b = BM_DISK_EDGE_NEXT(e_b, v_pivot)) != v_pivot->e); - - BMEdge *e_split = NULL; - - /* if we have no others or the other edge is outside this face, - * we're an endpoint to connect to a boundary */ - if ((found_other_self == false) || found_other_face) { - - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f_a); - float dist_best_sq = FLT_MAX; - - do { - float v_pivot_co_test[3]; - float v_pivot_fac = line_point_factor_v3(v_pivot->co, l_iter->e->v1->co, l_iter->e->v2->co); - CLAMP(v_pivot_fac, 0.0f, 1.0f); - interp_v3_v3v3(v_pivot_co_test, l_iter->e->v1->co, l_iter->e->v2->co, v_pivot_fac); - - float dist_test_sq = len_squared_v3v3(v_pivot_co_test, v_pivot->co); - if ((dist_test_sq < dist_best_sq) || (e_split == NULL)) { - bool ok = true; - - if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) || - BM_edge_exists(v_pivot, l_iter->e->v2))) - { - /* very unlikely but will cause complications splicing the verts together, - * so just skip this case */ - ok = false; - } - else if (found_other_face) { - /* double check that _all_ the faces used by v_pivot's edges are attached - * to this edge otherwise don't attempt the split since it will give - * non-deterministic results */ - BMLoop *l_radial_iter = l_iter->radial_next; - int other_face_shared = 0; - if (l_radial_iter != l_iter) { - do { - if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_INTERNAL_TAG)) { - other_face_shared++; - } - } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); - } - if (other_face_shared != found_other_face) { - ok = false; - } - } - - if (ok) { - e_split = l_iter->e; - dist_best_sq = dist_test_sq; - copy_v3_v3(r_v_pivot_co, v_pivot_co_test); - *r_v_pivot_fac = v_pivot_fac; - } - } - } while ((l_iter = l_iter->next) != l_first); - } - - { - /* reset the flag, for future use */ - BMFace *f; - while ((f = BLI_SMALLSTACK_POP(face_stack))) { - BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); - } - } - - return e_split; + const int f_a_index = BM_elem_index_get(e_a); + bool found_other_self = false; + int found_other_face = 0; + BLI_SMALLSTACK_DECLARE(face_stack, BMFace *); + + /* loop over surrounding edges to check if we're part of a chain or a delimiter vertex */ + BMEdge *e_b = v_pivot->e; + do { + if (e_b != e_a) { + const int f_b_index = BM_elem_index_get(e_b); + if (f_b_index == f_a_index) { + /* not an endpoint */ + found_other_self = true; + } + else if (f_b_index != -1) { + BLI_assert(f_b_index < ftable_len); + UNUSED_VARS_NDEBUG(ftable_len); + + /* 'v_pivot' spans 2+ faces, + * tag to ensure we pick an edge that includes this face */ + BMFace *f_b = ftable[f_b_index]; + if (!BM_elem_flag_test(f_b, BM_ELEM_INTERNAL_TAG)) { + BM_elem_flag_enable(f_b, BM_ELEM_INTERNAL_TAG); + BLI_SMALLSTACK_PUSH(face_stack, f_b); + found_other_face++; + } + } + } + } while ((e_b = BM_DISK_EDGE_NEXT(e_b, v_pivot)) != v_pivot->e); + + BMEdge *e_split = NULL; + + /* if we have no others or the other edge is outside this face, + * we're an endpoint to connect to a boundary */ + if ((found_other_self == false) || found_other_face) { + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f_a); + float dist_best_sq = FLT_MAX; + + do { + float v_pivot_co_test[3]; + float v_pivot_fac = line_point_factor_v3(v_pivot->co, l_iter->e->v1->co, l_iter->e->v2->co); + CLAMP(v_pivot_fac, 0.0f, 1.0f); + interp_v3_v3v3(v_pivot_co_test, l_iter->e->v1->co, l_iter->e->v2->co, v_pivot_fac); + + float dist_test_sq = len_squared_v3v3(v_pivot_co_test, v_pivot->co); + if ((dist_test_sq < dist_best_sq) || (e_split == NULL)) { + bool ok = true; + + if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) || + BM_edge_exists(v_pivot, l_iter->e->v2))) { + /* very unlikely but will cause complications splicing the verts together, + * so just skip this case */ + ok = false; + } + else if (found_other_face) { + /* double check that _all_ the faces used by v_pivot's edges are attached + * to this edge otherwise don't attempt the split since it will give + * non-deterministic results */ + BMLoop *l_radial_iter = l_iter->radial_next; + int other_face_shared = 0; + if (l_radial_iter != l_iter) { + do { + if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_INTERNAL_TAG)) { + other_face_shared++; + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); + } + if (other_face_shared != found_other_face) { + ok = false; + } + } + + if (ok) { + e_split = l_iter->e; + dist_best_sq = dist_test_sq; + copy_v3_v3(r_v_pivot_co, v_pivot_co_test); + *r_v_pivot_fac = v_pivot_fac; + } + } + } while ((l_iter = l_iter->next) != l_first); + } + + { + /* reset the flag, for future use */ + BMFace *f; + while ((f = BLI_SMALLSTACK_POP(face_stack))) { + BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); + } + } + + return e_split; } -#endif /* USE_NET_ISLAND_CONNECT */ - +#endif /* USE_NET_ISLAND_CONNECT */ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op)) { - const char hflag = BM_ELEM_TAG; - - BMEdge *e; - BMIter iter; - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if ((bm->totedgesel == 0) || - (bm->totfacesel == 0)) - { - continue; - } - - BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); - - { - BMVert *v; - BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(v, hflag); - } - } - - /* edge index is set to -1 then used to associate them with faces */ - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { - BM_elem_flag_enable(e, hflag); - - BM_elem_flag_enable(e->v1, hflag); - BM_elem_flag_enable(e->v2, hflag); - - } - else { - BM_elem_flag_disable(e, hflag); - } - BM_elem_index_set(e, -1); /* set_dirty */ - } - bm->elem_index_dirty |= BM_EDGE; - - { - BMFace *f; - int i; - BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_elem_flag_enable(f, hflag); - } - else { - BM_elem_flag_disable(f, hflag); - } - BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); - BM_elem_index_set(f, i); /* set_ok */ - } - } - bm->elem_index_dirty &= ~BM_FACE; - - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, hflag)) { - BMIter viter; - BMVert *v; - BM_ITER_ELEM(v, &viter, e, BM_VERTS_OF_EDGE) { - BMIter liter; - BMLoop *l; - - unsigned int loop_stack_len; - BMLoop *l_best = NULL; - - BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack)); - loop_stack_len = 0; - - BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { - if (BM_elem_flag_test(l->f, hflag)) { - BLI_SMALLSTACK_PUSH(loop_stack, l); - loop_stack_len++; - } - } - - if (loop_stack_len == 0) { - /* pass */ - } - else if (loop_stack_len == 1) { - l_best = BLI_SMALLSTACK_POP(loop_stack); - } - else { - /* complicated case, match the edge with a face-loop */ - - BMVert *v_other = BM_edge_other_vert(e, v); - float e_dir[3]; - - /* we want closest to zero */ - float dot_best = FLT_MAX; - - sub_v3_v3v3(e_dir, v_other->co, v->co); - normalize_v3(e_dir); - - while ((l = BLI_SMALLSTACK_POP(loop_stack))) { - float dot_test; - - /* Check dot first to save on expensive angle-comparison. - * ideal case is 90d difference == 0.0 dot */ - dot_test = fabsf(dot_v3v3(e_dir, l->f->no)); - if (dot_test < dot_best) { - - /* check we're in the correct corner - * (works with convex loops too) */ - if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) < - angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no)) - { - dot_best = dot_test; - l_best = l; - } - } - } - } - - if (l_best) { - BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */ - } - } - } - } - - { - BMFace *f; - BLI_buffer_declare_static(BMEdge **, edge_net_temp_buf, 0, 128); - - BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, hflag)) { - bm_face_split_by_edges(bm, f, hflag, &edge_net_temp_buf); - } - } - BLI_buffer_free(&edge_net_temp_buf); - } + const char hflag = BM_ELEM_TAG; + + BMEdge *e; + BMIter iter; + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if ((bm->totedgesel == 0) || (bm->totfacesel == 0)) { + continue; + } + + BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); + + { + BMVert *v; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(v, hflag); + } + } + + /* edge index is set to -1 then used to associate them with faces */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { + BM_elem_flag_enable(e, hflag); + + BM_elem_flag_enable(e->v1, hflag); + BM_elem_flag_enable(e->v2, hflag); + } + else { + BM_elem_flag_disable(e, hflag); + } + BM_elem_index_set(e, -1); /* set_dirty */ + } + bm->elem_index_dirty |= BM_EDGE; + + { + BMFace *f; + int i; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_elem_flag_enable(f, hflag); + } + else { + BM_elem_flag_disable(f, hflag); + } + BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); + BM_elem_index_set(f, i); /* set_ok */ + } + } + bm->elem_index_dirty &= ~BM_FACE; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, hflag)) { + BMIter viter; + BMVert *v; + BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { + BMIter liter; + BMLoop *l; + + unsigned int loop_stack_len; + BMLoop *l_best = NULL; + + BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack)); + loop_stack_len = 0; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (BM_elem_flag_test(l->f, hflag)) { + BLI_SMALLSTACK_PUSH(loop_stack, l); + loop_stack_len++; + } + } + + if (loop_stack_len == 0) { + /* pass */ + } + else if (loop_stack_len == 1) { + l_best = BLI_SMALLSTACK_POP(loop_stack); + } + else { + /* complicated case, match the edge with a face-loop */ + + BMVert *v_other = BM_edge_other_vert(e, v); + float e_dir[3]; + + /* we want closest to zero */ + float dot_best = FLT_MAX; + + sub_v3_v3v3(e_dir, v_other->co, v->co); + normalize_v3(e_dir); + + while ((l = BLI_SMALLSTACK_POP(loop_stack))) { + float dot_test; + + /* Check dot first to save on expensive angle-comparison. + * ideal case is 90d difference == 0.0 dot */ + dot_test = fabsf(dot_v3v3(e_dir, l->f->no)); + if (dot_test < dot_best) { + + /* check we're in the correct corner + * (works with convex loops too) */ + if (angle_signed_on_axis_v3v3v3_v3( + l->prev->v->co, l->v->co, v_other->co, l->f->no) < + angle_signed_on_axis_v3v3v3_v3( + l->prev->v->co, l->v->co, l->next->v->co, l->f->no)) { + dot_best = dot_test; + l_best = l; + } + } + } + } + + if (l_best) { + BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */ + } + } + } + } + + { + BMFace *f; + BLI_buffer_declare_static(BMEdge **, edge_net_temp_buf, 0, 128); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, hflag)) { + bm_face_split_by_edges(bm, f, hflag, &edge_net_temp_buf); + } + } + BLI_buffer_free(&edge_net_temp_buf); + } #ifdef USE_NET_ISLAND_CONNECT - /* before overwriting edge index values, collect edges left untouched */ - BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge *), __func__); - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { - BLI_stack_push(edges_loose, &e); - } - } + /* before overwriting edge index values, collect edges left untouched */ + BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge *), __func__); + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { + BLI_stack_push(edges_loose, &e); + } + } #endif - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); #ifdef USE_NET_ISLAND_CONNECT - /* we may have remaining isolated regions remaining, - * these will need to have connecting edges created */ - if (!BLI_stack_is_empty(edges_loose)) { - GHash *face_edge_map = BLI_ghash_ptr_new(__func__); - - MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - - BM_mesh_elem_index_ensure(bm, BM_FACE); - - { - BMBVHTree *bmbvh = BKE_bmbvh_new(bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false); - - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_index_set(e, -1); /* set_dirty */ - } - - while (!BLI_stack_is_empty(edges_loose)) { - BLI_stack_pop(edges_loose, &e); - float e_center[3]; - mid_v3_v3v3(e_center, e->v1->co, e->v2->co); - - BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX); - if (f) { - ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena); - BM_elem_index_set(e, BM_elem_index_get(f)); /* set_dirty */ - } - } - - BKE_bmbvh_free(bmbvh); - } - - bm->elem_index_dirty |= BM_EDGE; - - BM_mesh_elem_table_ensure(bm, BM_FACE); - - /* detect edges chains that span faces - * and splice vertices into the closest edges */ - { - GHashIterator gh_iter; - - GHASH_ITER(gh_iter, face_edge_map) { - BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); - LinkNode *e_link = e_ls_base->list; - - do { - e = e_link->link; - - for (int j = 0; j < 2; j++) { - BMVert *v_pivot = (&e->v1)[j]; - /* checking that \a v_pivot isn't in the face prevents attempting - * to splice the same vertex into an edge from multiple faces */ - if (!BM_vert_in_face(v_pivot, f)) { - float v_pivot_co[3]; - float v_pivot_fac; - BMEdge *e_split = bm_face_split_edge_find( - e, f, v_pivot, bm->ftable, bm->totface, - v_pivot_co, &v_pivot_fac); - - if (e_split) { - /* for degenerate cases this vertex may be in one - * of this edges radial faces */ - if (!bm_vert_in_faces_radial(v_pivot, e_split, f)) { - BMEdge *e_new; - BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac); - if (v_new) { - /* we _know_ these don't share an edge */ - BM_vert_splice(bm, v_pivot, v_new); - BM_elem_index_set(e_new, BM_elem_index_get(e_split)); - } - } - } - } - } - - } while ((e_link = e_link->next)); - } - } - - - { - MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - - GHashIterator gh_iter; - - GHASH_ITER(gh_iter, face_edge_map) { - BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); - - bm_face_split_by_edges_island_connect( - bm, f, - e_ls_base->list, e_ls_base->list_len, - mem_arena_edgenet); - - BLI_memarena_clear(mem_arena_edgenet); - } - - BLI_memarena_free(mem_arena_edgenet); - } - - BLI_memarena_free(mem_arena); - - BLI_ghash_free(face_edge_map, NULL, NULL); - - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - } - - BLI_stack_free(edges_loose); -#endif /* USE_NET_ISLAND_CONNECT */ - - } - MEM_freeN(objects); - return OPERATOR_FINISHED; + /* we may have remaining isolated regions remaining, + * these will need to have connecting edges created */ + if (!BLI_stack_is_empty(edges_loose)) { + GHash *face_edge_map = BLI_ghash_ptr_new(__func__); + + MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + + BM_mesh_elem_index_ensure(bm, BM_FACE); + + { + BMBVHTree *bmbvh = BKE_bmbvh_new( + bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false); + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_index_set(e, -1); /* set_dirty */ + } + + while (!BLI_stack_is_empty(edges_loose)) { + BLI_stack_pop(edges_loose, &e); + float e_center[3]; + mid_v3_v3v3(e_center, e->v1->co, e->v2->co); + + BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX); + if (f) { + ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena); + BM_elem_index_set(e, BM_elem_index_get(f)); /* set_dirty */ + } + } + + BKE_bmbvh_free(bmbvh); + } + + bm->elem_index_dirty |= BM_EDGE; + + BM_mesh_elem_table_ensure(bm, BM_FACE); + + /* detect edges chains that span faces + * and splice vertices into the closest edges */ + { + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, face_edge_map) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); + LinkNode *e_link = e_ls_base->list; + + do { + e = e_link->link; + + for (int j = 0; j < 2; j++) { + BMVert *v_pivot = (&e->v1)[j]; + /* checking that \a v_pivot isn't in the face prevents attempting + * to splice the same vertex into an edge from multiple faces */ + if (!BM_vert_in_face(v_pivot, f)) { + float v_pivot_co[3]; + float v_pivot_fac; + BMEdge *e_split = bm_face_split_edge_find( + e, f, v_pivot, bm->ftable, bm->totface, v_pivot_co, &v_pivot_fac); + + if (e_split) { + /* for degenerate cases this vertex may be in one + * of this edges radial faces */ + if (!bm_vert_in_faces_radial(v_pivot, e_split, f)) { + BMEdge *e_new; + BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac); + if (v_new) { + /* we _know_ these don't share an edge */ + BM_vert_splice(bm, v_pivot, v_new); + BM_elem_index_set(e_new, BM_elem_index_get(e_split)); + } + } + } + } + } + + } while ((e_link = e_link->next)); + } + } + + { + MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, face_edge_map) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); + + bm_face_split_by_edges_island_connect( + bm, f, e_ls_base->list, e_ls_base->list_len, mem_arena_edgenet); + + BLI_memarena_clear(mem_arena_edgenet); + } + + BLI_memarena_free(mem_arena_edgenet); + } + + BLI_memarena_free(mem_arena); + + BLI_ghash_free(face_edge_map, NULL, NULL); + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + } + + BLI_stack_free(edges_loose); +#endif /* USE_NET_ISLAND_CONNECT */ + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } - void MESH_OT_face_split_by_edges(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Weld Edges into Faces"; - ot->description = "Weld loose edges into faces (splitting them into new faces)"; - ot->idname = "MESH_OT_face_split_by_edges"; + /* identifiers */ + ot->name = "Weld Edges into Faces"; + ot->description = "Weld loose edges into faces (splitting them into new faces)"; + ot->idname = "MESH_OT_face_split_by_edges"; - /* api callbacks */ - ot->exec = edbm_face_split_by_edges_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_face_split_by_edges_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 0017044f2ff..f4979c8f2a8 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -69,199 +69,196 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /* detect isolated holes and fill them */ #define USE_NET_ISLAND_CONNECT -#define KMAXDIST 10 /* max mouse distance from edge before not detecting it */ +#define KMAXDIST 10 /* max mouse distance from edge before not detecting it */ /* WARNING: knife float precision is fragile: * be careful before making changes here see: (T43229, T42864, T42459, T41164). */ -#define KNIFE_FLT_EPS 0.00001f -#define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS) -#define KNIFE_FLT_EPSBIG 0.0005f +#define KNIFE_FLT_EPS 0.00001f +#define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS) +#define KNIFE_FLT_EPSBIG 0.0005f -#define KNIFE_FLT_EPS_PX_VERT 0.5f -#define KNIFE_FLT_EPS_PX_EDGE 0.05f -#define KNIFE_FLT_EPS_PX_FACE 0.05f +#define KNIFE_FLT_EPS_PX_VERT 0.5f +#define KNIFE_FLT_EPS_PX_EDGE 0.05f +#define KNIFE_FLT_EPS_PX_FACE 0.05f typedef struct KnifeColors { - uchar line[3]; - uchar edge[3]; - uchar curpoint[3]; - uchar curpoint_a[4]; - uchar point[3]; - uchar point_a[4]; + uchar line[3]; + uchar edge[3]; + uchar curpoint[3]; + uchar curpoint_a[4]; + uchar point[3]; + uchar point_a[4]; } KnifeColors; /* knifetool operator */ typedef struct KnifeVert { - BMVert *v; /* non-NULL if this is an original vert */ - ListBase edges; - ListBase faces; + BMVert *v; /* non-NULL if this is an original vert */ + ListBase edges; + ListBase faces; - float co[3], cageco[3], sco[2]; /* sco is screen coordinates for cageco */ - bool is_face, in_space; - bool is_cut; /* along a cut created by user input (will draw too) */ + float co[3], cageco[3], sco[2]; /* sco is screen coordinates for cageco */ + bool is_face, in_space; + bool is_cut; /* along a cut created by user input (will draw too) */ } KnifeVert; typedef struct Ref { - struct Ref *next, *prev; - void *ref; + struct Ref *next, *prev; + void *ref; } Ref; typedef struct KnifeEdge { - KnifeVert *v1, *v2; - BMFace *basef; /* face to restrict face fill to */ - ListBase faces; + KnifeVert *v1, *v2; + BMFace *basef; /* face to restrict face fill to */ + ListBase faces; - BMEdge *e /* , *e_old */; /* non-NULL if this is an original edge */ - bool is_cut; /* along a cut created by user input (will draw too) */ + BMEdge *e /* , *e_old */; /* non-NULL if this is an original edge */ + bool is_cut; /* along a cut created by user input (will draw too) */ } KnifeEdge; typedef struct KnifeLineHit { - float hit[3], cagehit[3]; - float schit[2]; /* screen coordinates for cagehit */ - float l; /* lambda along cut line */ - float perc; /* lambda along hit line */ - float m; /* depth front-to-back */ - - /* Exactly one of kfe, v, or f should be non-NULL, - * saying whether cut line crosses and edge, - * is snapped to a vert, or is in the middle of some face. */ - KnifeEdge *kfe; - KnifeVert *v; - BMFace *f; + float hit[3], cagehit[3]; + float schit[2]; /* screen coordinates for cagehit */ + float l; /* lambda along cut line */ + float perc; /* lambda along hit line */ + float m; /* depth front-to-back */ + + /* Exactly one of kfe, v, or f should be non-NULL, + * saying whether cut line crosses and edge, + * is snapped to a vert, or is in the middle of some face. */ + KnifeEdge *kfe; + KnifeVert *v; + BMFace *f; } KnifeLineHit; typedef struct KnifePosData { - float co[3]; - float cage[3]; - - /* At most one of vert, edge, or bmface should be non-NULL, - * saying whether the point is snapped to a vertex, edge, or in a face. - * If none are set, this point is in space and is_space should be true. */ - KnifeVert *vert; - KnifeEdge *edge; - BMFace *bmface; - bool is_space; - - float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */ + float co[3]; + float cage[3]; + + /* At most one of vert, edge, or bmface should be non-NULL, + * saying whether the point is snapped to a vertex, edge, or in a face. + * If none are set, this point is in space and is_space should be true. */ + KnifeVert *vert; + KnifeEdge *edge; + BMFace *bmface; + bool is_space; + + float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */ } KnifePosData; /* struct for properties used while drawing */ typedef struct KnifeTool_OpData { - ARegion *ar; /* region that knifetool was activated in */ - void *draw_handle; /* for drawing preview loop */ - ViewContext vc; /* note: _don't_ use 'mval', instead use the one we define below */ - float mval[2]; /* mouse value with snapping applied */ - //bContext *C; - - Scene *scene; - Object *ob; - BMEditMesh *em; - - MemArena *arena; - - /* reused for edge-net filling */ - struct { - /* cleared each use */ - GSet *edge_visit; + ARegion *ar; /* region that knifetool was activated in */ + void *draw_handle; /* for drawing preview loop */ + ViewContext vc; /* note: _don't_ use 'mval', instead use the one we define below */ + float mval[2]; /* mouse value with snapping applied */ + //bContext *C; + + Scene *scene; + Object *ob; + BMEditMesh *em; + + MemArena *arena; + + /* reused for edge-net filling */ + struct { + /* cleared each use */ + GSet *edge_visit; #ifdef USE_NET_ISLAND_CONNECT - MemArena *arena; + MemArena *arena; #endif - } edgenet; + } edgenet; - GHash *origvertmap; - GHash *origedgemap; - GHash *kedgefacemap; - GHash *facetrimap; + GHash *origvertmap; + GHash *origedgemap; + GHash *kedgefacemap; + GHash *facetrimap; - BMBVHTree *bmbvh; + BMBVHTree *bmbvh; - BLI_mempool *kverts; - BLI_mempool *kedges; + BLI_mempool *kverts; + BLI_mempool *kedges; - float vthresh; - float ethresh; + float vthresh; + float ethresh; - /* used for drag-cutting */ - KnifeLineHit *linehits; - int totlinehit; + /* used for drag-cutting */ + KnifeLineHit *linehits; + int totlinehit; - /* Data for mouse-position-derived data */ - KnifePosData curr; /* current point under the cursor */ - KnifePosData prev; /* last added cut (a line draws from the cursor to this) */ - KnifePosData init; /* the first point in the cut-list, used for closing the loop */ + /* Data for mouse-position-derived data */ + KnifePosData curr; /* current point under the cursor */ + KnifePosData prev; /* last added cut (a line draws from the cursor to this) */ + KnifePosData init; /* the first point in the cut-list, used for closing the loop */ - int totkedge, totkvert; + int totkedge, totkvert; - BLI_mempool *refs; + BLI_mempool *refs; - float projmat[4][4]; - float projmat_inv[4][4]; - /* vector along view z axis (object space, normalized) */ - float proj_zaxis[3]; + float projmat[4][4]; + float projmat_inv[4][4]; + /* vector along view z axis (object space, normalized) */ + float proj_zaxis[3]; - KnifeColors colors; + KnifeColors colors; - /* run by the UI or not */ - bool is_interactive; + /* run by the UI or not */ + bool is_interactive; - /* operatpr options */ - bool cut_through; /* preference, can be modified at runtime (that feature may go) */ - bool only_select; /* set on initialization */ - bool select_result; /* set on initialization */ + /* operatpr options */ + bool cut_through; /* preference, can be modified at runtime (that feature may go) */ + bool only_select; /* set on initialization */ + bool select_result; /* set on initialization */ - bool is_ortho; - float ortho_extent; - float ortho_extent_center[3]; + bool is_ortho; + float ortho_extent; + float ortho_extent_center[3]; - float clipsta, clipend; + float clipsta, clipend; - enum { - MODE_IDLE, - MODE_DRAGGING, - MODE_CONNECT, - MODE_PANNING - } mode; - bool is_drag_hold; + enum { MODE_IDLE, MODE_DRAGGING, MODE_CONNECT, MODE_PANNING } mode; + bool is_drag_hold; - int prevmode; - bool snap_midpoints; - bool ignore_edge_snapping; - bool ignore_vert_snapping; + int prevmode; + bool snap_midpoints; + bool ignore_edge_snapping; + bool ignore_vert_snapping; - /* use to check if we're currently dragging an angle snapped line */ - bool is_angle_snapping; - bool angle_snapping; - float angle; + /* use to check if we're currently dragging an angle snapped line */ + bool is_angle_snapping; + bool angle_snapping; + float angle; - const float (*cagecos)[3]; + const float (*cagecos)[3]; } KnifeTool_OpData; enum { - KNF_MODAL_CANCEL = 1, - KNF_MODAL_CONFIRM, - KNF_MODAL_MIDPOINT_ON, - KNF_MODAL_MIDPOINT_OFF, - KNF_MODAL_NEW_CUT, - KNF_MODEL_IGNORE_SNAP_ON, - KNF_MODEL_IGNORE_SNAP_OFF, - KNF_MODAL_ADD_CUT, - KNF_MODAL_ANGLE_SNAP_TOGGLE, - KNF_MODAL_CUT_THROUGH_TOGGLE, - KNF_MODAL_PANNING, - KNF_MODAL_ADD_CUT_CLOSED, + KNF_MODAL_CANCEL = 1, + KNF_MODAL_CONFIRM, + KNF_MODAL_MIDPOINT_ON, + KNF_MODAL_MIDPOINT_OFF, + KNF_MODAL_NEW_CUT, + KNF_MODEL_IGNORE_SNAP_ON, + KNF_MODEL_IGNORE_SNAP_OFF, + KNF_MODAL_ADD_CUT, + KNF_MODAL_ANGLE_SNAP_TOGGLE, + KNF_MODAL_CUT_THROUGH_TOGGLE, + KNF_MODAL_PANNING, + KNF_MODAL_ADD_CUT_CLOSED, }; - static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f); -static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], const float ofs, - float r_origin[3], float r_dest[3]); +static void knife_input_ray_segment(KnifeTool_OpData *kcd, + const float mval[2], + const float ofs, + float r_origin[3], + float r_dest[3]); static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f); @@ -271,205 +268,217 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event); static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *kcd) { - char header[UI_MAX_DRAW_STR]; - char buf[UI_MAX_DRAW_STR]; + char header[UI_MAX_DRAW_STR]; + char buf[UI_MAX_DRAW_STR]; - char *p = buf; - int available_len = sizeof(buf); + char *p = buf; + int available_len = sizeof(buf); #define WM_MODALKEY(_id) \ - WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) - - BLI_snprintf(header, sizeof(header), IFACE_("%s: confirm, %s: cancel, " - "%s: start/define cut, %s: close cut, %s: new cut, " - "%s: midpoint snap (%s), %s: ignore snap (%s), " - "%s: angle constraint (%s), %s: cut through (%s), " - "%s: panning"), - WM_MODALKEY(KNF_MODAL_CONFIRM), WM_MODALKEY(KNF_MODAL_CANCEL), - WM_MODALKEY(KNF_MODAL_ADD_CUT), WM_MODALKEY(KNF_MODAL_ADD_CUT_CLOSED), WM_MODALKEY(KNF_MODAL_NEW_CUT), - WM_MODALKEY(KNF_MODAL_MIDPOINT_ON), WM_bool_as_string(kcd->snap_midpoints), - WM_MODALKEY(KNF_MODEL_IGNORE_SNAP_ON), WM_bool_as_string(kcd->ignore_edge_snapping), - WM_MODALKEY(KNF_MODAL_ANGLE_SNAP_TOGGLE), WM_bool_as_string(kcd->angle_snapping), - WM_MODALKEY(KNF_MODAL_CUT_THROUGH_TOGGLE), WM_bool_as_string(kcd->cut_through), - WM_MODALKEY(KNF_MODAL_PANNING)); + WM_modalkeymap_operator_items_to_string_buf( \ + op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) + + BLI_snprintf(header, + sizeof(header), + IFACE_("%s: confirm, %s: cancel, " + "%s: start/define cut, %s: close cut, %s: new cut, " + "%s: midpoint snap (%s), %s: ignore snap (%s), " + "%s: angle constraint (%s), %s: cut through (%s), " + "%s: panning"), + WM_MODALKEY(KNF_MODAL_CONFIRM), + WM_MODALKEY(KNF_MODAL_CANCEL), + WM_MODALKEY(KNF_MODAL_ADD_CUT), + WM_MODALKEY(KNF_MODAL_ADD_CUT_CLOSED), + WM_MODALKEY(KNF_MODAL_NEW_CUT), + WM_MODALKEY(KNF_MODAL_MIDPOINT_ON), + WM_bool_as_string(kcd->snap_midpoints), + WM_MODALKEY(KNF_MODEL_IGNORE_SNAP_ON), + WM_bool_as_string(kcd->ignore_edge_snapping), + WM_MODALKEY(KNF_MODAL_ANGLE_SNAP_TOGGLE), + WM_bool_as_string(kcd->angle_snapping), + WM_MODALKEY(KNF_MODAL_CUT_THROUGH_TOGGLE), + WM_bool_as_string(kcd->cut_through), + WM_MODALKEY(KNF_MODAL_PANNING)); #undef WM_MODALKEY - ED_workspace_status_text(C, header); + ED_workspace_status_text(C, header); } static void knife_project_v2(const KnifeTool_OpData *kcd, const float co[3], float sco[2]) { - ED_view3d_project_float_v2_m4(kcd->ar, co, sco, (float (*)[4])kcd->projmat); + ED_view3d_project_float_v2_m4(kcd->ar, co, sco, (float(*)[4])kcd->projmat); } /* use when lambda is in screen-space */ -static void knife_interp_v3_v3v3( - const KnifeTool_OpData *kcd, - float r_co[3], const float v1[3], const float v2[3], float lambda_ss) +static void knife_interp_v3_v3v3(const KnifeTool_OpData *kcd, + float r_co[3], + const float v1[3], + const float v2[3], + float lambda_ss) { - if (kcd->is_ortho) { - interp_v3_v3v3(r_co, v1, v2, lambda_ss); - } - else { - /* transform into screen-space, interp, then transform back */ - float v1_ss[3], v2_ss[3]; + if (kcd->is_ortho) { + interp_v3_v3v3(r_co, v1, v2, lambda_ss); + } + else { + /* transform into screen-space, interp, then transform back */ + float v1_ss[3], v2_ss[3]; - mul_v3_project_m4_v3(v1_ss, (float (*)[4])kcd->projmat, v1); - mul_v3_project_m4_v3(v2_ss, (float (*)[4])kcd->projmat, v2); + mul_v3_project_m4_v3(v1_ss, (float(*)[4])kcd->projmat, v1); + mul_v3_project_m4_v3(v2_ss, (float(*)[4])kcd->projmat, v2); - interp_v3_v3v3(r_co, v1_ss, v2_ss, lambda_ss); + interp_v3_v3v3(r_co, v1_ss, v2_ss, lambda_ss); - mul_project_m4_v3((float (*)[4])kcd->projmat_inv, r_co); - } + mul_project_m4_v3((float(*)[4])kcd->projmat_inv, r_co); + } } static void knife_pos_data_clear(KnifePosData *kpd) { - zero_v3(kpd->co); - zero_v3(kpd->cage); - kpd->vert = NULL; - kpd->edge = NULL; - kpd->bmface = NULL; - zero_v2(kpd->mval); + zero_v3(kpd->co); + zero_v3(kpd->cage); + kpd->vert = NULL; + kpd->edge = NULL; + kpd->bmface = NULL; + zero_v2(kpd->mval); } static ListBase *knife_empty_list(KnifeTool_OpData *kcd) { - ListBase *lst; + ListBase *lst; - lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase)); - BLI_listbase_clear(lst); - return lst; + lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase)); + BLI_listbase_clear(lst); + return lst; } static void knife_append_list(KnifeTool_OpData *kcd, ListBase *lst, void *elem) { - Ref *ref; + Ref *ref; - ref = BLI_mempool_calloc(kcd->refs); - ref->ref = elem; - BLI_addtail(lst, ref); + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = elem; + BLI_addtail(lst, ref); } static Ref *find_ref(ListBase *lb, void *ref) { - Ref *ref1; + Ref *ref1; - for (ref1 = lb->first; ref1; ref1 = ref1->next) { - if (ref1->ref == ref) - return ref1; - } + for (ref1 = lb->first; ref1; ref1 = ref1->next) { + if (ref1->ref == ref) + return ref1; + } - return NULL; + return NULL; } static void knife_append_list_no_dup(KnifeTool_OpData *kcd, ListBase *lst, void *elem) { - if (!find_ref(lst, elem)) - knife_append_list(kcd, lst, elem); + if (!find_ref(lst, elem)) + knife_append_list(kcd, lst, elem); } static KnifeEdge *new_knife_edge(KnifeTool_OpData *kcd) { - kcd->totkedge++; - return BLI_mempool_calloc(kcd->kedges); + kcd->totkedge++; + return BLI_mempool_calloc(kcd->kedges); } static void knife_add_to_vert_edges(KnifeTool_OpData *kcd, KnifeEdge *kfe) { - knife_append_list(kcd, &kfe->v1->edges, kfe); - knife_append_list(kcd, &kfe->v2->edges, kfe); + knife_append_list(kcd, &kfe->v1->edges, kfe); + knife_append_list(kcd, &kfe->v2->edges, kfe); } /* Add faces of an edge to a KnifeVert's faces list. No checks for dups. */ static void knife_add_edge_faces_to_vert(KnifeTool_OpData *kcd, KnifeVert *kfv, BMEdge *e) { - BMIter bmiter; - BMFace *f; + BMIter bmiter; + BMFace *f; - BM_ITER_ELEM (f, &bmiter, e, BM_FACES_OF_EDGE) { - knife_append_list(kcd, &kfv->faces, f); - } + BM_ITER_ELEM (f, &bmiter, e, BM_FACES_OF_EDGE) { + knife_append_list(kcd, &kfv->faces, f); + } } /* Find a face in common in the two faces lists. * If more than one, return the first; if none, return NULL */ static BMFace *knife_find_common_face(ListBase *faces1, ListBase *faces2) { - Ref *ref1, *ref2; + Ref *ref1, *ref2; - for (ref1 = faces1->first; ref1; ref1 = ref1->next) { - for (ref2 = faces2->first; ref2; ref2 = ref2->next) { - if (ref1->ref == ref2->ref) - return (BMFace *)(ref1->ref); - } - } - return NULL; + for (ref1 = faces1->first; ref1; ref1 = ref1->next) { + for (ref2 = faces2->first; ref2; ref2 = ref2->next) { + if (ref1->ref == ref2->ref) + return (BMFace *)(ref1->ref); + } + } + return NULL; } static KnifeVert *new_knife_vert(KnifeTool_OpData *kcd, const float co[3], const float cageco[3]) { - KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts); + KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts); - kcd->totkvert++; + kcd->totkvert++; - copy_v3_v3(kfv->co, co); - copy_v3_v3(kfv->cageco, cageco); + copy_v3_v3(kfv->co, co); + copy_v3_v3(kfv->cageco, cageco); - knife_project_v2(kcd, kfv->cageco, kfv->sco); + knife_project_v2(kcd, kfv->cageco, kfv->sco); - return kfv; + return kfv; } /* get a KnifeVert wrapper for an existing BMVert */ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v) { - KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v); - const float *cageco; + KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v); + const float *cageco; - if (!kfv) { - BMIter bmiter; - BMFace *f; + if (!kfv) { + BMIter bmiter; + BMFace *f; - if (BM_elem_index_get(v) >= 0) - cageco = kcd->cagecos[BM_elem_index_get(v)]; - else - cageco = v->co; - kfv = new_knife_vert(kcd, v->co, cageco); - kfv->v = v; - BLI_ghash_insert(kcd->origvertmap, v, kfv); - BM_ITER_ELEM (f, &bmiter, v, BM_FACES_OF_VERT) { - knife_append_list(kcd, &kfv->faces, f); - } - } + if (BM_elem_index_get(v) >= 0) + cageco = kcd->cagecos[BM_elem_index_get(v)]; + else + cageco = v->co; + kfv = new_knife_vert(kcd, v->co, cageco); + kfv->v = v; + BLI_ghash_insert(kcd->origvertmap, v, kfv); + BM_ITER_ELEM (f, &bmiter, v, BM_FACES_OF_VERT) { + knife_append_list(kcd, &kfv->faces, f); + } + } - return kfv; + return kfv; } /* get a KnifeEdge wrapper for an existing BMEdge */ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e) { - KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e); - if (!kfe) { - BMIter bmiter; - BMFace *f; + KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e); + if (!kfe) { + BMIter bmiter; + BMFace *f; - kfe = new_knife_edge(kcd); - kfe->e = e; - kfe->v1 = get_bm_knife_vert(kcd, e->v1); - kfe->v2 = get_bm_knife_vert(kcd, e->v2); + kfe = new_knife_edge(kcd); + kfe->e = e; + kfe->v1 = get_bm_knife_vert(kcd, e->v1); + kfe->v2 = get_bm_knife_vert(kcd, e->v2); - knife_add_to_vert_edges(kcd, kfe); + knife_add_to_vert_edges(kcd, kfe); - BLI_ghash_insert(kcd->origedgemap, e, kfe); + BLI_ghash_insert(kcd->origedgemap, e, kfe); - BM_ITER_ELEM (f, &bmiter, e, BM_FACES_OF_EDGE) { - knife_append_list(kcd, &kfe->faces, f); - } - } + BM_ITER_ELEM (f, &bmiter, e, BM_FACES_OF_EDGE) { + knife_append_list(kcd, &kfe->faces, f); + } + } - return kfe; + return kfe; } /* Record the index in kcd->em->looptris of first looptri triple for a given face, @@ -482,140 +491,141 @@ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e) */ static void set_lowest_face_tri(KnifeTool_OpData *kcd, BMFace *f, int index) { - int i; + int i; - if (BLI_ghash_lookup(kcd->facetrimap, f)) - return; + if (BLI_ghash_lookup(kcd->facetrimap, f)) + return; - BLI_assert(index >= 0 && index < kcd->em->tottri); - BLI_assert(kcd->em->looptris[index][0]->f == f); - for (i = index - 1; i >= 0; i--) { - if (kcd->em->looptris[i][0]->f != f) { - i++; - break; - } - } - if (i == -1) - i++; + BLI_assert(index >= 0 && index < kcd->em->tottri); + BLI_assert(kcd->em->looptris[index][0]->f == f); + for (i = index - 1; i >= 0; i--) { + if (kcd->em->looptris[i][0]->f != f) { + i++; + break; + } + } + if (i == -1) + i++; - BLI_ghash_insert(kcd->facetrimap, f, POINTER_FROM_INT(i + 1)); + BLI_ghash_insert(kcd->facetrimap, f, POINTER_FROM_INT(i + 1)); } /* This should only be called for faces that have had a lowest face tri set by previous function */ static int get_lowest_face_tri(KnifeTool_OpData *kcd, BMFace *f) { - int ans; + int ans; - ans = POINTER_AS_INT(BLI_ghash_lookup(kcd->facetrimap, f)); - BLI_assert(ans != 0); - return ans - 1; + ans = POINTER_AS_INT(BLI_ghash_lookup(kcd->facetrimap, f)); + BLI_assert(ans != 0); + return ans - 1; } /* User has just clicked for first time or first time after a restart (E key). * Copy the current position data into prev. */ static void knife_start_cut(KnifeTool_OpData *kcd) { - kcd->prev = kcd->curr; - kcd->curr.is_space = 0; /*TODO: why do we do this? */ + kcd->prev = kcd->curr; + kcd->curr.is_space = 0; /*TODO: why do we do this? */ - if (kcd->prev.vert == NULL && kcd->prev.edge == NULL) { - float origin[3], origin_ofs[3]; - float ofs_local[3]; + if (kcd->prev.vert == NULL && kcd->prev.edge == NULL) { + float origin[3], origin_ofs[3]; + float ofs_local[3]; - negate_v3_v3(ofs_local, kcd->vc.rv3d->ofs); - invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); - mul_m4_v3(kcd->ob->imat, ofs_local); + negate_v3_v3(ofs_local, kcd->vc.rv3d->ofs); + invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); + mul_m4_v3(kcd->ob->imat, ofs_local); - knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); + knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); - if (!isect_line_plane_v3(kcd->prev.cage, origin, origin_ofs, ofs_local, kcd->proj_zaxis)) { - zero_v3(kcd->prev.cage); - } + if (!isect_line_plane_v3(kcd->prev.cage, origin, origin_ofs, ofs_local, kcd->proj_zaxis)) { + zero_v3(kcd->prev.cage); + } - copy_v3_v3(kcd->prev.co, kcd->prev.cage); /*TODO: do we need this? */ - copy_v3_v3(kcd->curr.cage, kcd->prev.cage); - copy_v3_v3(kcd->curr.co, kcd->prev.co); - } + copy_v3_v3(kcd->prev.co, kcd->prev.cage); /*TODO: do we need this? */ + copy_v3_v3(kcd->curr.cage, kcd->prev.cage); + copy_v3_v3(kcd->curr.co, kcd->prev.co); + } } static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f) { - ListBase *lst = BLI_ghash_lookup(kcd->kedgefacemap, f); + ListBase *lst = BLI_ghash_lookup(kcd->kedgefacemap, f); - if (!lst) { - BMIter bmiter; - BMEdge *e; + if (!lst) { + BMIter bmiter; + BMEdge *e; - lst = knife_empty_list(kcd); + lst = knife_empty_list(kcd); - BM_ITER_ELEM (e, &bmiter, f, BM_EDGES_OF_FACE) { - knife_append_list(kcd, lst, get_bm_knife_edge(kcd, e)); - } + BM_ITER_ELEM (e, &bmiter, f, BM_EDGES_OF_FACE) { + knife_append_list(kcd, lst, get_bm_knife_edge(kcd, e)); + } - BLI_ghash_insert(kcd->kedgefacemap, f, lst); - } + BLI_ghash_insert(kcd->kedgefacemap, f, lst); + } - return lst; + return lst; } static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace *f) { - knife_append_list(kcd, knife_get_face_kedges(kcd, f), kfe); - knife_append_list(kcd, &kfe->faces, f); + knife_append_list(kcd, knife_get_face_kedges(kcd, f), kfe); + knife_append_list(kcd, &kfe->faces, f); } -static KnifeVert *knife_split_edge( - KnifeTool_OpData *kcd, KnifeEdge *kfe, - const float co[3], const float cageco[3], - KnifeEdge **r_kfe) +static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, + KnifeEdge *kfe, + const float co[3], + const float cageco[3], + KnifeEdge **r_kfe) { - KnifeEdge *newkfe = new_knife_edge(kcd); - Ref *ref; - BMFace *f; + KnifeEdge *newkfe = new_knife_edge(kcd); + Ref *ref; + BMFace *f; - newkfe->v1 = kfe->v1; - newkfe->v2 = new_knife_vert(kcd, co, cageco); - newkfe->v2->is_cut = true; - if (kfe->e) { - knife_add_edge_faces_to_vert(kcd, newkfe->v2, kfe->e); - } - else { - /* kfe cuts across an existing face. - * If v1 and v2 are in multiple faces together (e.g., if they - * are in doubled polys) then this arbitrarily chooses one of them */ - f = knife_find_common_face(&kfe->v1->faces, &kfe->v2->faces); - if (f) - knife_append_list(kcd, &newkfe->v2->faces, f); - } - newkfe->basef = kfe->basef; + newkfe->v1 = kfe->v1; + newkfe->v2 = new_knife_vert(kcd, co, cageco); + newkfe->v2->is_cut = true; + if (kfe->e) { + knife_add_edge_faces_to_vert(kcd, newkfe->v2, kfe->e); + } + else { + /* kfe cuts across an existing face. + * If v1 and v2 are in multiple faces together (e.g., if they + * are in doubled polys) then this arbitrarily chooses one of them */ + f = knife_find_common_face(&kfe->v1->faces, &kfe->v2->faces); + if (f) + knife_append_list(kcd, &newkfe->v2->faces, f); + } + newkfe->basef = kfe->basef; - ref = find_ref(&kfe->v1->edges, kfe); - BLI_remlink(&kfe->v1->edges, ref); + ref = find_ref(&kfe->v1->edges, kfe); + BLI_remlink(&kfe->v1->edges, ref); - kfe->v1 = newkfe->v2; - BLI_addtail(&kfe->v1->edges, ref); + kfe->v1 = newkfe->v2; + BLI_addtail(&kfe->v1->edges, ref); - for (ref = kfe->faces.first; ref; ref = ref->next) - knife_edge_append_face(kcd, newkfe, ref->ref); + for (ref = kfe->faces.first; ref; ref = ref->next) + knife_edge_append_face(kcd, newkfe, ref->ref); - knife_add_to_vert_edges(kcd, newkfe); + knife_add_to_vert_edges(kcd, newkfe); - newkfe->is_cut = kfe->is_cut; - newkfe->e = kfe->e; + newkfe->is_cut = kfe->is_cut; + newkfe->e = kfe->e; - *r_kfe = newkfe; + *r_kfe = newkfe; - return newkfe->v2; + return newkfe->v2; } static void linehit_to_knifepos(KnifePosData *kpos, KnifeLineHit *lh) { - kpos->bmface = lh->f; - kpos->vert = lh->v; - kpos->edge = lh->kfe; - copy_v3_v3(kpos->cage, lh->cagehit); - copy_v3_v3(kpos->co, lh->hit); - copy_v2_v2(kpos->mval, lh->schit); + kpos->bmface = lh->f; + kpos->vert = lh->v; + kpos->edge = lh->kfe; + copy_v3_v3(kpos->cage, lh->cagehit); + copy_v3_v3(kpos->co, lh->hit); + copy_v2_v2(kpos->mval, lh->schit); } /* primary key: lambda along cut @@ -624,20 +634,27 @@ static void linehit_to_knifepos(KnifePosData *kpos, KnifeLineHit *lh) */ static int linehit_compare(const void *vlh1, const void *vlh2) { - const KnifeLineHit *lh1 = vlh1; - const KnifeLineHit *lh2 = vlh2; - - if (lh1->l < lh2->l) return -1; - else if (lh1->l > lh2->l) return 1; - else { - if (lh1->m < lh2->m) return -1; - else if (lh1->m > lh2->m) return 1; - else { - if (lh1->v < lh2->v) return -1; - else if (lh1->v > lh2->v) return 1; - else return 0; - } - } + const KnifeLineHit *lh1 = vlh1; + const KnifeLineHit *lh2 = vlh2; + + if (lh1->l < lh2->l) + return -1; + else if (lh1->l > lh2->l) + return 1; + else { + if (lh1->m < lh2->m) + return -1; + else if (lh1->m > lh2->m) + return 1; + else { + if (lh1->v < lh2->v) + return -1; + else if (lh1->v > lh2->v) + return 1; + else + return 0; + } + } } /* @@ -647,202 +664,195 @@ static int linehit_compare(const void *vlh1, const void *vlh2) */ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd) { - KnifeLineHit *linehits, *lhi, *lhj; - int i, j, n; - bool is_double = false; - - n = kcd->totlinehit; - linehits = kcd->linehits; - if (n == 0) - return; - - qsort(linehits, n, sizeof(KnifeLineHit), linehit_compare); - - /* Remove any edge hits that are preceded or followed - * by a vertex hit that is very near. Mark such edge hits using - * l == -1 and then do another pass to actually remove. - * Also remove all but one of a series of vertex hits for the same vertex. */ - for (i = 0; i < n; i++) { - lhi = &linehits[i]; - if (lhi->v) { - for (j = i - 1; j >= 0; j--) { - lhj = &linehits[j]; - if (!lhj->kfe || - fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || - fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) - { - break; - } - - if (lhi->kfe == lhj->kfe) { - lhj->l = -1.0f; - is_double = true; - } - } - for (j = i + 1; j < n; j++) { - lhj = &linehits[j]; - if (fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || - fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) - { - break; - } - if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || - (lhi->v == lhj->v)) - { - lhj->l = -1.0f; - is_double = true; - } - } - } - } - - if (is_double) { - /* delete-in-place loop: copying from pos j to pos i+1 */ - i = 0; - j = 1; - while (j < n) { - lhi = &linehits[i]; - lhj = &linehits[j]; - if (lhj->l == -1.0f) { - j++; /* skip copying this one */ - } - else { - /* copy unless a no-op */ - if (lhi->l == -1.0f) { - /* could happen if linehits[0] is being deleted */ - memcpy(&linehits[i], &linehits[j], sizeof(KnifeLineHit)); - } - else { - if (i + 1 != j) - memcpy(&linehits[i + 1], &linehits[j], sizeof(KnifeLineHit)); - i++; - } - j++; - } - } - kcd->totlinehit = i + 1; - } + KnifeLineHit *linehits, *lhi, *lhj; + int i, j, n; + bool is_double = false; + + n = kcd->totlinehit; + linehits = kcd->linehits; + if (n == 0) + return; + + qsort(linehits, n, sizeof(KnifeLineHit), linehit_compare); + + /* Remove any edge hits that are preceded or followed + * by a vertex hit that is very near. Mark such edge hits using + * l == -1 and then do another pass to actually remove. + * Also remove all but one of a series of vertex hits for the same vertex. */ + for (i = 0; i < n; i++) { + lhi = &linehits[i]; + if (lhi->v) { + for (j = i - 1; j >= 0; j--) { + lhj = &linehits[j]; + if (!lhj->kfe || fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || + fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) { + break; + } + + if (lhi->kfe == lhj->kfe) { + lhj->l = -1.0f; + is_double = true; + } + } + for (j = i + 1; j < n; j++) { + lhj = &linehits[j]; + if (fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || + fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) { + break; + } + if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || (lhi->v == lhj->v)) { + lhj->l = -1.0f; + is_double = true; + } + } + } + } + + if (is_double) { + /* delete-in-place loop: copying from pos j to pos i+1 */ + i = 0; + j = 1; + while (j < n) { + lhi = &linehits[i]; + lhj = &linehits[j]; + if (lhj->l == -1.0f) { + j++; /* skip copying this one */ + } + else { + /* copy unless a no-op */ + if (lhi->l == -1.0f) { + /* could happen if linehits[0] is being deleted */ + memcpy(&linehits[i], &linehits[j], sizeof(KnifeLineHit)); + } + else { + if (i + 1 != j) + memcpy(&linehits[i + 1], &linehits[j], sizeof(KnifeLineHit)); + i++; + } + j++; + } + } + kcd->totlinehit = i + 1; + } } /* Add hit to list of hits in facehits[f], where facehits is a map, if not already there */ -static void add_hit_to_facehits(KnifeTool_OpData *kcd, GHash *facehits, BMFace *f, KnifeLineHit *hit) +static void add_hit_to_facehits(KnifeTool_OpData *kcd, + GHash *facehits, + BMFace *f, + KnifeLineHit *hit) { - ListBase *lst = BLI_ghash_lookup(facehits, f); + ListBase *lst = BLI_ghash_lookup(facehits, f); - if (!lst) { - lst = knife_empty_list(kcd); - BLI_ghash_insert(facehits, f, lst); - } - knife_append_list_no_dup(kcd, lst, hit); + if (!lst) { + lst = knife_empty_list(kcd); + BLI_ghash_insert(facehits, f, lst); + } + knife_append_list_no_dup(kcd, lst, hit); } /** * special purpose function, if the linehit is connected to a real edge/vert * return true if \a co is outside the face. */ -static bool knife_add_single_cut__is_linehit_outside_face(BMFace *f, const KnifeLineHit *lh, const float co[3]) -{ - - if (lh->v && lh->v->v) { - BMLoop *l; /* side-of-loop */ - if ((l = BM_face_vert_share_loop(f, lh->v->v)) && - (BM_loop_point_side_of_loop_test(l, co) < 0.0f)) - { - return true; - } - } - else if ((lh->kfe && lh->kfe->e)) { - BMLoop *l; /* side-of-edge */ - if ((l = BM_face_edge_share_loop(f, lh->kfe->e)) && - (BM_loop_point_side_of_edge_test(l, co) < 0.0f)) - { - return true; - } - } - - return false; -} - - -static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, KnifeLineHit *lh2, BMFace *f) -{ - KnifeEdge *kfe, *kfe2; - BMEdge *e_base; - - if ((lh1->v && lh1->v == lh2->v) || - (lh1->kfe && lh1->kfe == lh2->kfe)) - { - return; - } - - /* if the cut is on an edge, just tag that its a cut and return */ - if ((lh1->v && lh2->v) && - (lh1->v->v && lh2->v && lh2->v->v) && - (e_base = BM_edge_exists(lh1->v->v, lh2->v->v))) - { - kfe = get_bm_knife_edge(kcd, e_base); - kfe->is_cut = true; - kfe->e = e_base; - return; - } - else { - if (knife_add_single_cut__is_linehit_outside_face(f, lh1, lh2->hit) || - knife_add_single_cut__is_linehit_outside_face(f, lh2, lh1->hit)) - { - return; - } - } - - - /* Check if edge actually lies within face (might not, if this face is concave) */ - if ((lh1->v && !lh1->kfe) && (lh2->v && !lh2->kfe)) { - if (!knife_verts_edge_in_face(lh1->v, lh2->v, f)) { - return; - } - } - - kfe = new_knife_edge(kcd); - kfe->is_cut = true; - kfe->basef = f; - - if (lh1->v) { - kfe->v1 = lh1->v; - } - else if (lh1->kfe) { - kfe->v1 = knife_split_edge(kcd, lh1->kfe, lh1->hit, lh1->cagehit, &kfe2); - lh1->v = kfe->v1; /* record the KnifeVert for this hit */ - } - else { - BLI_assert(lh1->f); - kfe->v1 = new_knife_vert(kcd, lh1->hit, lh1->cagehit); - kfe->v1->is_cut = true; - kfe->v1->is_face = true; - knife_append_list(kcd, &kfe->v1->faces, lh1->f); - lh1->v = kfe->v1; /* record the KnifeVert for this hit */ - } - - if (lh2->v) { - kfe->v2 = lh2->v; - } - else if (lh2->kfe) { - kfe->v2 = knife_split_edge(kcd, lh2->kfe, lh2->hit, lh2->cagehit, &kfe2); - lh2->v = kfe->v2; /* future uses of lh2 won't split again */ - } - else { - BLI_assert(lh2->f); - kfe->v2 = new_knife_vert(kcd, lh2->hit, lh2->cagehit); - kfe->v2->is_cut = true; - kfe->v2->is_face = true; - knife_append_list(kcd, &kfe->v2->faces, lh2->f); - lh2->v = kfe->v2; /* record the KnifeVert for this hit */ - } - - knife_add_to_vert_edges(kcd, kfe); - - /* TODO: check if this is ever needed */ - if (kfe->basef && !find_ref(&kfe->faces, kfe->basef)) - knife_edge_append_face(kcd, kfe, kfe->basef); - +static bool knife_add_single_cut__is_linehit_outside_face(BMFace *f, + const KnifeLineHit *lh, + const float co[3]) +{ + + if (lh->v && lh->v->v) { + BMLoop *l; /* side-of-loop */ + if ((l = BM_face_vert_share_loop(f, lh->v->v)) && + (BM_loop_point_side_of_loop_test(l, co) < 0.0f)) { + return true; + } + } + else if ((lh->kfe && lh->kfe->e)) { + BMLoop *l; /* side-of-edge */ + if ((l = BM_face_edge_share_loop(f, lh->kfe->e)) && + (BM_loop_point_side_of_edge_test(l, co) < 0.0f)) { + return true; + } + } + + return false; +} + +static void knife_add_single_cut(KnifeTool_OpData *kcd, + KnifeLineHit *lh1, + KnifeLineHit *lh2, + BMFace *f) +{ + KnifeEdge *kfe, *kfe2; + BMEdge *e_base; + + if ((lh1->v && lh1->v == lh2->v) || (lh1->kfe && lh1->kfe == lh2->kfe)) { + return; + } + + /* if the cut is on an edge, just tag that its a cut and return */ + if ((lh1->v && lh2->v) && (lh1->v->v && lh2->v && lh2->v->v) && + (e_base = BM_edge_exists(lh1->v->v, lh2->v->v))) { + kfe = get_bm_knife_edge(kcd, e_base); + kfe->is_cut = true; + kfe->e = e_base; + return; + } + else { + if (knife_add_single_cut__is_linehit_outside_face(f, lh1, lh2->hit) || + knife_add_single_cut__is_linehit_outside_face(f, lh2, lh1->hit)) { + return; + } + } + + /* Check if edge actually lies within face (might not, if this face is concave) */ + if ((lh1->v && !lh1->kfe) && (lh2->v && !lh2->kfe)) { + if (!knife_verts_edge_in_face(lh1->v, lh2->v, f)) { + return; + } + } + + kfe = new_knife_edge(kcd); + kfe->is_cut = true; + kfe->basef = f; + + if (lh1->v) { + kfe->v1 = lh1->v; + } + else if (lh1->kfe) { + kfe->v1 = knife_split_edge(kcd, lh1->kfe, lh1->hit, lh1->cagehit, &kfe2); + lh1->v = kfe->v1; /* record the KnifeVert for this hit */ + } + else { + BLI_assert(lh1->f); + kfe->v1 = new_knife_vert(kcd, lh1->hit, lh1->cagehit); + kfe->v1->is_cut = true; + kfe->v1->is_face = true; + knife_append_list(kcd, &kfe->v1->faces, lh1->f); + lh1->v = kfe->v1; /* record the KnifeVert for this hit */ + } + + if (lh2->v) { + kfe->v2 = lh2->v; + } + else if (lh2->kfe) { + kfe->v2 = knife_split_edge(kcd, lh2->kfe, lh2->hit, lh2->cagehit, &kfe2); + lh2->v = kfe->v2; /* future uses of lh2 won't split again */ + } + else { + BLI_assert(lh2->f); + kfe->v2 = new_knife_vert(kcd, lh2->hit, lh2->cagehit); + kfe->v2->is_cut = true; + kfe->v2->is_face = true; + knife_append_list(kcd, &kfe->v2->faces, lh2->f); + lh2->v = kfe->v2; /* record the KnifeVert for this hit */ + } + + knife_add_to_vert_edges(kcd, kfe); + + /* TODO: check if this is ever needed */ + if (kfe->basef && !find_ref(&kfe->faces, kfe->basef)) + knife_edge_append_face(kcd, kfe, kfe->basef); } /* Given a list of KnifeLineHits for one face, sorted by l @@ -851,14 +861,14 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife */ static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits) { - Ref *r; + Ref *r; - if (BLI_listbase_count_at_most(hits, 2) != 2) - return; + if (BLI_listbase_count_at_most(hits, 2) != 2) + return; - for (r = hits->first; r->next; r = r->next) { - knife_add_single_cut(kcd, r->ref, r->next->ref, f); - } + for (r = hits->first; r->next; r = r->next) { + knife_add_single_cut(kcd, r->ref, r->next->ref, f); + } } /* User has just left-clicked after the first time. @@ -868,338 +878,337 @@ static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits) */ static void knife_add_cut(KnifeTool_OpData *kcd) { - int i; - GHash *facehits; - BMFace *f; - Ref *r; - GHashIterator giter; - ListBase *lst; - - prepare_linehits_for_cut(kcd); - if (kcd->totlinehit == 0) { - if (kcd->is_drag_hold == false) { - kcd->prev = kcd->curr; - } - return; - } - - /* make facehits: map face -> list of linehits touching it */ - facehits = BLI_ghash_ptr_new("knife facehits"); - for (i = 0; i < kcd->totlinehit; i++) { - KnifeLineHit *lh = &kcd->linehits[i]; - if (lh->f) { - add_hit_to_facehits(kcd, facehits, lh->f, lh); - } - if (lh->v) { - for (r = lh->v->faces.first; r; r = r->next) { - add_hit_to_facehits(kcd, facehits, r->ref, lh); - } - } - if (lh->kfe) { - for (r = lh->kfe->faces.first; r; r = r->next) { - add_hit_to_facehits(kcd, facehits, r->ref, lh); - } - } - } - - /* Note: as following loop progresses, the 'v' fields of - * the linehits will be filled in (as edges are split or - * in-face verts are made), so it may be true that both - * the v and the kfe or f fields will be non-NULL. */ - GHASH_ITER (giter, facehits) { - f = (BMFace *)BLI_ghashIterator_getKey(&giter); - lst = (ListBase *)BLI_ghashIterator_getValue(&giter); - knife_cut_face(kcd, f, lst); - } - - /* set up for next cut */ - kcd->prev = kcd->curr; - - - if (kcd->prev.bmface) { - /* was "in face" but now we have a KnifeVert it is snapped to */ - KnifeLineHit *lh = &kcd->linehits[kcd->totlinehit - 1]; - kcd->prev.vert = lh->v; - kcd->prev.bmface = NULL; - } - - if (kcd->is_drag_hold) { - KnifeLineHit *lh = &kcd->linehits[kcd->totlinehit - 1]; - linehit_to_knifepos(&kcd->prev, lh); - } - - BLI_ghash_free(facehits, NULL, NULL); - MEM_freeN(kcd->linehits); - kcd->linehits = NULL; - kcd->totlinehit = 0; + int i; + GHash *facehits; + BMFace *f; + Ref *r; + GHashIterator giter; + ListBase *lst; + + prepare_linehits_for_cut(kcd); + if (kcd->totlinehit == 0) { + if (kcd->is_drag_hold == false) { + kcd->prev = kcd->curr; + } + return; + } + + /* make facehits: map face -> list of linehits touching it */ + facehits = BLI_ghash_ptr_new("knife facehits"); + for (i = 0; i < kcd->totlinehit; i++) { + KnifeLineHit *lh = &kcd->linehits[i]; + if (lh->f) { + add_hit_to_facehits(kcd, facehits, lh->f, lh); + } + if (lh->v) { + for (r = lh->v->faces.first; r; r = r->next) { + add_hit_to_facehits(kcd, facehits, r->ref, lh); + } + } + if (lh->kfe) { + for (r = lh->kfe->faces.first; r; r = r->next) { + add_hit_to_facehits(kcd, facehits, r->ref, lh); + } + } + } + + /* Note: as following loop progresses, the 'v' fields of + * the linehits will be filled in (as edges are split or + * in-face verts are made), so it may be true that both + * the v and the kfe or f fields will be non-NULL. */ + GHASH_ITER (giter, facehits) { + f = (BMFace *)BLI_ghashIterator_getKey(&giter); + lst = (ListBase *)BLI_ghashIterator_getValue(&giter); + knife_cut_face(kcd, f, lst); + } + + /* set up for next cut */ + kcd->prev = kcd->curr; + + if (kcd->prev.bmface) { + /* was "in face" but now we have a KnifeVert it is snapped to */ + KnifeLineHit *lh = &kcd->linehits[kcd->totlinehit - 1]; + kcd->prev.vert = lh->v; + kcd->prev.bmface = NULL; + } + + if (kcd->is_drag_hold) { + KnifeLineHit *lh = &kcd->linehits[kcd->totlinehit - 1]; + linehit_to_knifepos(&kcd->prev, lh); + } + + BLI_ghash_free(facehits, NULL, NULL); + MEM_freeN(kcd->linehits); + kcd->linehits = NULL; + kcd->totlinehit = 0; } static void knife_finish_cut(KnifeTool_OpData *kcd) { - if (kcd->linehits) { - MEM_freeN(kcd->linehits); - kcd->linehits = NULL; - kcd->totlinehit = 0; - } + if (kcd->linehits) { + MEM_freeN(kcd->linehits); + kcd->linehits = NULL; + kcd->totlinehit = 0; + } } static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) { - float v1[3], v2[3]; - float planes[4][4]; + float v1[3], v2[3]; + float planes[4][4]; - planes_from_projmat( - (float (*)[4])kcd->projmat, - planes[2], planes[0], planes[3], planes[1], NULL, NULL); + planes_from_projmat( + (float(*)[4])kcd->projmat, planes[2], planes[0], planes[3], planes[1], NULL, NULL); - /* ray-cast all planes */ - { - float ray_dir[3]; - float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}}; - float lambda_best[2] = {-FLT_MAX, FLT_MAX}; - int i; + /* ray-cast all planes */ + { + float ray_dir[3]; + float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}}; + float lambda_best[2] = {-FLT_MAX, FLT_MAX}; + int i; - /* we (sometimes) need the lines to be at the same depth before projecting */ + /* we (sometimes) need the lines to be at the same depth before projecting */ #if 0 - sub_v3_v3v3(ray_dir, kcd->curr.cage, kcd->prev.cage); + sub_v3_v3v3(ray_dir, kcd->curr.cage, kcd->prev.cage); #else - { - float curr_cage_adjust[3]; - float co_depth[3]; + { + float curr_cage_adjust[3]; + float co_depth[3]; - copy_v3_v3(co_depth, kcd->prev.cage); - mul_m4_v3(kcd->ob->obmat, co_depth); - ED_view3d_win_to_3d(kcd->vc.v3d, kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust); - mul_m4_v3(kcd->ob->imat, curr_cage_adjust); + copy_v3_v3(co_depth, kcd->prev.cage); + mul_m4_v3(kcd->ob->obmat, co_depth); + ED_view3d_win_to_3d(kcd->vc.v3d, kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust); + mul_m4_v3(kcd->ob->imat, curr_cage_adjust); - sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage); - } + sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage); + } #endif - for (i = 0; i < 4; i++) { - float ray_hit[3]; - float lambda_test; - if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) { - madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test); - if (lambda_test < 0.0f) { - if (lambda_test > lambda_best[0]) { - copy_v3_v3(ray_hit_best[0], ray_hit); - lambda_best[0] = lambda_test; - } - } - else { - if (lambda_test < lambda_best[1]) { - copy_v3_v3(ray_hit_best[1], ray_hit); - lambda_best[1] = lambda_test; - } - } - } - } - - copy_v3_v3(v1, ray_hit_best[0]); - copy_v3_v3(v2, ray_hit_best[1]); - } - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformThemeColor(TH_TRANSFORM); - GPU_line_width(2.0); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, v1); - immVertex3fv(pos, v2); - immEnd(); - - immUnbindProgram(); + for (i = 0; i < 4; i++) { + float ray_hit[3]; + float lambda_test; + if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) { + madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test); + if (lambda_test < 0.0f) { + if (lambda_test > lambda_best[0]) { + copy_v3_v3(ray_hit_best[0], ray_hit); + lambda_best[0] = lambda_test; + } + } + else { + if (lambda_test < lambda_best[1]) { + copy_v3_v3(ray_hit_best[1], ray_hit); + lambda_best[1] = lambda_test; + } + } + } + } + + copy_v3_v3(v1, ray_hit_best[0]); + copy_v3_v3(v2, ray_hit_best[1]); + } + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColor(TH_TRANSFORM); + GPU_line_width(2.0); + + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immEnd(); + + immUnbindProgram(); } static void knife_init_colors(KnifeColors *colors) { - /* possible BMESH_TODO: add explicit themes or calculate these by - * figuring out contrasting colors with grid / edges / verts - * a la UI_make_axis_color */ - UI_GetThemeColorType3ubv(TH_NURB_VLINE, SPACE_VIEW3D, colors->line); - UI_GetThemeColorType3ubv(TH_NURB_ULINE, SPACE_VIEW3D, colors->edge); - UI_GetThemeColorType3ubv(TH_HANDLE_SEL_VECT, SPACE_VIEW3D, colors->curpoint); - UI_GetThemeColorType3ubv(TH_HANDLE_SEL_VECT, SPACE_VIEW3D, colors->curpoint_a); - colors->curpoint_a[3] = 102; - UI_GetThemeColorType3ubv(TH_ACTIVE_SPLINE, SPACE_VIEW3D, colors->point); - UI_GetThemeColorType3ubv(TH_ACTIVE_SPLINE, SPACE_VIEW3D, colors->point_a); - colors->point_a[3] = 102; + /* possible BMESH_TODO: add explicit themes or calculate these by + * figuring out contrasting colors with grid / edges / verts + * a la UI_make_axis_color */ + UI_GetThemeColorType3ubv(TH_NURB_VLINE, SPACE_VIEW3D, colors->line); + UI_GetThemeColorType3ubv(TH_NURB_ULINE, SPACE_VIEW3D, colors->edge); + UI_GetThemeColorType3ubv(TH_HANDLE_SEL_VECT, SPACE_VIEW3D, colors->curpoint); + UI_GetThemeColorType3ubv(TH_HANDLE_SEL_VECT, SPACE_VIEW3D, colors->curpoint_a); + colors->curpoint_a[3] = 102; + UI_GetThemeColorType3ubv(TH_ACTIVE_SPLINE, SPACE_VIEW3D, colors->point); + UI_GetThemeColorType3ubv(TH_ACTIVE_SPLINE, SPACE_VIEW3D, colors->point_a); + colors->point_a[3] = 102; } /* modal loop selection drawing callback */ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) { - const KnifeTool_OpData *kcd = arg; - GPU_depth_test(false); - - glPolygonOffset(1.0f, 1.0f); - - GPU_matrix_push(); - GPU_matrix_mul(kcd->ob->obmat); - - if (kcd->mode == MODE_DRAGGING && kcd->is_angle_snapping) { - knifetool_draw_angle_snapping(kcd); - } - - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - if (kcd->mode == MODE_DRAGGING) { - immUniformColor3ubv(kcd->colors.line); - GPU_line_width(2.0); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, kcd->prev.cage); - immVertex3fv(pos, kcd->curr.cage); - immEnd(); - } - - if (kcd->prev.vert) { - immUniformColor3ubv(kcd->colors.point); - GPU_point_size(11); - - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, kcd->prev.cage); - immEnd(); - } - - if (kcd->prev.bmface) { - immUniformColor3ubv(kcd->colors.curpoint); - GPU_point_size(9); - - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, kcd->prev.cage); - immEnd(); - } - - if (kcd->curr.edge) { - immUniformColor3ubv(kcd->colors.edge); - GPU_line_width(2.0); + const KnifeTool_OpData *kcd = arg; + GPU_depth_test(false); + + glPolygonOffset(1.0f, 1.0f); + + GPU_matrix_push(); + GPU_matrix_mul(kcd->ob->obmat); + + if (kcd->mode == MODE_DRAGGING && kcd->is_angle_snapping) { + knifetool_draw_angle_snapping(kcd); + } + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + if (kcd->mode == MODE_DRAGGING) { + immUniformColor3ubv(kcd->colors.line); + GPU_line_width(2.0); + + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, kcd->prev.cage); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); + } + + if (kcd->prev.vert) { + immUniformColor3ubv(kcd->colors.point); + GPU_point_size(11); + + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->prev.cage); + immEnd(); + } + + if (kcd->prev.bmface) { + immUniformColor3ubv(kcd->colors.curpoint); + GPU_point_size(9); + + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->prev.cage); + immEnd(); + } + + if (kcd->curr.edge) { + immUniformColor3ubv(kcd->colors.edge); + GPU_line_width(2.0); - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, kcd->curr.edge->v1->cageco); - immVertex3fv(pos, kcd->curr.edge->v2->cageco); - immEnd(); - } - else if (kcd->curr.vert) { - immUniformColor3ubv(kcd->colors.point); - GPU_point_size(11); + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, kcd->curr.edge->v1->cageco); + immVertex3fv(pos, kcd->curr.edge->v2->cageco); + immEnd(); + } + else if (kcd->curr.vert) { + immUniformColor3ubv(kcd->colors.point); + GPU_point_size(11); - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, kcd->curr.cage); - immEnd(); - } + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); + } - if (kcd->curr.bmface) { - immUniformColor3ubv(kcd->colors.curpoint); - GPU_point_size(9); + if (kcd->curr.bmface) { + immUniformColor3ubv(kcd->colors.curpoint); + GPU_point_size(9); - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, kcd->curr.cage); - immEnd(); - } + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); + } - if (kcd->totlinehit > 0) { - KnifeLineHit *lh; - int i, v, vs; - float fcol[4]; + if (kcd->totlinehit > 0) { + KnifeLineHit *lh; + int i, v, vs; + float fcol[4]; - GPU_blend(true); - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); - GPU_vertbuf_data_alloc(vert, kcd->totlinehit); + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, kcd->totlinehit); - lh = kcd->linehits; - for (i = 0, v = 0, vs = kcd->totlinehit - 1; i < kcd->totlinehit; i++, lh++) { - if (lh->v) { - GPU_vertbuf_attr_set(vert, pos, v++, lh->cagehit); - } - else { - GPU_vertbuf_attr_set(vert, pos, vs--, lh->cagehit); - } - } + lh = kcd->linehits; + for (i = 0, v = 0, vs = kcd->totlinehit - 1; i < kcd->totlinehit; i++, lh++) { + if (lh->v) { + GPU_vertbuf_attr_set(vert, pos, v++, lh->cagehit); + } + else { + GPU_vertbuf_attr_set(vert, pos, vs--, lh->cagehit); + } + } - GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO); - GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); - /* draw any snapped verts first */ - rgba_uchar_to_float(fcol, kcd->colors.point_a); - GPU_batch_uniform_4fv(batch, "color", fcol); - GPU_matrix_bind(batch->interface); - GPU_point_size(11); - GPU_batch_draw_range_ex(batch, 0, v - 1, false); + /* draw any snapped verts first */ + rgba_uchar_to_float(fcol, kcd->colors.point_a); + GPU_batch_uniform_4fv(batch, "color", fcol); + GPU_matrix_bind(batch->interface); + GPU_point_size(11); + GPU_batch_draw_range_ex(batch, 0, v - 1, false); - /* now draw the rest */ - rgba_uchar_to_float(fcol, kcd->colors.curpoint_a); - GPU_batch_uniform_4fv(batch, "color", fcol); - GPU_point_size(7); - GPU_batch_draw_range_ex(batch, vs + 1, kcd->totlinehit - (vs + 1), false); + /* now draw the rest */ + rgba_uchar_to_float(fcol, kcd->colors.curpoint_a); + GPU_batch_uniform_4fv(batch, "color", fcol); + GPU_point_size(7); + GPU_batch_draw_range_ex(batch, vs + 1, kcd->totlinehit - (vs + 1), false); - GPU_batch_program_use_end(batch); - GPU_batch_discard(batch); + GPU_batch_program_use_end(batch); + GPU_batch_discard(batch); - GPU_blend(false); - } + GPU_blend(false); + } - if (kcd->totkedge > 0) { - BLI_mempool_iter iter; - KnifeEdge *kfe; + if (kcd->totkedge > 0) { + BLI_mempool_iter iter; + KnifeEdge *kfe; - immUniformColor3ubv(kcd->colors.line); - GPU_line_width(1.0); + immUniformColor3ubv(kcd->colors.line); + GPU_line_width(1.0); - GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2); + GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2); - BLI_mempool_iternew(kcd->kedges, &iter); - for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { - if (!kfe->is_cut) - continue; + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { + if (!kfe->is_cut) + continue; - immVertex3fv(pos, kfe->v1->cageco); - immVertex3fv(pos, kfe->v2->cageco); - } + immVertex3fv(pos, kfe->v1->cageco); + immVertex3fv(pos, kfe->v2->cageco); + } - immEnd(); + immEnd(); - GPU_batch_draw(batch); - GPU_batch_discard(batch); - } + GPU_batch_draw(batch); + GPU_batch_discard(batch); + } - if (kcd->totkvert > 0) { - BLI_mempool_iter iter; - KnifeVert *kfv; + if (kcd->totkvert > 0) { + BLI_mempool_iter iter; + KnifeVert *kfv; - immUniformColor3ubv(kcd->colors.point); - GPU_point_size(5.0); + immUniformColor3ubv(kcd->colors.point); + GPU_point_size(5.0); - GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); + GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); - BLI_mempool_iternew(kcd->kverts, &iter); - for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { - if (!kfv->is_cut) - continue; + BLI_mempool_iternew(kcd->kverts, &iter); + for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { + if (!kfv->is_cut) + continue; - immVertex3fv(pos, kfv->cageco); - } + immVertex3fv(pos, kfv->cageco); + } - immEnd(); + immEnd(); - GPU_batch_draw(batch); - GPU_batch_discard(batch); - } + GPU_batch_draw(batch); + GPU_batch_discard(batch); + } - immUnbindProgram(); + immUnbindProgram(); - GPU_matrix_pop(); + GPU_matrix_pop(); - /* Reset default */ - GPU_depth_test(true); + /* Reset default */ + GPU_depth_test(true); } /** @@ -1210,68 +1219,70 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void * it really means "infinite number of intersections". * In such a case we should have gotten hits on edges or verts of the face. */ -static bool knife_ray_intersect_face( - KnifeTool_OpData *kcd, - const float s[2], const float v1[3], const float v2[3], - BMFace *f, const float face_tol_sq, - float hit_co[3], float hit_cageco[3]) -{ - int tottri, tri_i; - float raydir[3]; - float tri_norm[3], tri_plane[4]; - float se1[2], se2[2]; - float d, lambda; - BMLoop **tri; - ListBase *lst; - Ref *ref; - KnifeEdge *kfe; - - sub_v3_v3v3(raydir, v2, v1); - normalize_v3(raydir); - tri_i = get_lowest_face_tri(kcd, f); - tottri = kcd->em->tottri; - BLI_assert(tri_i >= 0 && tri_i < tottri); - - for (; tri_i < tottri; tri_i++) { - const float *lv1, *lv2, *lv3; - float ray_tri_uv[2]; - - tri = kcd->em->looptris[tri_i]; - if (tri[0]->f != f) - break; - lv1 = kcd->cagecos[BM_elem_index_get(tri[0]->v)]; - lv2 = kcd->cagecos[BM_elem_index_get(tri[1]->v)]; - lv3 = kcd->cagecos[BM_elem_index_get(tri[2]->v)]; - /* using epsilon test in case ray is directly through an internal - * tessellation edge and might not hit either tessellation tri with - * an exact test; - * we will exclude hits near real edges by a later test */ - if (isect_ray_tri_epsilon_v3(v1, raydir, lv1, lv2, lv3, &lambda, ray_tri_uv, KNIFE_FLT_EPS)) { - /* check if line coplanar with tri */ - normal_tri_v3(tri_norm, lv1, lv2, lv3); - plane_from_point_normal_v3(tri_plane, lv1, tri_norm); - if ((dist_squared_to_plane_v3(v1, tri_plane) < KNIFE_FLT_EPS) && - (dist_squared_to_plane_v3(v2, tri_plane) < KNIFE_FLT_EPS)) - { - return false; - } - interp_v3_v3v3v3_uv(hit_cageco, lv1, lv2, lv3, ray_tri_uv); - /* Now check that far enough away from verts and edges */ - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { - kfe = ref->ref; - knife_project_v2(kcd, kfe->v1->cageco, se1); - knife_project_v2(kcd, kfe->v2->cageco, se2); - d = dist_squared_to_line_segment_v2(s, se1, se2); - if (d < face_tol_sq) { - return false; - } - } - interp_v3_v3v3v3_uv(hit_co, tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, ray_tri_uv); - return true; - } - } - return false; +static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, + const float s[2], + const float v1[3], + const float v2[3], + BMFace *f, + const float face_tol_sq, + float hit_co[3], + float hit_cageco[3]) +{ + int tottri, tri_i; + float raydir[3]; + float tri_norm[3], tri_plane[4]; + float se1[2], se2[2]; + float d, lambda; + BMLoop **tri; + ListBase *lst; + Ref *ref; + KnifeEdge *kfe; + + sub_v3_v3v3(raydir, v2, v1); + normalize_v3(raydir); + tri_i = get_lowest_face_tri(kcd, f); + tottri = kcd->em->tottri; + BLI_assert(tri_i >= 0 && tri_i < tottri); + + for (; tri_i < tottri; tri_i++) { + const float *lv1, *lv2, *lv3; + float ray_tri_uv[2]; + + tri = kcd->em->looptris[tri_i]; + if (tri[0]->f != f) + break; + lv1 = kcd->cagecos[BM_elem_index_get(tri[0]->v)]; + lv2 = kcd->cagecos[BM_elem_index_get(tri[1]->v)]; + lv3 = kcd->cagecos[BM_elem_index_get(tri[2]->v)]; + /* using epsilon test in case ray is directly through an internal + * tessellation edge and might not hit either tessellation tri with + * an exact test; + * we will exclude hits near real edges by a later test */ + if (isect_ray_tri_epsilon_v3(v1, raydir, lv1, lv2, lv3, &lambda, ray_tri_uv, KNIFE_FLT_EPS)) { + /* check if line coplanar with tri */ + normal_tri_v3(tri_norm, lv1, lv2, lv3); + plane_from_point_normal_v3(tri_plane, lv1, tri_norm); + if ((dist_squared_to_plane_v3(v1, tri_plane) < KNIFE_FLT_EPS) && + (dist_squared_to_plane_v3(v2, tri_plane) < KNIFE_FLT_EPS)) { + return false; + } + interp_v3_v3v3v3_uv(hit_cageco, lv1, lv2, lv3, ray_tri_uv); + /* Now check that far enough away from verts and edges */ + lst = knife_get_face_kedges(kcd, f); + for (ref = lst->first; ref; ref = ref->next) { + kfe = ref->ref; + knife_project_v2(kcd, kfe->v1->cageco, se1); + knife_project_v2(kcd, kfe->v2->cageco, se2); + d = dist_squared_to_line_segment_v2(s, se1, se2); + if (d < face_tol_sq) { + return false; + } + } + interp_v3_v3v3v3_uv(hit_co, tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, ray_tri_uv); + return true; + } + } + return false; } /** @@ -1279,96 +1290,95 @@ static bool knife_ray_intersect_face( */ static void calc_ortho_extent(KnifeTool_OpData *kcd) { - BMIter iter; - BMVert *v; - BMesh *bm = kcd->em->bm; - float min[3], max[3]; + BMIter iter; + BMVert *v; + BMesh *bm = kcd->em->bm; + float min[3], max[3]; - INIT_MINMAX(min, max); + INIT_MINMAX(min, max); - if (kcd->cagecos) { - minmax_v3v3_v3_array(min, max, kcd->cagecos, bm->totvert); - } - else { - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - minmax_v3v3_v3(min, max, v->co); - } - } + if (kcd->cagecos) { + minmax_v3v3_v3_array(min, max, kcd->cagecos, bm->totvert); + } + else { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + minmax_v3v3_v3(min, max, v->co); + } + } - kcd->ortho_extent = len_v3v3(min, max) / 2; - mid_v3_v3v3(kcd->ortho_extent_center, min, max); + kcd->ortho_extent = len_v3v3(min, max) / 2; + mid_v3_v3v3(kcd->ortho_extent_center, min, max); } static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe) { - BMElem *ele_test; - KnifeEdge *kfe = NULL; - - /* vert? */ - ele_test = (BMElem *)kfv->v; - - if (r_kfe || ele_test == NULL) { - if (kfv->v == NULL) { - Ref *ref; - for (ref = kfv->edges.first; ref; ref = ref->next) { - kfe = ref->ref; - if (kfe->e) { - if (r_kfe) { - *r_kfe = kfe; - } - break; - } - } - } - } - - /* edge? */ - if (ele_test == NULL) { - if (kfe) { - ele_test = (BMElem *)kfe->e; - } - } - - /* face? */ - if (ele_test == NULL) { - if (BLI_listbase_is_single(&kfe->faces)) { - ele_test = ((Ref *)kfe->faces.first)->ref; - } - } - - return ele_test; + BMElem *ele_test; + KnifeEdge *kfe = NULL; + + /* vert? */ + ele_test = (BMElem *)kfv->v; + + if (r_kfe || ele_test == NULL) { + if (kfv->v == NULL) { + Ref *ref; + for (ref = kfv->edges.first; ref; ref = ref->next) { + kfe = ref->ref; + if (kfe->e) { + if (r_kfe) { + *r_kfe = kfe; + } + break; + } + } + } + } + + /* edge? */ + if (ele_test == NULL) { + if (kfe) { + ele_test = (BMElem *)kfe->e; + } + } + + /* face? */ + if (ele_test == NULL) { + if (BLI_listbase_is_single(&kfe->faces)) { + ele_test = ((Ref *)kfe->faces.first)->ref; + } + } + + return ele_test; } static BMElem *bm_elem_from_knife_edge(KnifeEdge *kfe) { - BMElem *ele_test; + BMElem *ele_test; - ele_test = (BMElem *)kfe->e; + ele_test = (BMElem *)kfe->e; - if (ele_test == NULL) { - ele_test = (BMElem *)kfe->basef; - } + if (ele_test == NULL) { + ele_test = (BMElem *)kfe->basef; + } - return ele_test; + return ele_test; } /* Do edges e1 and e2 go between exactly the same coordinates? */ static bool coinciding_edges(BMEdge *e1, BMEdge *e2) { - const float *co11, *co12, *co21, *co22; + const float *co11, *co12, *co21, *co22; - co11 = e1->v1->co; - co12 = e1->v2->co; - co21 = e2->v1->co; - co22 = e2->v2->co; - if ((equals_v3v3(co11, co21) && equals_v3v3(co12, co22)) || - (equals_v3v3(co11, co22) && equals_v3v3(co12, co21))) - { - return true; - } - else { - return false; - } + co11 = e1->v1->co; + co12 = e1->v2->co; + co21 = e2->v1->co; + co22 = e2->v2->co; + if ((equals_v3v3(co11, co21) && equals_v3v3(co12, co22)) || + (equals_v3v3(co11, co22) && equals_v3v3(co12, co21))) { + return true; + } + else { + return false; + } } /* Callback used in point_is_visible to exclude hits on the faces that are the same @@ -1378,40 +1388,39 @@ static bool coinciding_edges(BMEdge *e1, BMEdge *e2) */ static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data) { - bool ans; - BMEdge *e, *e2; - BMIter iter; - - switch (((BMElem *)user_data)->head.htype) { - case BM_FACE: - ans = (BMFace *)user_data != f; - break; - case BM_EDGE: - e = (BMEdge *)user_data; - ans = !BM_edge_in_face(e, f); - if (ans) { - /* Is it a boundary edge, coincident with a split edge? */ - if (BM_edge_is_boundary(e)) { - BM_ITER_ELEM(e2, &iter, f, BM_EDGES_OF_FACE) { - if (coinciding_edges(e, e2)) { - ans = false; - break; - } - } - } - } - break; - case BM_VERT: - ans = !BM_vert_in_face((BMVert *)user_data, f); - break; - default: - ans = true; - break; - } - return ans; + bool ans; + BMEdge *e, *e2; + BMIter iter; + + switch (((BMElem *)user_data)->head.htype) { + case BM_FACE: + ans = (BMFace *)user_data != f; + break; + case BM_EDGE: + e = (BMEdge *)user_data; + ans = !BM_edge_in_face(e, f); + if (ans) { + /* Is it a boundary edge, coincident with a split edge? */ + if (BM_edge_is_boundary(e)) { + BM_ITER_ELEM (e2, &iter, f, BM_EDGES_OF_FACE) { + if (coinciding_edges(e, e2)) { + ans = false; + break; + } + } + } + } + break; + case BM_VERT: + ans = !BM_vert_in_face((BMVert *)user_data, f); + break; + default: + ans = true; + break; + } + return ans; } - /** * Check if \a p is visible (not clipped, not occluded by another face). * s in screen projection of p. @@ -1419,729 +1428,737 @@ static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data) * \param ele_test: Optional vert/edge/face to use when \a p is on the surface of the geometry, * intersecting faces matching this face (or connected when an vert/edge) will be ignored. */ -static bool point_is_visible( - KnifeTool_OpData *kcd, const float p[3], const float s[2], - BMElem *ele_test) -{ - BMFace *f_hit; - - /* If box clipping on, make sure p is not clipped */ - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING && - ED_view3d_clipping_test(kcd->vc.rv3d, p, true)) - { - return false; - } - - /* If not cutting through, make sure no face is in front of p */ - if (!kcd->cut_through) { - float dist; - float view[3], p_ofs[3]; - - /* TODO: I think there's a simpler way to get the required raycast ray */ - ED_view3d_unproject(kcd->vc.ar, s[0], s[1], 0.0f, view); - - mul_m4_v3(kcd->ob->imat, view); - - /* make p_ofs a little towards view, so ray doesn't hit p's face. */ - sub_v3_v3(view, p); - dist = normalize_v3(view); - copy_v3_v3(p_ofs, p); - - /* avoid projecting behind the viewpoint */ - if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { - dist = kcd->vc.v3d->clip_end * 2.0f; - } - - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { - float view_clip[2][3]; - /* note: view_clip[0] should never get clipped */ - copy_v3_v3(view_clip[0], p_ofs); - madd_v3_v3v3fl(view_clip[1], p_ofs, view, dist); - - if (clip_segment_v3_plane_n( - view_clip[0], view_clip[1], kcd->vc.rv3d->clip_local, 6, - view_clip[0], view_clip[1])) - { - dist = len_v3v3(p_ofs, view_clip[1]); - } - } - - /* see if there's a face hit between p1 and the view */ - if (ele_test) { - f_hit = BKE_bmbvh_ray_cast_filter( - kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL, - bm_ray_cast_cb_elem_not_in_face_check, ele_test); - } - else { - f_hit = BKE_bmbvh_ray_cast( - kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL); - } - - if (f_hit) { - return false; - } - } - - return true; +static bool point_is_visible(KnifeTool_OpData *kcd, + const float p[3], + const float s[2], + BMElem *ele_test) +{ + BMFace *f_hit; + + /* If box clipping on, make sure p is not clipped */ + if (kcd->vc.rv3d->rflag & RV3D_CLIPPING && ED_view3d_clipping_test(kcd->vc.rv3d, p, true)) { + return false; + } + + /* If not cutting through, make sure no face is in front of p */ + if (!kcd->cut_through) { + float dist; + float view[3], p_ofs[3]; + + /* TODO: I think there's a simpler way to get the required raycast ray */ + ED_view3d_unproject(kcd->vc.ar, s[0], s[1], 0.0f, view); + + mul_m4_v3(kcd->ob->imat, view); + + /* make p_ofs a little towards view, so ray doesn't hit p's face. */ + sub_v3_v3(view, p); + dist = normalize_v3(view); + copy_v3_v3(p_ofs, p); + + /* avoid projecting behind the viewpoint */ + if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { + dist = kcd->vc.v3d->clip_end * 2.0f; + } + + if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + float view_clip[2][3]; + /* note: view_clip[0] should never get clipped */ + copy_v3_v3(view_clip[0], p_ofs); + madd_v3_v3v3fl(view_clip[1], p_ofs, view, dist); + + if (clip_segment_v3_plane_n(view_clip[0], + view_clip[1], + kcd->vc.rv3d->clip_local, + 6, + view_clip[0], + view_clip[1])) { + dist = len_v3v3(p_ofs, view_clip[1]); + } + } + + /* see if there's a face hit between p1 and the view */ + if (ele_test) { + f_hit = BKE_bmbvh_ray_cast_filter(kcd->bmbvh, + p_ofs, + view, + KNIFE_FLT_EPS, + &dist, + NULL, + NULL, + bm_ray_cast_cb_elem_not_in_face_check, + ele_test); + } + else { + f_hit = BKE_bmbvh_ray_cast(kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL); + } + + if (f_hit) { + return false; + } + } + + return true; } /* Clip the line (v1, v2) to planes perpendicular to it and distances d from * the closest point on the line to the origin */ static void clip_to_ortho_planes(float v1[3], float v2[3], const float center[3], const float d) { - float closest[3], dir[3]; + float closest[3], dir[3]; - sub_v3_v3v3(dir, v1, v2); - normalize_v3(dir); + sub_v3_v3v3(dir, v1, v2); + normalize_v3(dir); - /* could be v1 or v2 */ - sub_v3_v3(v1, center); - project_plane_normalized_v3_v3v3(closest, v1, dir); - add_v3_v3(closest, center); + /* could be v1 or v2 */ + sub_v3_v3(v1, center); + project_plane_normalized_v3_v3v3(closest, v1, dir); + add_v3_v3(closest, center); - madd_v3_v3v3fl(v1, closest, dir, d); - madd_v3_v3v3fl(v2, closest, dir, -d); + madd_v3_v3v3fl(v1, closest, dir, d); + madd_v3_v3v3fl(v2, closest, dir, -d); } static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh) { - lh->m = dot_m4_v3_row_z(kcd->vc.rv3d->persmatob, lh->cagehit); + lh->m = dot_m4_v3_row_z(kcd->vc.rv3d->persmatob, lh->cagehit); } /* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */ static void knife_find_line_hits(KnifeTool_OpData *kcd) { - SmallHash faces, kfes, kfvs; - float v1[3], v2[3], v3[3], v4[3], s1[2], s2[2]; - BVHTree *planetree, *tree; - BVHTreeOverlap *results, *result; - BMLoop **ls; - BMFace *f; - KnifeEdge *kfe; - KnifeVert *v; - ListBase *lst; - Ref *ref; - KnifeLineHit *linehits = NULL; - BLI_array_declare(linehits); - SmallHashIter hiter; - KnifeLineHit hit; - void *val; - void **val_p; - float plane_cos[12]; - float s[2], se1[2], se2[2], sint[2]; - float r1[3], r2[3]; - float d, d1, d2, lambda; - float vert_tol, vert_tol_sq; - float line_tol, line_tol_sq; - float face_tol, face_tol_sq; - int isect_kind; - unsigned int tot; - int i; - const bool use_hit_prev = true; - const bool use_hit_curr = (kcd->is_drag_hold == false); - - if (kcd->linehits) { - MEM_freeN(kcd->linehits); - kcd->linehits = NULL; - kcd->totlinehit = 0; - } - - copy_v3_v3(v1, kcd->prev.cage); - copy_v3_v3(v2, kcd->curr.cage); - - /* project screen line's 3d coordinates back into 2d */ - knife_project_v2(kcd, v1, s1); - knife_project_v2(kcd, v2, s2); - - if (kcd->is_interactive) { - if (len_squared_v2v2(s1, s2) < 1.0f) { - return; - } - } - else { - if (len_squared_v2v2(s1, s2) < KNIFE_FLT_EPS_SQUARED) { - return; - } - } - - /* unproject screen line */ - ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s1, v1, v3, true); - ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s2, v2, v4, true); - - mul_m4_v3(kcd->ob->imat, v1); - mul_m4_v3(kcd->ob->imat, v2); - mul_m4_v3(kcd->ob->imat, v3); - mul_m4_v3(kcd->ob->imat, v4); - - /* numeric error, 'v1' -> 'v2', 'v2' -> 'v4' can end up being ~2000 units apart in otho mode - * (from ED_view3d_win_to_segment_clipped() above) - * this gives precision error; rather then solving properly - * (which may involve using doubles everywhere!), - * limit the distance between these points */ - if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { - if (kcd->ortho_extent == 0.0f) - calc_ortho_extent(kcd); - clip_to_ortho_planes(v1, v3, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f); - clip_to_ortho_planes(v2, v4, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f); - } - - /* First use bvh tree to find faces, knife edges, and knife verts that might - * intersect the cut plane with rays v1-v3 and v2-v4. - * This deduplicates the candidates before doing more expensive intersection tests. */ - - tree = BKE_bmbvh_tree_get(kcd->bmbvh); - planetree = BLI_bvhtree_new(4, FLT_EPSILON * 4, 8, 8); - copy_v3_v3(plane_cos + 0, v1); - copy_v3_v3(plane_cos + 3, v2); - copy_v3_v3(plane_cos + 6, v3); - copy_v3_v3(plane_cos + 9, v4); - BLI_bvhtree_insert(planetree, 0, plane_cos, 4); - BLI_bvhtree_balance(planetree); - - results = BLI_bvhtree_overlap(tree, planetree, &tot, NULL, NULL); - if (!results) { - BLI_bvhtree_free(planetree); - return; - } - - BLI_smallhash_init(&faces); - BLI_smallhash_init(&kfes); - BLI_smallhash_init(&kfvs); - - for (i = 0, result = results; i < tot; i++, result++) { - ls = (BMLoop **)kcd->em->looptris[result->indexA]; - f = ls[0]->f; - set_lowest_face_tri(kcd, f, result->indexA); - - /* occlude but never cut unselected faces (when only_select is used) */ - if (kcd->only_select && !BM_elem_flag_test(f, BM_ELEM_SELECT)) { - continue; - } - /* for faces, store index of lowest hit looptri in hash */ - if (BLI_smallhash_haskey(&faces, (uintptr_t)f)) { - continue; - } - /* don't care what the value is except that it is non-NULL, for iterator */ - BLI_smallhash_insert(&faces, (uintptr_t)f, f); - - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { - kfe = ref->ref; - if (BLI_smallhash_haskey(&kfes, (uintptr_t)kfe)) - continue; - BLI_smallhash_insert(&kfes, (uintptr_t)kfe, kfe); - v = kfe->v1; - BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v); - v = kfe->v2; - BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v); - } - } - - /* Now go through the candidates and find intersections */ - /* These tolerances, in screen space, are for intermediate hits, as ends are already snapped to screen */ - - if (kcd->is_interactive) { - vert_tol = KNIFE_FLT_EPS_PX_VERT; - line_tol = KNIFE_FLT_EPS_PX_EDGE; - face_tol = KNIFE_FLT_EPS_PX_FACE; - } - else { - /* Use 1/100th of a pixel, see T43896 (too big), T47910 (too small). - * - * Update, leave this as is until we investigate not using pixel coords for geometry calculations: T48023 - */ - vert_tol = line_tol = face_tol = 0.5f; - } - - vert_tol_sq = vert_tol * vert_tol; - line_tol_sq = line_tol * line_tol; - face_tol_sq = face_tol * face_tol; - - /* Assume these tolerances swamp floating point rounding errors in calculations below */ - - /* first look for vertex hits */ - for (val_p = BLI_smallhash_iternew_p(&kfvs, &hiter, (uintptr_t *)&v); val_p; - val_p = BLI_smallhash_iternext_p(&hiter, (uintptr_t *)&v)) - { - KnifeEdge *kfe_hit = NULL; - - knife_project_v2(kcd, v->cageco, s); - d = dist_squared_to_line_segment_v2(s, s1, s2); - if ((d <= vert_tol_sq) && - (point_is_visible(kcd, v->cageco, s, bm_elem_from_knife_vert(v, &kfe_hit)))) - { - memset(&hit, 0, sizeof(hit)); - hit.v = v; - - /* If this isn't from an existing BMVert, it may have been added to a BMEdge originally. - * knowing if the hit comes from an edge is important for edge-in-face checks later on - * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */ - if (kfe_hit) { - hit.kfe = kfe_hit; - } - - copy_v3_v3(hit.hit, v->co); - copy_v3_v3(hit.cagehit, v->cageco); - copy_v2_v2(hit.schit, s); - set_linehit_depth(kcd, &hit); - BLI_array_append(linehits, hit); - } - else { - /* note that these vertes aren't used */ - *val_p = NULL; - } - } - - /* now edge hits; don't add if a vertex at end of edge should have hit */ - for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val; - val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) - { - int kfe_verts_in_cut; - /* if we intersect both verts, don't attempt to intersect the edge */ - - kfe_verts_in_cut = (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) != NULL) + - (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2) != NULL); - - if (kfe_verts_in_cut == 2) { - continue; - } - - knife_project_v2(kcd, kfe->v1->cageco, se1); - knife_project_v2(kcd, kfe->v2->cageco, se2); - isect_kind = (kfe_verts_in_cut) ? -1 : isect_seg_seg_v2_point(s1, s2, se1, se2, sint); - if (isect_kind == -1) { - /* isect_seg_seg_v2_simple doesn't do tolerance test around ends of s1-s2 */ - closest_to_line_segment_v2(sint, s1, se1, se2); - if (len_squared_v2v2(sint, s1) <= line_tol_sq) - isect_kind = 1; - else { - closest_to_line_segment_v2(sint, s2, se1, se2); - if (len_squared_v2v2(sint, s2) <= line_tol_sq) - isect_kind = 1; - } - } - if (isect_kind == 1) { - d1 = len_v2v2(sint, se1); - d2 = len_v2v2(se2, se1); - if (!(d1 <= line_tol || d2 <= line_tol || fabsf(d1 - d2) <= line_tol)) { - float p_cage[3], p_cage_tmp[3]; - lambda = d1 / d2; - /* Can't just interpolate between ends of kfe because - * that doesn't work with perspective transformation. - * Need to find 3d intersection of ray through sint */ - knife_input_ray_segment(kcd, sint, 1.0f, r1, r2); - isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp); - if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, bm_elem_from_knife_edge(kfe))) { - memset(&hit, 0, sizeof(hit)); - if (kcd->snap_midpoints) { - /* choose intermediate point snap too */ - mid_v3_v3v3(p_cage, kfe->v1->cageco, kfe->v2->cageco); - mid_v2_v2v2(sint, se1, se2); - lambda = 0.5f; - } - hit.kfe = kfe; - transform_point_by_seg_v3( - hit.hit, p_cage, - kfe->v1->co, kfe->v2->co, - kfe->v1->cageco, kfe->v2->cageco); - copy_v3_v3(hit.cagehit, p_cage); - copy_v2_v2(hit.schit, sint); - hit.perc = lambda; - set_linehit_depth(kcd, &hit); - BLI_array_append(linehits, hit); - } - } - } - } - /* now face hits; don't add if a vertex or edge in face should have hit */ - for (val = BLI_smallhash_iternew(&faces, &hiter, (uintptr_t *)&f); val; - val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) - { - float p[3], p_cage[3]; - - if (use_hit_prev && knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) { - if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) { - memset(&hit, 0, sizeof(hit)); - hit.f = f; - copy_v3_v3(hit.hit, p); - copy_v3_v3(hit.cagehit, p_cage); - copy_v2_v2(hit.schit, s1); - set_linehit_depth(kcd, &hit); - BLI_array_append(linehits, hit); - } - } - - if (use_hit_curr && knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) { - if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) { - memset(&hit, 0, sizeof(hit)); - hit.f = f; - copy_v3_v3(hit.hit, p); - copy_v3_v3(hit.cagehit, p_cage); - copy_v2_v2(hit.schit, s2); - set_linehit_depth(kcd, &hit); - BLI_array_append(linehits, hit); - } - } - } - - kcd->linehits = linehits; - kcd->totlinehit = BLI_array_len(linehits); - - /* find position along screen line, used for sorting */ - for (i = 0; i < kcd->totlinehit; i++) { - KnifeLineHit *lh = kcd->linehits + i; - - lh->l = len_v2v2(lh->schit, s1) / len_v2v2(s2, s1); - } - - BLI_smallhash_release(&faces); - BLI_smallhash_release(&kfes); - BLI_smallhash_release(&kfvs); - BLI_bvhtree_free(planetree); - if (results) - MEM_freeN(results); -} - -static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], const float ofs, - float r_origin[3], float r_origin_ofs[3]) -{ - /* unproject to find view ray */ - ED_view3d_unproject(kcd->vc.ar, mval[0], mval[1], 0.0f, r_origin); - ED_view3d_unproject(kcd->vc.ar, mval[0], mval[1], ofs, r_origin_ofs); - - /* transform into object space */ - invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); - - mul_m4_v3(kcd->ob->imat, r_origin); - mul_m4_v3(kcd->ob->imat, r_origin_ofs); -} - -static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], bool *is_space) -{ - BMFace *f; - float dist = KMAXDIST; - float origin[3]; - float origin_ofs[3]; - float ray[3], ray_normal[3]; - - /* unproject to find view ray */ - knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); - sub_v3_v3v3(ray, origin_ofs, origin); - normalize_v3_v3(ray_normal, ray); - - f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray_normal, 0.0f, NULL, co, cageco); - - if (f && kcd->only_select && BM_elem_flag_test(f, BM_ELEM_SELECT) == 0) { - f = NULL; - } - - if (is_space) - *is_space = !f; - - if (!f) { - if (kcd->is_interactive) { - /* try to use backbuffer selection method if ray casting failed */ - f = EDBM_face_find_nearest(&kcd->vc, &dist); - - /* cheat for now; just put in the origin instead - * of a true coordinate on the face. - * This just puts a point 1.0f infront of the view. */ - add_v3_v3v3(co, origin, ray); - } - } - - return f; + SmallHash faces, kfes, kfvs; + float v1[3], v2[3], v3[3], v4[3], s1[2], s2[2]; + BVHTree *planetree, *tree; + BVHTreeOverlap *results, *result; + BMLoop **ls; + BMFace *f; + KnifeEdge *kfe; + KnifeVert *v; + ListBase *lst; + Ref *ref; + KnifeLineHit *linehits = NULL; + BLI_array_declare(linehits); + SmallHashIter hiter; + KnifeLineHit hit; + void *val; + void **val_p; + float plane_cos[12]; + float s[2], se1[2], se2[2], sint[2]; + float r1[3], r2[3]; + float d, d1, d2, lambda; + float vert_tol, vert_tol_sq; + float line_tol, line_tol_sq; + float face_tol, face_tol_sq; + int isect_kind; + unsigned int tot; + int i; + const bool use_hit_prev = true; + const bool use_hit_curr = (kcd->is_drag_hold == false); + + if (kcd->linehits) { + MEM_freeN(kcd->linehits); + kcd->linehits = NULL; + kcd->totlinehit = 0; + } + + copy_v3_v3(v1, kcd->prev.cage); + copy_v3_v3(v2, kcd->curr.cage); + + /* project screen line's 3d coordinates back into 2d */ + knife_project_v2(kcd, v1, s1); + knife_project_v2(kcd, v2, s2); + + if (kcd->is_interactive) { + if (len_squared_v2v2(s1, s2) < 1.0f) { + return; + } + } + else { + if (len_squared_v2v2(s1, s2) < KNIFE_FLT_EPS_SQUARED) { + return; + } + } + + /* unproject screen line */ + ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s1, v1, v3, true); + ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s2, v2, v4, true); + + mul_m4_v3(kcd->ob->imat, v1); + mul_m4_v3(kcd->ob->imat, v2); + mul_m4_v3(kcd->ob->imat, v3); + mul_m4_v3(kcd->ob->imat, v4); + + /* numeric error, 'v1' -> 'v2', 'v2' -> 'v4' can end up being ~2000 units apart in otho mode + * (from ED_view3d_win_to_segment_clipped() above) + * this gives precision error; rather then solving properly + * (which may involve using doubles everywhere!), + * limit the distance between these points */ + if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { + if (kcd->ortho_extent == 0.0f) + calc_ortho_extent(kcd); + clip_to_ortho_planes(v1, v3, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f); + clip_to_ortho_planes(v2, v4, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f); + } + + /* First use bvh tree to find faces, knife edges, and knife verts that might + * intersect the cut plane with rays v1-v3 and v2-v4. + * This deduplicates the candidates before doing more expensive intersection tests. */ + + tree = BKE_bmbvh_tree_get(kcd->bmbvh); + planetree = BLI_bvhtree_new(4, FLT_EPSILON * 4, 8, 8); + copy_v3_v3(plane_cos + 0, v1); + copy_v3_v3(plane_cos + 3, v2); + copy_v3_v3(plane_cos + 6, v3); + copy_v3_v3(plane_cos + 9, v4); + BLI_bvhtree_insert(planetree, 0, plane_cos, 4); + BLI_bvhtree_balance(planetree); + + results = BLI_bvhtree_overlap(tree, planetree, &tot, NULL, NULL); + if (!results) { + BLI_bvhtree_free(planetree); + return; + } + + BLI_smallhash_init(&faces); + BLI_smallhash_init(&kfes); + BLI_smallhash_init(&kfvs); + + for (i = 0, result = results; i < tot; i++, result++) { + ls = (BMLoop **)kcd->em->looptris[result->indexA]; + f = ls[0]->f; + set_lowest_face_tri(kcd, f, result->indexA); + + /* occlude but never cut unselected faces (when only_select is used) */ + if (kcd->only_select && !BM_elem_flag_test(f, BM_ELEM_SELECT)) { + continue; + } + /* for faces, store index of lowest hit looptri in hash */ + if (BLI_smallhash_haskey(&faces, (uintptr_t)f)) { + continue; + } + /* don't care what the value is except that it is non-NULL, for iterator */ + BLI_smallhash_insert(&faces, (uintptr_t)f, f); + + lst = knife_get_face_kedges(kcd, f); + for (ref = lst->first; ref; ref = ref->next) { + kfe = ref->ref; + if (BLI_smallhash_haskey(&kfes, (uintptr_t)kfe)) + continue; + BLI_smallhash_insert(&kfes, (uintptr_t)kfe, kfe); + v = kfe->v1; + BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v); + v = kfe->v2; + BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v); + } + } + + /* Now go through the candidates and find intersections */ + /* These tolerances, in screen space, are for intermediate hits, as ends are already snapped to screen */ + + if (kcd->is_interactive) { + vert_tol = KNIFE_FLT_EPS_PX_VERT; + line_tol = KNIFE_FLT_EPS_PX_EDGE; + face_tol = KNIFE_FLT_EPS_PX_FACE; + } + else { + /* Use 1/100th of a pixel, see T43896 (too big), T47910 (too small). + * + * Update, leave this as is until we investigate not using pixel coords for geometry calculations: T48023 + */ + vert_tol = line_tol = face_tol = 0.5f; + } + + vert_tol_sq = vert_tol * vert_tol; + line_tol_sq = line_tol * line_tol; + face_tol_sq = face_tol * face_tol; + + /* Assume these tolerances swamp floating point rounding errors in calculations below */ + + /* first look for vertex hits */ + for (val_p = BLI_smallhash_iternew_p(&kfvs, &hiter, (uintptr_t *)&v); val_p; + val_p = BLI_smallhash_iternext_p(&hiter, (uintptr_t *)&v)) { + KnifeEdge *kfe_hit = NULL; + + knife_project_v2(kcd, v->cageco, s); + d = dist_squared_to_line_segment_v2(s, s1, s2); + if ((d <= vert_tol_sq) && + (point_is_visible(kcd, v->cageco, s, bm_elem_from_knife_vert(v, &kfe_hit)))) { + memset(&hit, 0, sizeof(hit)); + hit.v = v; + + /* If this isn't from an existing BMVert, it may have been added to a BMEdge originally. + * knowing if the hit comes from an edge is important for edge-in-face checks later on + * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */ + if (kfe_hit) { + hit.kfe = kfe_hit; + } + + copy_v3_v3(hit.hit, v->co); + copy_v3_v3(hit.cagehit, v->cageco); + copy_v2_v2(hit.schit, s); + set_linehit_depth(kcd, &hit); + BLI_array_append(linehits, hit); + } + else { + /* note that these vertes aren't used */ + *val_p = NULL; + } + } + + /* now edge hits; don't add if a vertex at end of edge should have hit */ + for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val; + val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) { + int kfe_verts_in_cut; + /* if we intersect both verts, don't attempt to intersect the edge */ + + kfe_verts_in_cut = (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) != NULL) + + (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2) != NULL); + + if (kfe_verts_in_cut == 2) { + continue; + } + + knife_project_v2(kcd, kfe->v1->cageco, se1); + knife_project_v2(kcd, kfe->v2->cageco, se2); + isect_kind = (kfe_verts_in_cut) ? -1 : isect_seg_seg_v2_point(s1, s2, se1, se2, sint); + if (isect_kind == -1) { + /* isect_seg_seg_v2_simple doesn't do tolerance test around ends of s1-s2 */ + closest_to_line_segment_v2(sint, s1, se1, se2); + if (len_squared_v2v2(sint, s1) <= line_tol_sq) + isect_kind = 1; + else { + closest_to_line_segment_v2(sint, s2, se1, se2); + if (len_squared_v2v2(sint, s2) <= line_tol_sq) + isect_kind = 1; + } + } + if (isect_kind == 1) { + d1 = len_v2v2(sint, se1); + d2 = len_v2v2(se2, se1); + if (!(d1 <= line_tol || d2 <= line_tol || fabsf(d1 - d2) <= line_tol)) { + float p_cage[3], p_cage_tmp[3]; + lambda = d1 / d2; + /* Can't just interpolate between ends of kfe because + * that doesn't work with perspective transformation. + * Need to find 3d intersection of ray through sint */ + knife_input_ray_segment(kcd, sint, 1.0f, r1, r2); + isect_kind = isect_line_line_v3( + kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp); + if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, bm_elem_from_knife_edge(kfe))) { + memset(&hit, 0, sizeof(hit)); + if (kcd->snap_midpoints) { + /* choose intermediate point snap too */ + mid_v3_v3v3(p_cage, kfe->v1->cageco, kfe->v2->cageco); + mid_v2_v2v2(sint, se1, se2); + lambda = 0.5f; + } + hit.kfe = kfe; + transform_point_by_seg_v3( + hit.hit, p_cage, kfe->v1->co, kfe->v2->co, kfe->v1->cageco, kfe->v2->cageco); + copy_v3_v3(hit.cagehit, p_cage); + copy_v2_v2(hit.schit, sint); + hit.perc = lambda; + set_linehit_depth(kcd, &hit); + BLI_array_append(linehits, hit); + } + } + } + } + /* now face hits; don't add if a vertex or edge in face should have hit */ + for (val = BLI_smallhash_iternew(&faces, &hiter, (uintptr_t *)&f); val; + val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) { + float p[3], p_cage[3]; + + if (use_hit_prev && knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) { + if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) { + memset(&hit, 0, sizeof(hit)); + hit.f = f; + copy_v3_v3(hit.hit, p); + copy_v3_v3(hit.cagehit, p_cage); + copy_v2_v2(hit.schit, s1); + set_linehit_depth(kcd, &hit); + BLI_array_append(linehits, hit); + } + } + + if (use_hit_curr && knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) { + if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) { + memset(&hit, 0, sizeof(hit)); + hit.f = f; + copy_v3_v3(hit.hit, p); + copy_v3_v3(hit.cagehit, p_cage); + copy_v2_v2(hit.schit, s2); + set_linehit_depth(kcd, &hit); + BLI_array_append(linehits, hit); + } + } + } + + kcd->linehits = linehits; + kcd->totlinehit = BLI_array_len(linehits); + + /* find position along screen line, used for sorting */ + for (i = 0; i < kcd->totlinehit; i++) { + KnifeLineHit *lh = kcd->linehits + i; + + lh->l = len_v2v2(lh->schit, s1) / len_v2v2(s2, s1); + } + + BLI_smallhash_release(&faces); + BLI_smallhash_release(&kfes); + BLI_smallhash_release(&kfvs); + BLI_bvhtree_free(planetree); + if (results) + MEM_freeN(results); +} + +static void knife_input_ray_segment(KnifeTool_OpData *kcd, + const float mval[2], + const float ofs, + float r_origin[3], + float r_origin_ofs[3]) +{ + /* unproject to find view ray */ + ED_view3d_unproject(kcd->vc.ar, mval[0], mval[1], 0.0f, r_origin); + ED_view3d_unproject(kcd->vc.ar, mval[0], mval[1], ofs, r_origin_ofs); + + /* transform into object space */ + invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); + + mul_m4_v3(kcd->ob->imat, r_origin); + mul_m4_v3(kcd->ob->imat, r_origin_ofs); +} + +static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, + float co[3], + float cageco[3], + bool *is_space) +{ + BMFace *f; + float dist = KMAXDIST; + float origin[3]; + float origin_ofs[3]; + float ray[3], ray_normal[3]; + + /* unproject to find view ray */ + knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); + sub_v3_v3v3(ray, origin_ofs, origin); + normalize_v3_v3(ray_normal, ray); + + f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray_normal, 0.0f, NULL, co, cageco); + + if (f && kcd->only_select && BM_elem_flag_test(f, BM_ELEM_SELECT) == 0) { + f = NULL; + } + + if (is_space) + *is_space = !f; + + if (!f) { + if (kcd->is_interactive) { + /* try to use backbuffer selection method if ray casting failed */ + f = EDBM_face_find_nearest(&kcd->vc, &dist); + + /* cheat for now; just put in the origin instead + * of a true coordinate on the face. + * This just puts a point 1.0f infront of the view. */ + add_v3_v3v3(co, origin, ray); + } + } + + return f; } /* find the 2d screen space density of vertices within a radius. used to scale snapping * distance for picking edges/verts.*/ static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius) { - BMFace *f; - bool is_space; - float co[3], cageco[3], sco[2]; + BMFace *f; + bool is_space; + float co[3], cageco[3], sco[2]; - BLI_assert(kcd->is_interactive == true); + BLI_assert(kcd->is_interactive == true); - f = knife_find_closest_face(kcd, co, cageco, &is_space); + f = knife_find_closest_face(kcd, co, cageco, &is_space); - if (f && !is_space) { - const float radius_sq = radius * radius; - ListBase *lst; - Ref *ref; - float dis_sq; - int c = 0; + if (f && !is_space) { + const float radius_sq = radius * radius; + ListBase *lst; + Ref *ref; + float dis_sq; + int c = 0; - knife_project_v2(kcd, cageco, sco); + knife_project_v2(kcd, cageco, sco); - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { - KnifeEdge *kfe = ref->ref; - int i; + lst = knife_get_face_kedges(kcd, f); + for (ref = lst->first; ref; ref = ref->next) { + KnifeEdge *kfe = ref->ref; + int i; - for (i = 0; i < 2; i++) { - KnifeVert *kfv = i ? kfe->v2 : kfe->v1; + for (i = 0; i < 2; i++) { + KnifeVert *kfv = i ? kfe->v2 : kfe->v1; - knife_project_v2(kcd, kfv->cageco, kfv->sco); + knife_project_v2(kcd, kfv->cageco, kfv->sco); - dis_sq = len_squared_v2v2(kfv->sco, sco); - if (dis_sq < radius_sq) { - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { - if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) { - c++; - } - } - else { - c++; - } - } - } - } + dis_sq = len_squared_v2v2(kfv->sco, sco); + if (dis_sq < radius_sq) { + if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) { + c++; + } + } + else { + c++; + } + } + } + } - return c; - } + return c; + } - return 0; + return 0; } /* returns snapping distance for edges/verts, scaled by the density of the * surrounding mesh (in screen space)*/ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize) { - float density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f); + float density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f); - return min_ff(maxsize / (density * 0.5f), maxsize); + return min_ff(maxsize / (density * 0.5f), maxsize); } /* p is closest point on edge to the mouse cursor */ -static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], float cagep[3], - BMFace **fptr, bool *is_space) -{ - BMFace *f; - float co[3], cageco[3], sco[2]; - float maxdist; - - if (kcd->is_interactive) { - maxdist = knife_snap_size(kcd, kcd->ethresh); - - if (kcd->ignore_vert_snapping) { - maxdist *= 0.5f; - } - } - else { - maxdist = KNIFE_FLT_EPS; - } - - f = knife_find_closest_face(kcd, co, cageco, NULL); - *is_space = !f; - - kcd->curr.bmface = f; - - if (f) { - const float maxdist_sq = maxdist * maxdist; - KnifeEdge *cure = NULL; - float cur_cagep[3]; - ListBase *lst; - Ref *ref; - float dis_sq, curdis_sq = FLT_MAX; - - /* set p to co, in case we don't find anything, means a face cut */ - copy_v3_v3(p, co); - copy_v3_v3(cagep, cageco); - - knife_project_v2(kcd, cageco, sco); - - /* look through all edges associated with this face */ - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { - KnifeEdge *kfe = ref->ref; - float test_cagep[3]; - float lambda; - - /* project edge vertices into screen space */ - knife_project_v2(kcd, kfe->v1->cageco, kfe->v1->sco); - knife_project_v2(kcd, kfe->v2->cageco, kfe->v2->sco); - - /* check if we're close enough and calculate 'lambda' */ - if (kcd->is_angle_snapping) { - /* if snapping, check we're in bounds */ - float sco_snap[2]; - isect_line_line_v2_point(kfe->v1->sco, kfe->v2->sco, kcd->prev.mval, kcd->curr.mval, sco_snap); - lambda = line_point_factor_v2(sco_snap, kfe->v1->sco, kfe->v2->sco); - - /* be strict about angle-snapping within edge */ - if ((lambda < 0.0f - KNIFE_FLT_EPSBIG) || (lambda > 1.0f + KNIFE_FLT_EPSBIG)) { - continue; - } - - dis_sq = len_squared_v2v2(sco, sco_snap); - if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { - /* we already have 'lambda' */ - } - else { - continue; - } - } - else { - dis_sq = dist_squared_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco); - if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { - lambda = line_point_factor_v2(sco, kfe->v1->sco, kfe->v2->sco); - } - else { - continue; - } - } - - /* now we have 'lambda' calculated (in screen-space) */ - knife_interp_v3_v3v3(kcd, test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda); - - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { - /* check we're in the view */ - if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) { - continue; - } - } - - cure = kfe; - curdis_sq = dis_sq; - copy_v3_v3(cur_cagep, test_cagep); - } - - if (fptr) - *fptr = f; - - if (cure) { - if (!kcd->ignore_edge_snapping || !(cure->e)) { - KnifeVert *edgesnap = NULL; - - if (kcd->snap_midpoints) { - mid_v3_v3v3(p, cure->v1->co, cure->v2->co); - mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco); - } - else { - float lambda = line_point_factor_v3(cur_cagep, cure->v1->cageco, cure->v2->cageco); - copy_v3_v3(cagep, cur_cagep); - interp_v3_v3v3(p, cure->v1->co, cure->v2->co, lambda); - } - - /* update mouse coordinates to the snapped-to edge's screen coordinates - * this is important for angle snap, which uses the previous mouse position */ - edgesnap = new_knife_vert(kcd, p, cagep); - kcd->curr.mval[0] = edgesnap->sco[0]; - kcd->curr.mval[1] = edgesnap->sco[1]; - - } - else { - return NULL; - } - } - - return cure; - } - - if (fptr) - *fptr = NULL; - - return NULL; +static KnifeEdge *knife_find_closest_edge( + KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, bool *is_space) +{ + BMFace *f; + float co[3], cageco[3], sco[2]; + float maxdist; + + if (kcd->is_interactive) { + maxdist = knife_snap_size(kcd, kcd->ethresh); + + if (kcd->ignore_vert_snapping) { + maxdist *= 0.5f; + } + } + else { + maxdist = KNIFE_FLT_EPS; + } + + f = knife_find_closest_face(kcd, co, cageco, NULL); + *is_space = !f; + + kcd->curr.bmface = f; + + if (f) { + const float maxdist_sq = maxdist * maxdist; + KnifeEdge *cure = NULL; + float cur_cagep[3]; + ListBase *lst; + Ref *ref; + float dis_sq, curdis_sq = FLT_MAX; + + /* set p to co, in case we don't find anything, means a face cut */ + copy_v3_v3(p, co); + copy_v3_v3(cagep, cageco); + + knife_project_v2(kcd, cageco, sco); + + /* look through all edges associated with this face */ + lst = knife_get_face_kedges(kcd, f); + for (ref = lst->first; ref; ref = ref->next) { + KnifeEdge *kfe = ref->ref; + float test_cagep[3]; + float lambda; + + /* project edge vertices into screen space */ + knife_project_v2(kcd, kfe->v1->cageco, kfe->v1->sco); + knife_project_v2(kcd, kfe->v2->cageco, kfe->v2->sco); + + /* check if we're close enough and calculate 'lambda' */ + if (kcd->is_angle_snapping) { + /* if snapping, check we're in bounds */ + float sco_snap[2]; + isect_line_line_v2_point( + kfe->v1->sco, kfe->v2->sco, kcd->prev.mval, kcd->curr.mval, sco_snap); + lambda = line_point_factor_v2(sco_snap, kfe->v1->sco, kfe->v2->sco); + + /* be strict about angle-snapping within edge */ + if ((lambda < 0.0f - KNIFE_FLT_EPSBIG) || (lambda > 1.0f + KNIFE_FLT_EPSBIG)) { + continue; + } + + dis_sq = len_squared_v2v2(sco, sco_snap); + if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { + /* we already have 'lambda' */ + } + else { + continue; + } + } + else { + dis_sq = dist_squared_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco); + if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { + lambda = line_point_factor_v2(sco, kfe->v1->sco, kfe->v2->sco); + } + else { + continue; + } + } + + /* now we have 'lambda' calculated (in screen-space) */ + knife_interp_v3_v3v3(kcd, test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda); + + if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + /* check we're in the view */ + if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) { + continue; + } + } + + cure = kfe; + curdis_sq = dis_sq; + copy_v3_v3(cur_cagep, test_cagep); + } + + if (fptr) + *fptr = f; + + if (cure) { + if (!kcd->ignore_edge_snapping || !(cure->e)) { + KnifeVert *edgesnap = NULL; + + if (kcd->snap_midpoints) { + mid_v3_v3v3(p, cure->v1->co, cure->v2->co); + mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco); + } + else { + float lambda = line_point_factor_v3(cur_cagep, cure->v1->cageco, cure->v2->cageco); + copy_v3_v3(cagep, cur_cagep); + interp_v3_v3v3(p, cure->v1->co, cure->v2->co, lambda); + } + + /* update mouse coordinates to the snapped-to edge's screen coordinates + * this is important for angle snap, which uses the previous mouse position */ + edgesnap = new_knife_vert(kcd, p, cagep); + kcd->curr.mval[0] = edgesnap->sco[0]; + kcd->curr.mval[1] = edgesnap->sco[1]; + } + else { + return NULL; + } + } + + return cure; + } + + if (fptr) + *fptr = NULL; + + return NULL; } /* find a vertex near the mouse cursor, if it exists */ -static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, - bool *is_space) -{ - BMFace *f; - float co[3], cageco[3], sco[2]; - float maxdist; - - if (kcd->is_interactive) { - maxdist = knife_snap_size(kcd, kcd->vthresh); - if (kcd->ignore_vert_snapping) { - maxdist *= 0.5f; - } - } - else { - maxdist = KNIFE_FLT_EPS; - } - - f = knife_find_closest_face(kcd, co, cageco, is_space); - - kcd->curr.bmface = f; - - if (f) { - const float maxdist_sq = maxdist * maxdist; - ListBase *lst; - Ref *ref; - KnifeVert *curv = NULL; - float dis_sq, curdis_sq = FLT_MAX; - - /* set p to co, in case we don't find anything, means a face cut */ - copy_v3_v3(p, co); - copy_v3_v3(cagep, cageco); - - knife_project_v2(kcd, cageco, sco); - - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { - KnifeEdge *kfe = ref->ref; - int i; - - for (i = 0; i < 2; i++) { - KnifeVert *kfv = i ? kfe->v2 : kfe->v1; - - knife_project_v2(kcd, kfv->cageco, kfv->sco); - - /* be strict about angle snapping, the vertex needs to be very close to the angle, - * or we ignore */ - if (kcd->is_angle_snapping) { - if (dist_squared_to_line_segment_v2(kfv->sco, kcd->prev.mval, kcd->curr.mval) > KNIFE_FLT_EPSBIG) { - continue; - } - } - - dis_sq = len_squared_v2v2(kfv->sco, sco); - if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { - if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) { - curv = kfv; - curdis_sq = dis_sq; - } - } - else { - curv = kfv; - curdis_sq = dis_sq; - } - } - } - } - - if (!kcd->ignore_vert_snapping || !(curv && curv->v)) { - if (fptr) - *fptr = f; - - if (curv) { - copy_v3_v3(p, curv->co); - copy_v3_v3(cagep, curv->cageco); - - /* update mouse coordinates to the snapped-to vertex's screen coordinates - * this is important for angle snap, which uses the previous mouse position */ - kcd->curr.mval[0] = curv->sco[0]; - kcd->curr.mval[1] = curv->sco[1]; - } - - return curv; - } - else { - if (fptr) - *fptr = f; - - return NULL; - } - } - - if (fptr) - *fptr = NULL; - - return NULL; +static KnifeVert *knife_find_closest_vert( + KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, bool *is_space) +{ + BMFace *f; + float co[3], cageco[3], sco[2]; + float maxdist; + + if (kcd->is_interactive) { + maxdist = knife_snap_size(kcd, kcd->vthresh); + if (kcd->ignore_vert_snapping) { + maxdist *= 0.5f; + } + } + else { + maxdist = KNIFE_FLT_EPS; + } + + f = knife_find_closest_face(kcd, co, cageco, is_space); + + kcd->curr.bmface = f; + + if (f) { + const float maxdist_sq = maxdist * maxdist; + ListBase *lst; + Ref *ref; + KnifeVert *curv = NULL; + float dis_sq, curdis_sq = FLT_MAX; + + /* set p to co, in case we don't find anything, means a face cut */ + copy_v3_v3(p, co); + copy_v3_v3(cagep, cageco); + + knife_project_v2(kcd, cageco, sco); + + lst = knife_get_face_kedges(kcd, f); + for (ref = lst->first; ref; ref = ref->next) { + KnifeEdge *kfe = ref->ref; + int i; + + for (i = 0; i < 2; i++) { + KnifeVert *kfv = i ? kfe->v2 : kfe->v1; + + knife_project_v2(kcd, kfv->cageco, kfv->sco); + + /* be strict about angle snapping, the vertex needs to be very close to the angle, + * or we ignore */ + if (kcd->is_angle_snapping) { + if (dist_squared_to_line_segment_v2(kfv->sco, kcd->prev.mval, kcd->curr.mval) > + KNIFE_FLT_EPSBIG) { + continue; + } + } + + dis_sq = len_squared_v2v2(kfv->sco, sco); + if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { + if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) { + curv = kfv; + curdis_sq = dis_sq; + } + } + else { + curv = kfv; + curdis_sq = dis_sq; + } + } + } + } + + if (!kcd->ignore_vert_snapping || !(curv && curv->v)) { + if (fptr) + *fptr = f; + + if (curv) { + copy_v3_v3(p, curv->co); + copy_v3_v3(cagep, curv->cageco); + + /* update mouse coordinates to the snapped-to vertex's screen coordinates + * this is important for angle snap, which uses the previous mouse position */ + kcd->curr.mval[0] = curv->sco[0]; + kcd->curr.mval[1] = curv->sco[1]; + } + + return curv; + } + else { + if (fptr) + *fptr = f; + + return NULL; + } + } + + if (fptr) + *fptr = NULL; + + return NULL; } /** @@ -2149,859 +2166,863 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo */ static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], float angle_snap) { - float m2[2][2]; - float v_unit[2]; - float angle, angle_delta; + float m2[2][2]; + float v_unit[2]; + float angle, angle_delta; - BLI_ASSERT_UNIT_V2(v_ref); + BLI_ASSERT_UNIT_V2(v_ref); - normalize_v2_v2(v_unit, v); - angle = angle_signed_v2v2(v_unit, v_ref); - angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle; - angle_to_mat2(m2, angle_delta); + normalize_v2_v2(v_unit, v); + angle = angle_signed_v2v2(v_unit, v_ref); + angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle; + angle_to_mat2(m2, angle_delta); - mul_v2_m2v2(r, m2, v); - return angle + angle_delta; + mul_v2_m2v2(r, m2, v); + return angle + angle_delta; } /* update both kcd->curr.mval and kcd->mval to snap to required angle */ static bool knife_snap_angle(KnifeTool_OpData *kcd) { - const float dvec_ref[2] = {0.0f, 1.0f}; - float dvec[2], dvec_snap[2]; - float snap_step = DEG2RADF(45); + const float dvec_ref[2] = {0.0f, 1.0f}; + float dvec[2], dvec_snap[2]; + float snap_step = DEG2RADF(45); - sub_v2_v2v2(dvec, kcd->curr.mval, kcd->prev.mval); - if (is_zero_v2(dvec)) { - return false; - } + sub_v2_v2v2(dvec, kcd->curr.mval, kcd->prev.mval); + if (is_zero_v2(dvec)) { + return false; + } - kcd->angle = snap_v2_angle(dvec_snap, dvec, dvec_ref, snap_step); + kcd->angle = snap_v2_angle(dvec_snap, dvec, dvec_ref, snap_step); - add_v2_v2v2(kcd->curr.mval, kcd->prev.mval, dvec_snap); + add_v2_v2v2(kcd->curr.mval, kcd->prev.mval, dvec_snap); - copy_v2_v2(kcd->mval, kcd->curr.mval); + copy_v2_v2(kcd->mval, kcd->curr.mval); - return true; + return true; } /* update active knife edge/vert pointers */ static int knife_update_active(KnifeTool_OpData *kcd) { - knife_pos_data_clear(&kcd->curr); - copy_v2_v2(kcd->curr.mval, kcd->mval); + knife_pos_data_clear(&kcd->curr); + copy_v2_v2(kcd->curr.mval, kcd->mval); - /* view matrix may have changed, reproject */ - knife_project_v2(kcd, kcd->prev.cage, kcd->prev.mval); + /* view matrix may have changed, reproject */ + knife_project_v2(kcd, kcd->prev.cage, kcd->prev.mval); - if (kcd->angle_snapping && (kcd->mode == MODE_DRAGGING)) { - kcd->is_angle_snapping = knife_snap_angle(kcd); - } - else { - kcd->is_angle_snapping = false; - } + if (kcd->angle_snapping && (kcd->mode == MODE_DRAGGING)) { + kcd->is_angle_snapping = knife_snap_angle(kcd); + } + else { + kcd->is_angle_snapping = false; + } - kcd->curr.vert = knife_find_closest_vert(kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space); + kcd->curr.vert = knife_find_closest_vert( + kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space); - if (!kcd->curr.vert && - /* no edge snapping while dragging (edges are too sticky when cuts are immediate) */ - !kcd->is_drag_hold) - { - kcd->curr.edge = knife_find_closest_edge(kcd, kcd->curr.co, kcd->curr.cage, - &kcd->curr.bmface, &kcd->curr.is_space); - } + if (!kcd->curr.vert && + /* no edge snapping while dragging (edges are too sticky when cuts are immediate) */ + !kcd->is_drag_hold) { + kcd->curr.edge = knife_find_closest_edge( + kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space); + } - /* if no hits are found this would normally default to (0, 0, 0) so instead - * get a point at the mouse ray closest to the previous point. - * Note that drawing lines in `free-space` isn't properly supported - * but there's no guarantee (0, 0, 0) has any geometry either - campbell */ - if (kcd->curr.vert == NULL && kcd->curr.edge == NULL && kcd->curr.bmface == NULL) { - float origin[3]; - float origin_ofs[3]; + /* if no hits are found this would normally default to (0, 0, 0) so instead + * get a point at the mouse ray closest to the previous point. + * Note that drawing lines in `free-space` isn't properly supported + * but there's no guarantee (0, 0, 0) has any geometry either - campbell */ + if (kcd->curr.vert == NULL && kcd->curr.edge == NULL && kcd->curr.bmface == NULL) { + float origin[3]; + float origin_ofs[3]; - knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); + knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); - if (!isect_line_plane_v3(kcd->curr.cage, origin, origin_ofs, kcd->prev.cage, kcd->proj_zaxis)) { - copy_v3_v3(kcd->curr.cage, kcd->prev.cage); + if (!isect_line_plane_v3( + kcd->curr.cage, origin, origin_ofs, kcd->prev.cage, kcd->proj_zaxis)) { + copy_v3_v3(kcd->curr.cage, kcd->prev.cage); - /* should never fail! */ - BLI_assert(0); - } - } + /* should never fail! */ + BLI_assert(0); + } + } - if (kcd->mode == MODE_DRAGGING) { - knife_find_line_hits(kcd); - } - return 1; + if (kcd->mode == MODE_DRAGGING) { + knife_find_line_hits(kcd); + } + return 1; } static int sort_verts_by_dist_cb(void *co_p, const void *cur_a_p, const void *cur_b_p) { - const KnifeVert *cur_a = ((const Ref *)cur_a_p)->ref; - const KnifeVert *cur_b = ((const Ref *)cur_b_p)->ref; - const float *co = co_p; - const float a_sq = len_squared_v3v3(co, cur_a->co); - const float b_sq = len_squared_v3v3(co, cur_b->co); + const KnifeVert *cur_a = ((const Ref *)cur_a_p)->ref; + const KnifeVert *cur_b = ((const Ref *)cur_b_p)->ref; + const float *co = co_p; + const float a_sq = len_squared_v3v3(co, cur_a->co); + const float b_sq = len_squared_v3v3(co, cur_b->co); - if (a_sq < b_sq) return -1; - else if (a_sq > b_sq) return 1; - else return 0; + if (a_sq < b_sq) + return -1; + else if (a_sq > b_sq) + return 1; + else + return 0; } static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f) { - bool v1_inside, v2_inside; - bool v1_inface, v2_inface; - BMLoop *l1, *l2; - - if (!f || !v1 || !v2) - return false; - - l1 = v1->v ? BM_face_vert_share_loop(f, v1->v) : NULL; - l2 = v2->v ? BM_face_vert_share_loop(f, v2->v) : NULL; - - if ((l1 && l2) && BM_loop_is_adjacent(l1, l2)) { - /* boundary-case, always false to avoid edge-in-face checks below */ - return false; - } - - /* find out if v1 and v2, if set, are part of the face */ - v1_inface = (l1 != NULL); - v2_inface = (l2 != NULL); - - /* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */ - v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co); - v2_inside = v2_inface ? false : BM_face_point_inside_test(f, v2->co); - if ((v1_inface && v2_inside) || - (v2_inface && v1_inside) || - (v1_inside && v2_inside)) - { - return true; - } - - if (v1_inface && v2_inface) { - float mid[3]; - /* Can have case where v1 and v2 are on shared chain between two faces. - * BM_face_splits_check_legal does visibility and self-intersection tests, - * but it is expensive and maybe a bit buggy, so use a simple - * "is the midpoint in the face" test */ - mid_v3_v3v3(mid, v1->co, v2->co); - return BM_face_point_inside_test(f, mid); - } - return false; + bool v1_inside, v2_inside; + bool v1_inface, v2_inface; + BMLoop *l1, *l2; + + if (!f || !v1 || !v2) + return false; + + l1 = v1->v ? BM_face_vert_share_loop(f, v1->v) : NULL; + l2 = v2->v ? BM_face_vert_share_loop(f, v2->v) : NULL; + + if ((l1 && l2) && BM_loop_is_adjacent(l1, l2)) { + /* boundary-case, always false to avoid edge-in-face checks below */ + return false; + } + + /* find out if v1 and v2, if set, are part of the face */ + v1_inface = (l1 != NULL); + v2_inface = (l2 != NULL); + + /* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */ + v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co); + v2_inside = v2_inface ? false : BM_face_point_inside_test(f, v2->co); + if ((v1_inface && v2_inside) || (v2_inface && v1_inside) || (v1_inside && v2_inside)) { + return true; + } + + if (v1_inface && v2_inface) { + float mid[3]; + /* Can have case where v1 and v2 are on shared chain between two faces. + * BM_face_splits_check_legal does visibility and self-intersection tests, + * but it is expensive and maybe a bit buggy, so use a simple + * "is the midpoint in the face" test */ + mid_v3_v3v3(mid, v1->co, v2->co); + return BM_face_point_inside_test(f, mid); + } + return false; } static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges) { - BMesh *bm = kcd->em->bm; - KnifeEdge *kfe; - Ref *ref; - int edge_array_len = BLI_listbase_count(kfedges); - int i; - - BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len); - - /* point to knife edges we've created edges in, edge_array aligned */ - KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len); - - BLI_assert(BLI_gset_len(kcd->edgenet.edge_visit) == 0); - - i = 0; - for (ref = kfedges->first; ref; ref = ref->next) { - bool is_new_edge = false; - kfe = ref->ref; - - if (kfe->e == NULL) { - if (kfe->v1->v && kfe->v2->v) { - kfe->e = BM_edge_exists(kfe->v1->v, kfe->v2->v); - } - } - - if (kfe->e) { - if (BM_edge_in_face(kfe->e, f)) { - /* shouldn't happen, but in this case - just ignore */ - continue; - } - } - else { - if (kfe->v1->v == NULL) { - kfe->v1->v = BM_vert_create(bm, kfe->v1->co, NULL, 0); - } - if (kfe->v2->v == NULL) { - kfe->v2->v = BM_vert_create(bm, kfe->v2->co, NULL, 0); - } - BLI_assert(kfe->e == NULL); - kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, 0); - if (kfe->e) { - if (kcd->select_result || BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_edge_select_set(bm, kfe->e, true); - } - is_new_edge = true; - } - } - - BLI_assert(kfe->e); - - if (BLI_gset_add(kcd->edgenet.edge_visit, kfe->e)) { - kfe_array[i] = is_new_edge ? kfe : 0; - edge_array[i] = kfe->e; - i += 1; - } - } - - if (i) { - const int edge_array_len_orig = i; - edge_array_len = i; + BMesh *bm = kcd->em->bm; + KnifeEdge *kfe; + Ref *ref; + int edge_array_len = BLI_listbase_count(kfedges); + int i; + + BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len); + + /* point to knife edges we've created edges in, edge_array aligned */ + KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len); + + BLI_assert(BLI_gset_len(kcd->edgenet.edge_visit) == 0); + + i = 0; + for (ref = kfedges->first; ref; ref = ref->next) { + bool is_new_edge = false; + kfe = ref->ref; + + if (kfe->e == NULL) { + if (kfe->v1->v && kfe->v2->v) { + kfe->e = BM_edge_exists(kfe->v1->v, kfe->v2->v); + } + } + + if (kfe->e) { + if (BM_edge_in_face(kfe->e, f)) { + /* shouldn't happen, but in this case - just ignore */ + continue; + } + } + else { + if (kfe->v1->v == NULL) { + kfe->v1->v = BM_vert_create(bm, kfe->v1->co, NULL, 0); + } + if (kfe->v2->v == NULL) { + kfe->v2->v = BM_vert_create(bm, kfe->v2->co, NULL, 0); + } + BLI_assert(kfe->e == NULL); + kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, 0); + if (kfe->e) { + if (kcd->select_result || BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_edge_select_set(bm, kfe->e, true); + } + is_new_edge = true; + } + } + + BLI_assert(kfe->e); + + if (BLI_gset_add(kcd->edgenet.edge_visit, kfe->e)) { + kfe_array[i] = is_new_edge ? kfe : 0; + edge_array[i] = kfe->e; + i += 1; + } + } + + if (i) { + const int edge_array_len_orig = i; + edge_array_len = i; #ifdef USE_NET_ISLAND_CONNECT - unsigned int edge_array_holes_len; - BMEdge **edge_array_holes; - if (BM_face_split_edgenet_connect_islands( - bm, f, - edge_array, edge_array_len, - true, - kcd->edgenet.arena, - &edge_array_holes, &edge_array_holes_len)) - { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - for (i = edge_array_len; i < edge_array_holes_len; i++) { - BM_edge_select_set(bm, edge_array_holes[i], true); - } - } - - edge_array_len = edge_array_holes_len; - edge_array = edge_array_holes; /* owned by the arena */ - } + unsigned int edge_array_holes_len; + BMEdge **edge_array_holes; + if (BM_face_split_edgenet_connect_islands(bm, + f, + edge_array, + edge_array_len, + true, + kcd->edgenet.arena, + &edge_array_holes, + &edge_array_holes_len)) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + for (i = edge_array_len; i < edge_array_holes_len; i++) { + BM_edge_select_set(bm, edge_array_holes[i], true); + } + } + + edge_array_len = edge_array_holes_len; + edge_array = edge_array_holes; /* owned by the arena */ + } #endif - { - BMFace **face_arr = NULL; - int face_arr_len; + { + BMFace **face_arr = NULL; + int face_arr_len; - BM_face_split_edgenet( - bm, f, edge_array, edge_array_len, - &face_arr, &face_arr_len); + BM_face_split_edgenet(bm, f, edge_array, edge_array_len, &face_arr, &face_arr_len); - if (face_arr) { - MEM_freeN(face_arr); - } - } - - /* remove dangling edges, not essential - but nice for users */ - for (i = 0; i < edge_array_len_orig; i++) { - if (kfe_array[i]) { - if (BM_edge_is_wire(kfe_array[i]->e)) { - BM_edge_kill(bm, kfe_array[i]->e); - kfe_array[i]->e = NULL; - } - } - } + if (face_arr) { + MEM_freeN(face_arr); + } + } + /* remove dangling edges, not essential - but nice for users */ + for (i = 0; i < edge_array_len_orig; i++) { + if (kfe_array[i]) { + if (BM_edge_is_wire(kfe_array[i]->e)) { + BM_edge_kill(bm, kfe_array[i]->e); + kfe_array[i]->e = NULL; + } + } + } #ifdef USE_NET_ISLAND_CONNECT - BLI_memarena_clear(kcd->edgenet.arena); + BLI_memarena_clear(kcd->edgenet.arena); #endif - } + } - BLI_gset_clear(kcd->edgenet.edge_visit, NULL); + BLI_gset_clear(kcd->edgenet.edge_visit, NULL); } /* Use the network of KnifeEdges and KnifeVerts accumulated to make real BMVerts and BMEdedges */ static void knife_make_cuts(KnifeTool_OpData *kcd) { - BMesh *bm = kcd->em->bm; - KnifeEdge *kfe; - KnifeVert *kfv; - BMFace *f; - BMEdge *e, *enew; - ListBase *lst; - Ref *ref; - float pct; - SmallHashIter hiter; - BLI_mempool_iter iter; - SmallHash fhash_, *fhash = &fhash_; - SmallHash ehash_, *ehash = &ehash_; - - BLI_smallhash_init(fhash); - BLI_smallhash_init(ehash); - - /* put list of cutting edges for a face into fhash, keyed by face */ - BLI_mempool_iternew(kcd->kedges, &iter); - for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { - - /* select edges that lie directly on the cut */ - if (kcd->select_result) { - if (kfe->e && kfe->is_cut) { - BM_edge_select_set(bm, kfe->e, true); - } - } - - f = kfe->basef; - if (!f || kfe->e) - continue; - lst = BLI_smallhash_lookup(fhash, (uintptr_t)f); - if (!lst) { - lst = knife_empty_list(kcd); - BLI_smallhash_insert(fhash, (uintptr_t)f, lst); - } - knife_append_list(kcd, lst, kfe); - } - - /* put list of splitting vertices for an edge into ehash, keyed by edge */ - BLI_mempool_iternew(kcd->kverts, &iter); - for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { - if (kfv->v) - continue; /* already have a BMVert */ - for (ref = kfv->edges.first; ref; ref = ref->next) { - kfe = ref->ref; - e = kfe->e; - if (!e) - continue; - lst = BLI_smallhash_lookup(ehash, (uintptr_t)e); - if (!lst) { - lst = knife_empty_list(kcd); - BLI_smallhash_insert(ehash, (uintptr_t)e, lst); - } - /* there can be more than one kfe in kfv's list with same e */ - if (!find_ref(lst, kfv)) - knife_append_list(kcd, lst, kfv); - } - } - - /* split bmesh edges where needed */ - for (lst = BLI_smallhash_iternew(ehash, &hiter, (uintptr_t *)&e); lst; - lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&e)) - { - BLI_listbase_sort_r(lst, sort_verts_by_dist_cb, e->v1->co); - - for (ref = lst->first; ref; ref = ref->next) { - kfv = ref->ref; - pct = line_point_factor_v3(kfv->co, e->v1->co, e->v2->co); - kfv->v = BM_edge_split(bm, e, e->v1, &enew, pct); - } - } - - if (kcd->only_select) { - EDBM_flag_disable_all(kcd->em, BM_ELEM_SELECT); - } - - /* do cuts for each face */ - for (lst = BLI_smallhash_iternew(fhash, &hiter, (uintptr_t *)&f); lst; - lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) - { - knife_make_face_cuts(kcd, f, lst); - } - - BLI_smallhash_release(fhash); - BLI_smallhash_release(ehash); + BMesh *bm = kcd->em->bm; + KnifeEdge *kfe; + KnifeVert *kfv; + BMFace *f; + BMEdge *e, *enew; + ListBase *lst; + Ref *ref; + float pct; + SmallHashIter hiter; + BLI_mempool_iter iter; + SmallHash fhash_, *fhash = &fhash_; + SmallHash ehash_, *ehash = &ehash_; + + BLI_smallhash_init(fhash); + BLI_smallhash_init(ehash); + + /* put list of cutting edges for a face into fhash, keyed by face */ + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { + + /* select edges that lie directly on the cut */ + if (kcd->select_result) { + if (kfe->e && kfe->is_cut) { + BM_edge_select_set(bm, kfe->e, true); + } + } + + f = kfe->basef; + if (!f || kfe->e) + continue; + lst = BLI_smallhash_lookup(fhash, (uintptr_t)f); + if (!lst) { + lst = knife_empty_list(kcd); + BLI_smallhash_insert(fhash, (uintptr_t)f, lst); + } + knife_append_list(kcd, lst, kfe); + } + + /* put list of splitting vertices for an edge into ehash, keyed by edge */ + BLI_mempool_iternew(kcd->kverts, &iter); + for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { + if (kfv->v) + continue; /* already have a BMVert */ + for (ref = kfv->edges.first; ref; ref = ref->next) { + kfe = ref->ref; + e = kfe->e; + if (!e) + continue; + lst = BLI_smallhash_lookup(ehash, (uintptr_t)e); + if (!lst) { + lst = knife_empty_list(kcd); + BLI_smallhash_insert(ehash, (uintptr_t)e, lst); + } + /* there can be more than one kfe in kfv's list with same e */ + if (!find_ref(lst, kfv)) + knife_append_list(kcd, lst, kfv); + } + } + + /* split bmesh edges where needed */ + for (lst = BLI_smallhash_iternew(ehash, &hiter, (uintptr_t *)&e); lst; + lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&e)) { + BLI_listbase_sort_r(lst, sort_verts_by_dist_cb, e->v1->co); + + for (ref = lst->first; ref; ref = ref->next) { + kfv = ref->ref; + pct = line_point_factor_v3(kfv->co, e->v1->co, e->v2->co); + kfv->v = BM_edge_split(bm, e, e->v1, &enew, pct); + } + } + + if (kcd->only_select) { + EDBM_flag_disable_all(kcd->em, BM_ELEM_SELECT); + } + + /* do cuts for each face */ + for (lst = BLI_smallhash_iternew(fhash, &hiter, (uintptr_t *)&f); lst; + lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) { + knife_make_face_cuts(kcd, f, lst); + } + + BLI_smallhash_release(fhash); + BLI_smallhash_release(ehash); } /* called on tool confirmation */ static void knifetool_finish_ex(KnifeTool_OpData *kcd) { - knife_make_cuts(kcd); + knife_make_cuts(kcd); - EDBM_selectmode_flush(kcd->em); - EDBM_mesh_normals_update(kcd->em); - EDBM_update_generic(kcd->em, true, true); + EDBM_selectmode_flush(kcd->em); + EDBM_mesh_normals_update(kcd->em); + EDBM_update_generic(kcd->em, true, true); - /* re-tessellating makes this invalid, dont use again by accident */ - knifetool_free_bmbvh(kcd); + /* re-tessellating makes this invalid, dont use again by accident */ + knifetool_free_bmbvh(kcd); } static void knifetool_finish(wmOperator *op) { - KnifeTool_OpData *kcd = op->customdata; - knifetool_finish_ex(kcd); + KnifeTool_OpData *kcd = op->customdata; + knifetool_finish_ex(kcd); } static void knife_recalc_projmat(KnifeTool_OpData *kcd) { - invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); - ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat); - invert_m4_m4(kcd->projmat_inv, kcd->projmat); + invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); + ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat); + invert_m4_m4(kcd->projmat_inv, kcd->projmat); - mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]); - normalize_v3(kcd->proj_zaxis); + mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]); + normalize_v3(kcd->proj_zaxis); - kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.depsgraph, - kcd->vc.v3d, kcd->vc.rv3d, - &kcd->clipsta, &kcd->clipend, true); + kcd->is_ortho = ED_view3d_clip_range_get( + kcd->vc.depsgraph, kcd->vc.v3d, kcd->vc.rv3d, &kcd->clipsta, &kcd->clipend, true); } /* called when modal loop selection is done... */ static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd) { - if (!kcd) - return; + if (!kcd) + return; - if (kcd->is_interactive) { - WM_cursor_modal_restore(CTX_wm_window(C)); + if (kcd->is_interactive) { + WM_cursor_modal_restore(CTX_wm_window(C)); - /* deactivate the extra drawing stuff in 3D-View */ - ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle); - } + /* deactivate the extra drawing stuff in 3D-View */ + ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle); + } - /* free the custom data */ - BLI_mempool_destroy(kcd->refs); - BLI_mempool_destroy(kcd->kverts); - BLI_mempool_destroy(kcd->kedges); + /* free the custom data */ + BLI_mempool_destroy(kcd->refs); + BLI_mempool_destroy(kcd->kverts); + BLI_mempool_destroy(kcd->kedges); - BLI_ghash_free(kcd->origedgemap, NULL, NULL); - BLI_ghash_free(kcd->origvertmap, NULL, NULL); - BLI_ghash_free(kcd->kedgefacemap, NULL, NULL); - BLI_ghash_free(kcd->facetrimap, NULL, NULL); + BLI_ghash_free(kcd->origedgemap, NULL, NULL); + BLI_ghash_free(kcd->origvertmap, NULL, NULL); + BLI_ghash_free(kcd->kedgefacemap, NULL, NULL); + BLI_ghash_free(kcd->facetrimap, NULL, NULL); - BLI_memarena_free(kcd->arena); + BLI_memarena_free(kcd->arena); #ifdef USE_NET_ISLAND_CONNECT - BLI_memarena_free(kcd->edgenet.arena); + BLI_memarena_free(kcd->edgenet.arena); #endif - BLI_gset_free(kcd->edgenet.edge_visit, NULL); + BLI_gset_free(kcd->edgenet.edge_visit, NULL); - /* tag for redraw */ - ED_region_tag_redraw(kcd->ar); + /* tag for redraw */ + ED_region_tag_redraw(kcd->ar); - knifetool_free_bmbvh(kcd); + knifetool_free_bmbvh(kcd); - if (kcd->linehits) - MEM_freeN(kcd->linehits); + if (kcd->linehits) + MEM_freeN(kcd->linehits); - /* destroy kcd itself */ - MEM_freeN(kcd); + /* destroy kcd itself */ + MEM_freeN(kcd); } static void knifetool_exit(bContext *C, wmOperator *op) { - KnifeTool_OpData *kcd = op->customdata; - knifetool_exit_ex(C, kcd); - op->customdata = NULL; + KnifeTool_OpData *kcd = op->customdata; + knifetool_exit_ex(C, kcd); + op->customdata = NULL; } static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2]) { - knife_recalc_projmat(kcd); - copy_v2_v2(kcd->mval, mval); + knife_recalc_projmat(kcd); + copy_v2_v2(kcd->mval, mval); - if (knife_update_active(kcd)) { - ED_region_tag_redraw(kcd->ar); - } + if (knife_update_active(kcd)) { + ED_region_tag_redraw(kcd->ar); + } } static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2]) { - float mval[2] = {UNPACK2(mval_i)}; - knifetool_update_mval(kcd, mval); + float mval[2] = {UNPACK2(mval_i)}; + knifetool_update_mval(kcd, mval); } static void knifetool_init_bmbvh(KnifeTool_OpData *kcd) { - BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT); + BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT); - Scene *scene_eval = (Scene *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->scene->id); - Object *obedit_eval = (Object *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->em->ob->id); - BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval); + Scene *scene_eval = (Scene *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->scene->id); + 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->vc.depsgraph, em_eval, scene_eval, NULL); + kcd->cagecos = (const float(*)[3])BKE_editmesh_vertexCos_get( + kcd->vc.depsgraph, em_eval, scene_eval, NULL); - kcd->bmbvh = BKE_bmbvh_new_from_editmesh( - kcd->em, - BMBVH_RETURN_ORIG | - ((kcd->only_select && kcd->cut_through) ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN), - kcd->cagecos, false); + kcd->bmbvh = BKE_bmbvh_new_from_editmesh( + kcd->em, + BMBVH_RETURN_ORIG | + ((kcd->only_select && kcd->cut_through) ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN), + kcd->cagecos, + false); } static void knifetool_free_bmbvh(KnifeTool_OpData *kcd) { - if (kcd->bmbvh) { - BKE_bmbvh_free(kcd->bmbvh); - kcd->bmbvh = NULL; - } + if (kcd->bmbvh) { + BKE_bmbvh_free(kcd->bmbvh); + kcd->bmbvh = NULL; + } - if (kcd->cagecos) { - MEM_freeN((void *)kcd->cagecos); - kcd->cagecos = NULL; - } + if (kcd->cagecos) { + MEM_freeN((void *)kcd->cagecos); + kcd->cagecos = NULL; + } } /* called when modal loop selection gets set up... */ -static void knifetool_init(bContext *C, KnifeTool_OpData *kcd, - const bool only_select, const bool cut_through, const bool is_interactive) +static void knifetool_init(bContext *C, + KnifeTool_OpData *kcd, + const bool only_select, + const bool cut_through, + const bool is_interactive) { - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); - /* assign the drawing handle for drawing preview line... */ - kcd->scene = scene; - kcd->ob = obedit; - kcd->ar = CTX_wm_region(C); + /* assign the drawing handle for drawing preview line... */ + kcd->scene = scene; + kcd->ob = obedit; + kcd->ar = CTX_wm_region(C); - em_setup_viewcontext(C, &kcd->vc); + em_setup_viewcontext(C, &kcd->vc); - kcd->em = BKE_editmesh_from_object(kcd->ob); + kcd->em = BKE_editmesh_from_object(kcd->ob); - /* cut all the way through the mesh if use_occlude_geometry button not pushed */ - kcd->is_interactive = is_interactive; - kcd->cut_through = cut_through; - kcd->only_select = only_select; + /* cut all the way through the mesh if use_occlude_geometry button not pushed */ + kcd->is_interactive = is_interactive; + kcd->cut_through = cut_through; + kcd->only_select = only_select; - knifetool_init_bmbvh(kcd); + knifetool_init_bmbvh(kcd); - kcd->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), "knife"); + kcd->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), "knife"); #ifdef USE_NET_ISLAND_CONNECT - kcd->edgenet.arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), __func__); + kcd->edgenet.arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), __func__); #endif - kcd->edgenet.edge_visit = BLI_gset_ptr_new(__func__); + kcd->edgenet.edge_visit = BLI_gset_ptr_new(__func__); - kcd->vthresh = KMAXDIST - 1; - kcd->ethresh = KMAXDIST; + kcd->vthresh = KMAXDIST - 1; + kcd->ethresh = KMAXDIST; - knife_recalc_projmat(kcd); + knife_recalc_projmat(kcd); - ED_region_tag_redraw(kcd->ar); + ED_region_tag_redraw(kcd->ar); - kcd->refs = BLI_mempool_create(sizeof(Ref), 0, 2048, 0); - kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 0, 512, BLI_MEMPOOL_ALLOW_ITER); - kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 0, 512, BLI_MEMPOOL_ALLOW_ITER); + kcd->refs = BLI_mempool_create(sizeof(Ref), 0, 2048, 0); + kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 0, 512, BLI_MEMPOOL_ALLOW_ITER); + kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 0, 512, BLI_MEMPOOL_ALLOW_ITER); - kcd->origedgemap = BLI_ghash_ptr_new("knife origedgemap"); - kcd->origvertmap = BLI_ghash_ptr_new("knife origvertmap"); - kcd->kedgefacemap = BLI_ghash_ptr_new("knife kedgefacemap"); - kcd->facetrimap = BLI_ghash_ptr_new("knife facetrimap"); + kcd->origedgemap = BLI_ghash_ptr_new("knife origedgemap"); + kcd->origvertmap = BLI_ghash_ptr_new("knife origvertmap"); + kcd->kedgefacemap = BLI_ghash_ptr_new("knife kedgefacemap"); + kcd->facetrimap = BLI_ghash_ptr_new("knife facetrimap"); - /* can't usefully select resulting edges in face mode */ - kcd->select_result = (kcd->em->selectmode != SCE_SELECT_FACE); + /* can't usefully select resulting edges in face mode */ + kcd->select_result = (kcd->em->selectmode != SCE_SELECT_FACE); - knife_pos_data_clear(&kcd->curr); - knife_pos_data_clear(&kcd->prev); + knife_pos_data_clear(&kcd->curr); + knife_pos_data_clear(&kcd->prev); - if (is_interactive) { - kcd->draw_handle = ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW); + if (is_interactive) { + kcd->draw_handle = ED_region_draw_cb_activate( + kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW); - knife_init_colors(&kcd->colors); - } + knife_init_colors(&kcd->colors); + } } static void knifetool_cancel(bContext *C, wmOperator *op) { - /* this is just a wrapper around exit() */ - knifetool_exit(C, op); + /* this is just a wrapper around exit() */ + knifetool_exit(C, op); } static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - const bool only_select = RNA_boolean_get(op->ptr, "only_selected"); - const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry"); - const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input"); + const bool only_select = RNA_boolean_get(op->ptr, "only_selected"); + const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry"); + const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input"); - KnifeTool_OpData *kcd; + KnifeTool_OpData *kcd; - if (only_select) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - BKE_report(op->reports, RPT_ERROR, "Selected faces required"); - return OPERATOR_CANCELLED; - } - } + if (only_select) { + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totfacesel == 0) { + BKE_report(op->reports, RPT_ERROR, "Selected faces required"); + return OPERATOR_CANCELLED; + } + } - view3d_operator_needs_opengl(C); + view3d_operator_needs_opengl(C); - /* alloc new customdata */ - kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__); + /* alloc new customdata */ + kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__); - knifetool_init(C, kcd, only_select, cut_through, true); + knifetool_init(C, kcd, only_select, cut_through, true); - op->flag |= OP_IS_MODAL_CURSOR_REGION; + op->flag |= OP_IS_MODAL_CURSOR_REGION; - /* add a modal handler for this operator - handles loop selection */ - WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR); - WM_event_add_modal_handler(C, op); + /* add a modal handler for this operator - handles loop selection */ + WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR); + WM_event_add_modal_handler(C, op); - knifetool_update_mval_i(kcd, event->mval); + knifetool_update_mval_i(kcd, event->mval); - if (wait_for_input == false) { - /* Avoid copy-paste logic. */ - wmEvent event_modal = { - .prevval = KM_NOTHING, - .type = EVT_MODAL_MAP, - .val = KNF_MODAL_ADD_CUT, - }; - int ret = knifetool_modal(C, op, &event_modal); - BLI_assert(ret == OPERATOR_RUNNING_MODAL); - UNUSED_VARS_NDEBUG(ret); - } + if (wait_for_input == false) { + /* Avoid copy-paste logic. */ + wmEvent event_modal = { + .prevval = KM_NOTHING, + .type = EVT_MODAL_MAP, + .val = KNF_MODAL_ADD_CUT, + }; + int ret = knifetool_modal(C, op, &event_modal); + BLI_assert(ret == OPERATOR_RUNNING_MODAL); + UNUSED_VARS_NDEBUG(ret); + } - knife_update_header(C, op, kcd); + knife_update_header(C, op, kcd); - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) { - static const EnumPropertyItem modal_items[] = { - {KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, - {KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""}, - {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""}, - {KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""}, - {KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""}, - {KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""}, - {KNF_MODAL_CUT_THROUGH_TOGGLE, "CUT_THROUGH_TOGGLE", 0, "Toggle Cut Through", ""}, - {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""}, - {KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""}, - {KNF_MODAL_PANNING, "PANNING", 0, "Panning", ""}, - {0, NULL, 0, NULL, NULL}, - }; + static const EnumPropertyItem modal_items[] = { + {KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""}, + {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""}, + {KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""}, + {KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""}, + {KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""}, + {KNF_MODAL_CUT_THROUGH_TOGGLE, "CUT_THROUGH_TOGGLE", 0, "Toggle Cut Through", ""}, + {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""}, + {KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""}, + {KNF_MODAL_PANNING, "PANNING", 0, "Panning", ""}, + {0, NULL, 0, NULL, NULL}, + }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Knife Tool Modal Map"); + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Knife Tool Modal Map"); - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) - return NULL; + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) + return NULL; - keymap = WM_modalkeymap_add(keyconf, "Knife Tool Modal Map", modal_items); + keymap = WM_modalkeymap_add(keyconf, "Knife Tool Modal Map", modal_items); - WM_modalkeymap_assign(keymap, "MESH_OT_knife_tool"); + WM_modalkeymap_assign(keymap, "MESH_OT_knife_tool"); - return keymap; + return keymap; } static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) { - Object *obedit = CTX_data_edit_object(C); - KnifeTool_OpData *kcd = op->customdata; - bool do_refresh = false; - - if (!obedit || obedit->type != OB_MESH || BKE_editmesh_from_object(obedit) != kcd->em) { - knifetool_exit(C, op); - ED_workspace_status_text(C, NULL); - return OPERATOR_FINISHED; - } - - em_setup_viewcontext(C, &kcd->vc); - kcd->ar = kcd->vc.ar; - - view3d_operator_needs_opengl(C); - ED_view3d_init_mats_rv3d(obedit, kcd->vc.rv3d); /* needed to initialize clipping */ - - if (kcd->mode == MODE_PANNING) - kcd->mode = kcd->prevmode; - - /* handle modal keymap */ - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case KNF_MODAL_CANCEL: - /* finish */ - ED_region_tag_redraw(kcd->ar); - - knifetool_exit(C, op); - ED_workspace_status_text(C, NULL); - - return OPERATOR_CANCELLED; - case KNF_MODAL_CONFIRM: - /* finish */ - ED_region_tag_redraw(kcd->ar); - - knifetool_finish(op); - knifetool_exit(C, op); - ED_workspace_status_text(C, NULL); - - return OPERATOR_FINISHED; - case KNF_MODAL_MIDPOINT_ON: - kcd->snap_midpoints = true; - - knife_recalc_projmat(kcd); - knife_update_active(kcd); - knife_update_header(C, op, kcd); - ED_region_tag_redraw(kcd->ar); - do_refresh = true; - break; - case KNF_MODAL_MIDPOINT_OFF: - kcd->snap_midpoints = false; - - knife_recalc_projmat(kcd); - knife_update_active(kcd); - knife_update_header(C, op, kcd); - ED_region_tag_redraw(kcd->ar); - do_refresh = true; - break; - case KNF_MODEL_IGNORE_SNAP_ON: - ED_region_tag_redraw(kcd->ar); - kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = true; - knife_update_header(C, op, kcd); - do_refresh = true; - break; - case KNF_MODEL_IGNORE_SNAP_OFF: - ED_region_tag_redraw(kcd->ar); - kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = false; - knife_update_header(C, op, kcd); - do_refresh = true; - break; - case KNF_MODAL_ANGLE_SNAP_TOGGLE: - kcd->angle_snapping = !kcd->angle_snapping; - knife_update_header(C, op, kcd); - do_refresh = true; - break; - case KNF_MODAL_CUT_THROUGH_TOGGLE: - kcd->cut_through = !kcd->cut_through; - knife_update_header(C, op, kcd); - do_refresh = true; - break; - case KNF_MODAL_NEW_CUT: - ED_region_tag_redraw(kcd->ar); - knife_finish_cut(kcd); - kcd->mode = MODE_IDLE; - break; - case KNF_MODAL_ADD_CUT: - knife_recalc_projmat(kcd); - - /* get the value of the event which triggered this one */ - if (event->prevval != KM_RELEASE) { - if (kcd->mode == MODE_DRAGGING) { - knife_add_cut(kcd); - } - else if (kcd->mode != MODE_PANNING) { - knife_start_cut(kcd); - kcd->mode = MODE_DRAGGING; - kcd->init = kcd->curr; - } - - /* freehand drawing is incompatible with cut-through */ - if (kcd->cut_through == false) { - kcd->is_drag_hold = true; - } - } - else { - kcd->is_drag_hold = false; - - /* needed because the last face 'hit' is ignored when dragging */ - knifetool_update_mval(kcd, kcd->curr.mval); - } - - ED_region_tag_redraw(kcd->ar); - break; - case KNF_MODAL_ADD_CUT_CLOSED: - if (kcd->mode == MODE_DRAGGING) { - - /* shouldn't be possible with default key-layout, just incase... */ - if (kcd->is_drag_hold) { - kcd->is_drag_hold = false; - knifetool_update_mval(kcd, kcd->curr.mval); - } - - kcd->prev = kcd->curr; - kcd->curr = kcd->init; - - knife_project_v2(kcd, kcd->curr.cage, kcd->curr.mval); - knifetool_update_mval(kcd, kcd->curr.mval); - - knife_add_cut(kcd); - - /* KNF_MODAL_NEW_CUT */ - knife_finish_cut(kcd); - kcd->mode = MODE_IDLE; - } - break; - case KNF_MODAL_PANNING: - if (event->val != KM_RELEASE) { - if (kcd->mode != MODE_PANNING) { - kcd->prevmode = kcd->mode; - kcd->mode = MODE_PANNING; - } - } - else { - kcd->mode = kcd->prevmode; - } - - ED_region_tag_redraw(kcd->ar); - return OPERATOR_PASS_THROUGH; - } - } - else { /* non-modal-mapped events */ - switch (event->type) { - case MOUSEPAN: - case MOUSEZOOM: - case MOUSEROTATE: - case WHEELUPMOUSE: - case WHEELDOWNMOUSE: - return OPERATOR_PASS_THROUGH; - case MOUSEMOVE: /* mouse moved somewhere to select another loop */ - if (kcd->mode != MODE_PANNING) { - knifetool_update_mval_i(kcd, event->mval); - - if (kcd->is_drag_hold) { - if (kcd->totlinehit >= 2) { - knife_add_cut(kcd); - } - } - } - - break; - } - } - - if (kcd->mode == MODE_DRAGGING) { - op->flag &= ~OP_IS_MODAL_CURSOR_REGION; - } - else { - op->flag |= OP_IS_MODAL_CURSOR_REGION; - } - - if (do_refresh) { - /* we don't really need to update mval, - * but this happens to be the best way to refresh at the moment */ - knifetool_update_mval_i(kcd, event->mval); - } - - /* keep going until the user confirms */ - return OPERATOR_RUNNING_MODAL; + Object *obedit = CTX_data_edit_object(C); + KnifeTool_OpData *kcd = op->customdata; + bool do_refresh = false; + + if (!obedit || obedit->type != OB_MESH || BKE_editmesh_from_object(obedit) != kcd->em) { + knifetool_exit(C, op); + ED_workspace_status_text(C, NULL); + return OPERATOR_FINISHED; + } + + em_setup_viewcontext(C, &kcd->vc); + kcd->ar = kcd->vc.ar; + + view3d_operator_needs_opengl(C); + ED_view3d_init_mats_rv3d(obedit, kcd->vc.rv3d); /* needed to initialize clipping */ + + if (kcd->mode == MODE_PANNING) + kcd->mode = kcd->prevmode; + + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case KNF_MODAL_CANCEL: + /* finish */ + ED_region_tag_redraw(kcd->ar); + + knifetool_exit(C, op); + ED_workspace_status_text(C, NULL); + + return OPERATOR_CANCELLED; + case KNF_MODAL_CONFIRM: + /* finish */ + ED_region_tag_redraw(kcd->ar); + + knifetool_finish(op); + knifetool_exit(C, op); + ED_workspace_status_text(C, NULL); + + return OPERATOR_FINISHED; + case KNF_MODAL_MIDPOINT_ON: + kcd->snap_midpoints = true; + + knife_recalc_projmat(kcd); + knife_update_active(kcd); + knife_update_header(C, op, kcd); + ED_region_tag_redraw(kcd->ar); + do_refresh = true; + break; + case KNF_MODAL_MIDPOINT_OFF: + kcd->snap_midpoints = false; + + knife_recalc_projmat(kcd); + knife_update_active(kcd); + knife_update_header(C, op, kcd); + ED_region_tag_redraw(kcd->ar); + do_refresh = true; + break; + case KNF_MODEL_IGNORE_SNAP_ON: + ED_region_tag_redraw(kcd->ar); + kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = true; + knife_update_header(C, op, kcd); + do_refresh = true; + break; + case KNF_MODEL_IGNORE_SNAP_OFF: + ED_region_tag_redraw(kcd->ar); + kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = false; + knife_update_header(C, op, kcd); + do_refresh = true; + break; + case KNF_MODAL_ANGLE_SNAP_TOGGLE: + kcd->angle_snapping = !kcd->angle_snapping; + knife_update_header(C, op, kcd); + do_refresh = true; + break; + case KNF_MODAL_CUT_THROUGH_TOGGLE: + kcd->cut_through = !kcd->cut_through; + knife_update_header(C, op, kcd); + do_refresh = true; + break; + case KNF_MODAL_NEW_CUT: + ED_region_tag_redraw(kcd->ar); + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + break; + case KNF_MODAL_ADD_CUT: + knife_recalc_projmat(kcd); + + /* get the value of the event which triggered this one */ + if (event->prevval != KM_RELEASE) { + if (kcd->mode == MODE_DRAGGING) { + knife_add_cut(kcd); + } + else if (kcd->mode != MODE_PANNING) { + knife_start_cut(kcd); + kcd->mode = MODE_DRAGGING; + kcd->init = kcd->curr; + } + + /* freehand drawing is incompatible with cut-through */ + if (kcd->cut_through == false) { + kcd->is_drag_hold = true; + } + } + else { + kcd->is_drag_hold = false; + + /* needed because the last face 'hit' is ignored when dragging */ + knifetool_update_mval(kcd, kcd->curr.mval); + } + + ED_region_tag_redraw(kcd->ar); + break; + case KNF_MODAL_ADD_CUT_CLOSED: + if (kcd->mode == MODE_DRAGGING) { + + /* shouldn't be possible with default key-layout, just incase... */ + if (kcd->is_drag_hold) { + kcd->is_drag_hold = false; + knifetool_update_mval(kcd, kcd->curr.mval); + } + + kcd->prev = kcd->curr; + kcd->curr = kcd->init; + + knife_project_v2(kcd, kcd->curr.cage, kcd->curr.mval); + knifetool_update_mval(kcd, kcd->curr.mval); + + knife_add_cut(kcd); + + /* KNF_MODAL_NEW_CUT */ + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + } + break; + case KNF_MODAL_PANNING: + if (event->val != KM_RELEASE) { + if (kcd->mode != MODE_PANNING) { + kcd->prevmode = kcd->mode; + kcd->mode = MODE_PANNING; + } + } + else { + kcd->mode = kcd->prevmode; + } + + ED_region_tag_redraw(kcd->ar); + return OPERATOR_PASS_THROUGH; + } + } + else { /* non-modal-mapped events */ + switch (event->type) { + case MOUSEPAN: + case MOUSEZOOM: + case MOUSEROTATE: + case WHEELUPMOUSE: + case WHEELDOWNMOUSE: + return OPERATOR_PASS_THROUGH; + case MOUSEMOVE: /* mouse moved somewhere to select another loop */ + if (kcd->mode != MODE_PANNING) { + knifetool_update_mval_i(kcd, event->mval); + + if (kcd->is_drag_hold) { + if (kcd->totlinehit >= 2) { + knife_add_cut(kcd); + } + } + } + + break; + } + } + + if (kcd->mode == MODE_DRAGGING) { + op->flag &= ~OP_IS_MODAL_CURSOR_REGION; + } + else { + op->flag |= OP_IS_MODAL_CURSOR_REGION; + } + + if (do_refresh) { + /* we don't really need to update mval, + * but this happens to be the best way to refresh at the moment */ + knifetool_update_mval_i(kcd, event->mval); + } + + /* keep going until the user confirms */ + return OPERATOR_RUNNING_MODAL; } void MESH_OT_knife_tool(wmOperatorType *ot) { - /* description */ - ot->name = "Knife Topology Tool"; - ot->idname = "MESH_OT_knife_tool"; - ot->description = "Cut new topology"; + /* description */ + ot->name = "Knife Topology Tool"; + ot->idname = "MESH_OT_knife_tool"; + ot->description = "Cut new topology"; - /* callbacks */ - ot->invoke = knifetool_invoke; - ot->modal = knifetool_modal; - ot->cancel = knifetool_cancel; - ot->poll = ED_operator_editmesh_view3d; + /* callbacks */ + ot->invoke = knifetool_invoke; + ot->modal = knifetool_modal; + ot->cancel = knifetool_cancel; + ot->poll = ED_operator_editmesh_view3d; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; - /* properties */ - PropertyRNA *prop; - RNA_def_boolean(ot->srna, "use_occlude_geometry", true, "Occlude Geometry", "Only cut the front most geometry"); - RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected", "Only cut selected geometry"); + /* properties */ + PropertyRNA *prop; + RNA_def_boolean(ot->srna, + "use_occlude_geometry", + true, + "Occlude Geometry", + "Only cut the front most geometry"); + RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected", "Only cut selected geometry"); - prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } - /* -------------------------------------------------------------------- */ /* Knife tool as a utility function * that can be used for internal slicing operations */ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2]) { - LinkNode *p = polys; - int isect = 0; + LinkNode *p = polys; + int isect = 0; - while (p) { - const float (*mval_fl)[2] = p->link; - const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); - isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false); - p = p->next; - } + while (p) { + const float(*mval_fl)[2] = p->link; + const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); + isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false); + p = p->next; + } - if (isect % 2) { - return true; - } - return false; + if (isect % 2) { + return true; + } + return false; } /** @@ -3009,156 +3030,155 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2]) */ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_through) { - KnifeTool_OpData *kcd; + KnifeTool_OpData *kcd; - view3d_operator_needs_opengl(C); + view3d_operator_needs_opengl(C); - /* init */ - { - const bool only_select = false; - const bool is_interactive = false; /* can enable for testing */ + /* init */ + { + const bool only_select = false; + const bool is_interactive = false; /* can enable for testing */ - kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__); + kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__); - knifetool_init(C, kcd, only_select, cut_through, is_interactive); + knifetool_init(C, kcd, only_select, cut_through, is_interactive); - kcd->ignore_edge_snapping = true; - kcd->ignore_vert_snapping = true; + kcd->ignore_edge_snapping = true; + kcd->ignore_vert_snapping = true; - if (use_tag) { - BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false); - } - } + if (use_tag) { + BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false); + } + } - /* execute */ - { - LinkNode *p = polys; + /* execute */ + { + LinkNode *p = polys; - knife_recalc_projmat(kcd); + knife_recalc_projmat(kcd); - while (p) { - const float (*mval_fl)[2] = p->link; - const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); - int i; + while (p) { + const float(*mval_fl)[2] = p->link; + const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); + int i; - for (i = 0; i < mval_tot; i++) { - knifetool_update_mval(kcd, mval_fl[i]); - if (i == 0) { - knife_start_cut(kcd); - kcd->mode = MODE_DRAGGING; - } - else { - knife_add_cut(kcd); - } - } - knife_finish_cut(kcd); - kcd->mode = MODE_IDLE; - p = p->next; - } - } + for (i = 0; i < mval_tot; i++) { + knifetool_update_mval(kcd, mval_fl[i]); + if (i == 0) { + knife_start_cut(kcd); + kcd->mode = MODE_DRAGGING; + } + else { + knife_add_cut(kcd); + } + } + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + p = p->next; + } + } - /* finish */ - { - knifetool_finish_ex(kcd); + /* finish */ + { + knifetool_finish_ex(kcd); - /* tag faces inside! */ - if (use_tag) { - BMesh *bm = kcd->em->bm; - float projmat[4][4]; + /* tag faces inside! */ + if (use_tag) { + BMesh *bm = kcd->em->bm; + float projmat[4][4]; - BMEdge *e; - BMIter iter; + BMEdge *e; + BMIter iter; - bool keep_search; + bool keep_search; - /* freed on knifetool_finish_ex, but we need again to check if points are visible */ - if (kcd->cut_through == false) { - knifetool_init_bmbvh(kcd); - } + /* freed on knifetool_finish_ex, but we need again to check if points are visible */ + if (kcd->cut_through == false) { + knifetool_init_bmbvh(kcd); + } - ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, projmat); + ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, projmat); - /* use face-loop tag to store if we have intersected */ -#define F_ISECT_IS_UNKNOWN(f) BM_elem_flag_test(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) + /* use face-loop tag to store if we have intersected */ +#define F_ISECT_IS_UNKNOWN(f) BM_elem_flag_test(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) #define F_ISECT_SET_UNKNOWN(f) BM_elem_flag_enable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) #define F_ISECT_SET_OUTSIDE(f) BM_elem_flag_disable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) - { - BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - F_ISECT_SET_UNKNOWN(f); - BM_elem_flag_disable(f, BM_ELEM_TAG); - } - } - - /* tag all faces linked to cut edges */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - /* check are we tagged?, then we are an original face */ - if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) { - BMFace *f; - BMIter fiter; - BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - float cent[3], cent_ss[2]; - BM_face_calc_point_in_face(f, cent); - knife_project_v2(kcd, cent, cent_ss); - if (edbm_mesh_knife_point_isect(polys, cent_ss)) { - BM_elem_flag_enable(f, BM_ELEM_TAG); - } - } - } - } - - /* expand tags for faces which are not cut, but are inside the polys */ - do { - BMFace *f; - keep_search = false; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) { - /* am I connected to a tagged face via an un-tagged edge - * (ie, not across a cut) */ - BMLoop *l_first = BM_FACE_FIRST_LOOP(f); - BMLoop *l_iter = l_first; - bool found = false; - - do { - if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) { - /* now check if the adjacent faces is tagged */ - BMLoop *l_radial_iter = l_iter->radial_next; - if (l_radial_iter != l_iter) { - do { - if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) { - found = true; - } - } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter && (found == false)); - } - } - } while ((l_iter = l_iter->next) != l_first && (found == false)); - - if (found) { - float cent[3], cent_ss[2]; - BM_face_calc_point_in_face(f, cent); - knife_project_v2(kcd, cent, cent_ss); - if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) && - edbm_mesh_knife_point_isect(polys, cent_ss)) - { - BM_elem_flag_enable(f, BM_ELEM_TAG); - keep_search = true; - } - else { - /* don't loose time on this face again, set it as outside */ - F_ISECT_SET_OUTSIDE(f); - } - } - } - } - } while (keep_search); + { + BMFace *f; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + F_ISECT_SET_UNKNOWN(f); + BM_elem_flag_disable(f, BM_ELEM_TAG); + } + } + + /* tag all faces linked to cut edges */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + /* check are we tagged?, then we are an original face */ + if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) { + BMFace *f; + BMIter fiter; + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + float cent[3], cent_ss[2]; + BM_face_calc_point_in_face(f, cent); + knife_project_v2(kcd, cent, cent_ss); + if (edbm_mesh_knife_point_isect(polys, cent_ss)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + } + } + } + } + + /* expand tags for faces which are not cut, but are inside the polys */ + do { + BMFace *f; + keep_search = false; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) { + /* am I connected to a tagged face via an un-tagged edge + * (ie, not across a cut) */ + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; + bool found = false; + + do { + if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) { + /* now check if the adjacent faces is tagged */ + BMLoop *l_radial_iter = l_iter->radial_next; + if (l_radial_iter != l_iter) { + do { + if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) { + found = true; + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter && + (found == false)); + } + } + } while ((l_iter = l_iter->next) != l_first && (found == false)); + + if (found) { + float cent[3], cent_ss[2]; + BM_face_calc_point_in_face(f, cent); + knife_project_v2(kcd, cent, cent_ss); + if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) && + edbm_mesh_knife_point_isect(polys, cent_ss)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + keep_search = true; + } + else { + /* don't loose time on this face again, set it as outside */ + F_ISECT_SET_OUTSIDE(f); + } + } + } + } + } while (keep_search); #undef F_ISECT_IS_UNKNOWN #undef F_ISECT_SET_UNKNOWN #undef F_ISECT_SET_OUTSIDE + } - } - - knifetool_exit_ex(C, kcd); - kcd = NULL; - } + knifetool_exit_ex(C, kcd); + kcd = NULL; + } } diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index 13fcb99f59b..13bcb1334a9 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -50,130 +50,135 @@ #include "ED_screen.h" #include "ED_view3d.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ - -static LinkNode *knifeproject_poly_from_object(const bContext *C, Scene *scene, Object *ob, LinkNode *polys) +static LinkNode *knifeproject_poly_from_object(const bContext *C, + Scene *scene, + Object *ob, + LinkNode *polys) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - ARegion *ar = CTX_wm_region(C); - struct Mesh *me_eval; - bool me_eval_needs_free; - - if (ob->type == OB_MESH || ob->runtime.mesh_eval) { - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - me_eval = ob_eval->runtime.mesh_eval; - if (me_eval == NULL) { - Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); - me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); - } - me_eval_needs_free = false; - } - else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - me_eval = BKE_mesh_new_nomain_from_curve(ob_eval); - me_eval_needs_free = true; - } - else { - me_eval = NULL; - } - - if (me_eval) { - ListBase nurbslist = {NULL, NULL}; - float projmat[4][4]; - - BKE_mesh_to_curve_nurblist(me_eval, &nurbslist, 0); /* wire */ - BKE_mesh_to_curve_nurblist(me_eval, &nurbslist, 1); /* boundary */ - - ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat); - - if (nurbslist.first) { - Nurb *nu; - for (nu = nurbslist.first; nu; nu = nu->next) { - if (nu->bp) { - int a; - BPoint *bp; - bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0; - float (*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__); - - for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) { - ED_view3d_project_float_v2_m4(ar, bp->vec, mval[a], projmat); - } - if (is_cyclic) { - copy_v2_v2(mval[a], mval[0]); - } - - BLI_linklist_prepend(&polys, mval); - } - } - } - - BKE_nurbList_free(&nurbslist); - - if (me_eval_needs_free) { - BKE_mesh_free(me_eval); - } - } - - return polys; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ARegion *ar = CTX_wm_region(C); + struct Mesh *me_eval; + bool me_eval_needs_free; + + if (ob->type == OB_MESH || ob->runtime.mesh_eval) { + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + me_eval = ob_eval->runtime.mesh_eval; + if (me_eval == NULL) { + Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); + me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); + } + me_eval_needs_free = false; + } + else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + me_eval = BKE_mesh_new_nomain_from_curve(ob_eval); + me_eval_needs_free = true; + } + else { + me_eval = NULL; + } + + if (me_eval) { + ListBase nurbslist = {NULL, NULL}; + float projmat[4][4]; + + BKE_mesh_to_curve_nurblist(me_eval, &nurbslist, 0); /* wire */ + BKE_mesh_to_curve_nurblist(me_eval, &nurbslist, 1); /* boundary */ + + ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat); + + if (nurbslist.first) { + Nurb *nu; + for (nu = nurbslist.first; nu; nu = nu->next) { + if (nu->bp) { + int a; + BPoint *bp; + bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0; + float(*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__); + + for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) { + ED_view3d_project_float_v2_m4(ar, bp->vec, mval[a], projmat); + } + if (is_cyclic) { + copy_v2_v2(mval[a], mval[0]); + } + + BLI_linklist_prepend(&polys, mval); + } + } + } + + BKE_nurbList_free(&nurbslist); + + if (me_eval_needs_free) { + BKE_mesh_free(me_eval); + } + } + + return polys; } static int knifeproject_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const bool cut_through = RNA_boolean_get(op->ptr, "cut_through"); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const bool cut_through = RNA_boolean_get(op->ptr, "cut_through"); - LinkNode *polys = NULL; + LinkNode *polys = NULL; - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - if (ob != obedit) { - polys = knifeproject_poly_from_object(C, scene, ob, polys); - } - } - CTX_DATA_END; + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + if (ob != obedit) { + polys = knifeproject_poly_from_object(C, scene, ob, polys); + } + } + CTX_DATA_END; - if (polys) { - EDBM_mesh_knife(C, polys, true, cut_through); + if (polys) { + EDBM_mesh_knife(C, polys, true, cut_through); - /* select only tagged faces */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + /* select only tagged faces */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - /* not essential, but switch out of vertex mode since the - * selected regions wont be nicely isolated after flushing. - * note: call after de-select to avoid selection flushing */ - EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE); + /* not essential, but switch out of vertex mode since the + * selected regions wont be nicely isolated after flushing. + * note: call after de-select to avoid selection flushing */ + EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE); - BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); + BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); - BM_mesh_select_mode_flush(em->bm); + BM_mesh_select_mode_flush(em->bm); - BLI_linklist_freeN(polys); + BLI_linklist_freeN(polys); - return OPERATOR_FINISHED; - } - else { - BKE_report(op->reports, RPT_ERROR, "No other selected objects found to use for projection"); - return OPERATOR_CANCELLED; - } + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No other selected objects found to use for projection"); + return OPERATOR_CANCELLED; + } } void MESH_OT_knife_project(wmOperatorType *ot) { - /* description */ - ot->name = "Knife Project"; - ot->idname = "MESH_OT_knife_project"; - ot->description = "Use other objects outlines & boundaries to project knife cuts"; - - /* callbacks */ - ot->exec = knifeproject_exec; - ot->poll = ED_operator_editmesh_region_view3d; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_USE_EVAL_DATA; - - /* parameters */ - RNA_def_boolean(ot->srna, "cut_through", false, "Cut through", "Cut through all faces, not just visible ones"); + /* description */ + ot->name = "Knife Project"; + ot->idname = "MESH_OT_knife_project"; + ot->description = "Use other objects outlines & boundaries to project knife cuts"; + + /* callbacks */ + ot->exec = knifeproject_exec; + ot->poll = ED_operator_editmesh_region_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_USE_EVAL_DATA; + + /* parameters */ + RNA_def_boolean(ot->srna, + "cut_through", + false, + "Cut through", + "Cut through all faces, not just visible ones"); } diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index f0c2023dfcc..d0988811d15 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -61,7 +61,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ #define SUBD_SMOOTH_MAX 4.0f #define SUBD_CUTS_MAX 500 @@ -70,584 +70,609 @@ /* struct for properties used while drawing */ typedef struct RingSelOpData { - ARegion *ar; /* region that ringsel was activated in */ - void *draw_handle; /* for drawing preview loop */ + ARegion *ar; /* region that ringsel was activated in */ + void *draw_handle; /* for drawing preview loop */ - struct EditMesh_PreSelEdgeRing *presel_edgering; + struct EditMesh_PreSelEdgeRing *presel_edgering; - ViewContext vc; + ViewContext vc; - Depsgraph *depsgraph; + Depsgraph *depsgraph; - Object **objects; - uint objects_len; + Object **objects; + uint objects_len; - /* These values switch objects based on the object under the cursor. */ - uint ob_index; - Object *ob; - BMEditMesh *em; - BMEdge *eed; + /* These values switch objects based on the object under the cursor. */ + uint ob_index; + Object *ob; + BMEditMesh *em; + BMEdge *eed; - NumInput num; + NumInput num; - bool extend; - bool do_cut; + bool extend; + bool do_cut; - float cuts; /* cuts as float so smooth mouse pan works in small increments */ - float smoothness; + float cuts; /* cuts as float so smooth mouse pan works in small increments */ + float smoothness; } RingSelOpData; /* modal loop selection drawing callback */ static void ringsel_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) { - RingSelOpData *lcd = arg; - EDBM_preselect_edgering_draw(lcd->presel_edgering, lcd->ob->obmat); + RingSelOpData *lcd = arg; + EDBM_preselect_edgering_draw(lcd->presel_edgering, lcd->ob->obmat); } static void edgering_select(RingSelOpData *lcd) { - if (!lcd->eed) { - return; - } - - if (!lcd->extend) { - for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { - Object *ob_iter = lcd->objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob_iter); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); - WM_main_add_notifier(NC_GEOM | ND_SELECT, ob_iter->data); - } - } - - BMEditMesh *em = lcd->em; - BMEdge *eed_start = lcd->eed; - BMWalker walker; - BMEdge *eed; - BMW_init(&walker, em->bm, BMW_EDGERING, - BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - for (eed = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) { - BM_edge_select_set(em->bm, eed, true); - } - BMW_end(&walker); + if (!lcd->eed) { + return; + } + + if (!lcd->extend) { + for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { + Object *ob_iter = lcd->objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob_iter); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + WM_main_add_notifier(NC_GEOM | ND_SELECT, ob_iter->data); + } + } + + BMEditMesh *em = lcd->em; + BMEdge *eed_start = lcd->eed; + BMWalker walker; + BMEdge *eed; + BMW_init(&walker, + em->bm, + BMW_EDGERING, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + for (eed = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) { + BM_edge_select_set(em->bm, eed, true); + } + BMW_end(&walker); } static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines) { - if (lcd->eed) { - const float (*coords)[3] = NULL; - { - Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(lcd->depsgraph, lcd->ob->data); - if (me_eval->runtime.edit_data) { - coords = me_eval->runtime.edit_data->vertexCos; - } - } - EDBM_preselect_edgering_update_from_edge(lcd->presel_edgering, lcd->em->bm, lcd->eed, previewlines, coords); - } - else { - EDBM_preselect_edgering_clear(lcd->presel_edgering); - } + if (lcd->eed) { + const float(*coords)[3] = NULL; + { + Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(lcd->depsgraph, lcd->ob->data); + if (me_eval->runtime.edit_data) { + coords = me_eval->runtime.edit_data->vertexCos; + } + } + EDBM_preselect_edgering_update_from_edge( + lcd->presel_edgering, lcd->em->bm, lcd->eed, previewlines, coords); + } + else { + EDBM_preselect_edgering_clear(lcd->presel_edgering); + } } static void ringsel_finish(bContext *C, wmOperator *op) { - RingSelOpData *lcd = op->customdata; - const int cuts = RNA_int_get(op->ptr, "number_cuts"); - const float smoothness = RNA_float_get(op->ptr, "smoothness"); - const int smooth_falloff = RNA_enum_get(op->ptr, "falloff"); + RingSelOpData *lcd = op->customdata; + const int cuts = RNA_int_get(op->ptr, "number_cuts"); + const float smoothness = RNA_float_get(op->ptr, "smoothness"); + const int smooth_falloff = RNA_enum_get(op->ptr, "falloff"); #ifdef BMW_EDGERING_NGON - const bool use_only_quads = false; + const bool use_only_quads = false; #else - const bool use_only_quads = false; + const bool use_only_quads = false; #endif - if (lcd->eed) { - BMEditMesh *em = lcd->em; - BMVert *v_eed_orig[2] = {lcd->eed->v1, lcd->eed->v2}; - - edgering_select(lcd); - - if (lcd->do_cut) { - const bool is_macro = (op->opm != NULL); - /* a single edge (rare, but better support) */ - const bool is_single = (BM_edge_is_wire(lcd->eed)); - const int seltype = is_single ? SUBDIV_SELECT_INNER : SUBDIV_SELECT_LOOPCUT; - - /* Enable gridfill, so that intersecting loopcut works as one would expect. - * Note though that it will break edgeslide in this specific case. - * See [#31939]. */ - BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT, - smoothness, smooth_falloff, true, - 0.0f, 0.0f, - cuts, seltype, SUBD_CORNER_PATH, 0, true, - use_only_quads, 0); - - /* when used in a macro the tessfaces will be recalculated anyway, - * this is needed here because modifiers depend on updated tessellation, see T45920 */ - EDBM_update_generic(em, true, true); - - if (is_single) { - /* de-select endpoints */ - BM_vert_select_set(em->bm, v_eed_orig[0], false); - BM_vert_select_set(em->bm, v_eed_orig[1], false); - - EDBM_selectmode_flush_ex(lcd->em, SCE_SELECT_VERTEX); - } - /* we cant slide multiple edges in vertex select mode */ - else if (is_macro && (cuts > 1) && (em->selectmode & SCE_SELECT_VERTEX)) { - EDBM_selectmode_disable(lcd->vc.scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE); - } - /* force edge slide to edge select mode in in face select mode */ - else if (EDBM_selectmode_disable(lcd->vc.scene, em, SCE_SELECT_FACE, SCE_SELECT_EDGE)) { - /* pass, the change will flush selection */ - } - else { - /* else flush explicitly */ - EDBM_selectmode_flush(lcd->em); - } - } - else { - /* XXX Is this piece of code ever used now? Simple loop select is now - * in editmesh_select.c (around line 1000)... */ - /* sets as active, useful for other tools */ - if (em->selectmode & SCE_SELECT_VERTEX) { - /* low priority TODO, get vertrex close to mouse */ - BM_select_history_store(em->bm, lcd->eed->v1); - } - if (em->selectmode & SCE_SELECT_EDGE) { - BM_select_history_store(em->bm, lcd->eed); - } - - EDBM_selectmode_flush(lcd->em); - DEG_id_tag_update(lcd->ob->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, lcd->ob->data); - } - } + if (lcd->eed) { + BMEditMesh *em = lcd->em; + BMVert *v_eed_orig[2] = {lcd->eed->v1, lcd->eed->v2}; + + edgering_select(lcd); + + if (lcd->do_cut) { + const bool is_macro = (op->opm != NULL); + /* a single edge (rare, but better support) */ + const bool is_single = (BM_edge_is_wire(lcd->eed)); + const int seltype = is_single ? SUBDIV_SELECT_INNER : SUBDIV_SELECT_LOOPCUT; + + /* Enable gridfill, so that intersecting loopcut works as one would expect. + * Note though that it will break edgeslide in this specific case. + * See [#31939]. */ + BM_mesh_esubdivide(em->bm, + BM_ELEM_SELECT, + smoothness, + smooth_falloff, + true, + 0.0f, + 0.0f, + cuts, + seltype, + SUBD_CORNER_PATH, + 0, + true, + use_only_quads, + 0); + + /* when used in a macro the tessfaces will be recalculated anyway, + * this is needed here because modifiers depend on updated tessellation, see T45920 */ + EDBM_update_generic(em, true, true); + + if (is_single) { + /* de-select endpoints */ + BM_vert_select_set(em->bm, v_eed_orig[0], false); + BM_vert_select_set(em->bm, v_eed_orig[1], false); + + EDBM_selectmode_flush_ex(lcd->em, SCE_SELECT_VERTEX); + } + /* we cant slide multiple edges in vertex select mode */ + else if (is_macro && (cuts > 1) && (em->selectmode & SCE_SELECT_VERTEX)) { + EDBM_selectmode_disable(lcd->vc.scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE); + } + /* force edge slide to edge select mode in in face select mode */ + else if (EDBM_selectmode_disable(lcd->vc.scene, em, SCE_SELECT_FACE, SCE_SELECT_EDGE)) { + /* pass, the change will flush selection */ + } + else { + /* else flush explicitly */ + EDBM_selectmode_flush(lcd->em); + } + } + else { + /* XXX Is this piece of code ever used now? Simple loop select is now + * in editmesh_select.c (around line 1000)... */ + /* sets as active, useful for other tools */ + if (em->selectmode & SCE_SELECT_VERTEX) { + /* low priority TODO, get vertrex close to mouse */ + BM_select_history_store(em->bm, lcd->eed->v1); + } + if (em->selectmode & SCE_SELECT_EDGE) { + BM_select_history_store(em->bm, lcd->eed); + } + + EDBM_selectmode_flush(lcd->em); + DEG_id_tag_update(lcd->ob->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, lcd->ob->data); + } + } } /* called when modal loop selection is done... */ static void ringsel_exit(bContext *UNUSED(C), wmOperator *op) { - RingSelOpData *lcd = op->customdata; + RingSelOpData *lcd = op->customdata; - /* deactivate the extra drawing stuff in 3D-View */ - ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle); + /* deactivate the extra drawing stuff in 3D-View */ + ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle); - EDBM_preselect_edgering_destroy(lcd->presel_edgering); + EDBM_preselect_edgering_destroy(lcd->presel_edgering); - MEM_freeN(lcd->objects); + MEM_freeN(lcd->objects); - ED_region_tag_redraw(lcd->ar); + ED_region_tag_redraw(lcd->ar); - /* free the custom data */ - MEM_freeN(lcd); - op->customdata = NULL; + /* free the custom data */ + MEM_freeN(lcd); + op->customdata = NULL; } - /* called when modal loop selection gets set up... */ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut) { - RingSelOpData *lcd; - Scene *scene = CTX_data_scene(C); - - /* alloc new customdata */ - lcd = op->customdata = MEM_callocN(sizeof(RingSelOpData), "ringsel Modal Op Data"); - - em_setup_viewcontext(C, &lcd->vc); - - lcd->depsgraph = CTX_data_depsgraph(C); - - /* assign the drawing handle for drawing preview line... */ - lcd->ar = CTX_wm_region(C); - lcd->draw_handle = ED_region_draw_cb_activate(lcd->ar->type, ringsel_draw, lcd, REGION_DRAW_POST_VIEW); - lcd->presel_edgering = EDBM_preselect_edgering_create(); - /* Initialize once the cursor is over a mesh. */ - lcd->ob = NULL; - lcd->em = NULL; - lcd->extend = do_cut ? false : RNA_boolean_get(op->ptr, "extend"); - lcd->do_cut = do_cut; - lcd->cuts = RNA_int_get(op->ptr, "number_cuts"); - lcd->smoothness = RNA_float_get(op->ptr, "smoothness"); - - initNumInput(&lcd->num); - lcd->num.idx_max = 1; - lcd->num.val_flag[0] |= NUM_NO_NEGATIVE | NUM_NO_FRACTION; - /* No specific flags for smoothness. */ - lcd->num.unit_sys = scene->unit.system; - lcd->num.unit_type[0] = B_UNIT_NONE; - lcd->num.unit_type[1] = B_UNIT_NONE; - - ED_region_tag_redraw(lcd->ar); - - return 1; + RingSelOpData *lcd; + Scene *scene = CTX_data_scene(C); + + /* alloc new customdata */ + lcd = op->customdata = MEM_callocN(sizeof(RingSelOpData), "ringsel Modal Op Data"); + + em_setup_viewcontext(C, &lcd->vc); + + lcd->depsgraph = CTX_data_depsgraph(C); + + /* assign the drawing handle for drawing preview line... */ + lcd->ar = CTX_wm_region(C); + lcd->draw_handle = ED_region_draw_cb_activate( + lcd->ar->type, ringsel_draw, lcd, REGION_DRAW_POST_VIEW); + lcd->presel_edgering = EDBM_preselect_edgering_create(); + /* Initialize once the cursor is over a mesh. */ + lcd->ob = NULL; + lcd->em = NULL; + lcd->extend = do_cut ? false : RNA_boolean_get(op->ptr, "extend"); + lcd->do_cut = do_cut; + lcd->cuts = RNA_int_get(op->ptr, "number_cuts"); + lcd->smoothness = RNA_float_get(op->ptr, "smoothness"); + + initNumInput(&lcd->num); + lcd->num.idx_max = 1; + lcd->num.val_flag[0] |= NUM_NO_NEGATIVE | NUM_NO_FRACTION; + /* No specific flags for smoothness. */ + lcd->num.unit_sys = scene->unit.system; + lcd->num.unit_type[0] = B_UNIT_NONE; + lcd->num.unit_type[1] = B_UNIT_NONE; + + ED_region_tag_redraw(lcd->ar); + + return 1; } static void ringcut_cancel(bContext *C, wmOperator *op) { - /* this is just a wrapper around exit() */ - ringsel_exit(C, op); + /* this is just a wrapper around exit() */ + ringsel_exit(C, op); } -static void loopcut_update_edge(RingSelOpData *lcd, uint ob_index, BMEdge *e, const int previewlines) +static void loopcut_update_edge(RingSelOpData *lcd, + uint ob_index, + BMEdge *e, + const int previewlines) { - if (e != lcd->eed) { - lcd->eed = e; - lcd->ob = lcd->vc.obedit; - lcd->ob_index = ob_index; - lcd->em = lcd->vc.em; - ringsel_find_edge(lcd, previewlines); - } - else if (e == NULL) { - lcd->ob = NULL; - lcd->em = NULL; - lcd->ob_index = UINT_MAX; - } + if (e != lcd->eed) { + lcd->eed = e; + lcd->ob = lcd->vc.obedit; + lcd->ob_index = ob_index; + lcd->em = lcd->vc.em; + ringsel_find_edge(lcd, previewlines); + } + else if (e == NULL) { + lcd->ob = NULL; + lcd->em = NULL; + lcd->ob_index = UINT_MAX; + } } static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines) { - struct { - Object *ob; - BMEdge *eed; - float dist; - int ob_index; - } best = { - .dist = ED_view3d_select_dist_px(), - }; - - for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { - Object *ob_iter = lcd->objects[ob_index]; - ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); - BMEdge *eed_test = EDBM_edge_find_nearest_ex(&lcd->vc, &best.dist, NULL, false, false, NULL); - if (eed_test) { - best.ob = ob_iter; - best.eed = eed_test; - best.ob_index = ob_index; - } - } - - if (best.eed) { - ED_view3d_viewcontext_init_object(&lcd->vc, best.ob); - } - - loopcut_update_edge(lcd, best.ob_index, best.eed, previewlines); + struct { + Object *ob; + BMEdge *eed; + float dist; + int ob_index; + } best = { + .dist = ED_view3d_select_dist_px(), + }; + + for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { + Object *ob_iter = lcd->objects[ob_index]; + ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); + BMEdge *eed_test = EDBM_edge_find_nearest_ex(&lcd->vc, &best.dist, NULL, false, false, NULL); + if (eed_test) { + best.ob = ob_iter; + best.eed = eed_test; + best.ob_index = ob_index; + } + } + + if (best.eed) { + ED_view3d_viewcontext_init_object(&lcd->vc, best.ob); + } + + loopcut_update_edge(lcd, best.ob_index, best.eed, previewlines); } /* called by both init() and exec() */ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) { - const bool is_interactive = (event != NULL); - - /* Use for redo - intentionally wrap int to uint. */ - const struct { - uint ob_index; - uint e_index; - } exec_data = { - .ob_index = (uint)RNA_int_get(op->ptr, "object_index"), - .e_index = (uint)RNA_int_get(op->ptr, "edge_index"), - }; - - ViewLayer *view_layer = CTX_data_view_layer(C); - - uint objects_len; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode(view_layer, CTX_wm_view3d(C), &objects_len); - - if (is_interactive) { - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; - if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) { - BKE_report(op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display"); - break; - } - } - } - - view3d_operator_needs_opengl(C); - - /* for re-execution, check edge index is in range before we setup ringsel */ - bool ok = true; - if (is_interactive == false) { - if (exec_data.ob_index >= objects_len) { - return OPERATOR_CANCELLED; - ok = false; - } - else { - Object *ob_iter = objects[exec_data.ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob_iter); - if (exec_data.e_index >= em->bm->totedge) { - ok = false; - } - } - } - - if (!ok || !ringsel_init(C, op, true)) { - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - - /* add a modal handler for this operator - handles loop selection */ - if (is_interactive) { - op->flag |= OP_IS_MODAL_CURSOR_REGION; - WM_event_add_modal_handler(C, op); - } - - RingSelOpData *lcd = op->customdata; - - lcd->objects = objects; - lcd->objects_len = objects_len; - - if (is_interactive) { - copy_v2_v2_int(lcd->vc.mval, event->mval); - loopcut_mouse_move(lcd, is_interactive ? 1 : 0); - } - else { - - Object *ob_iter = objects[exec_data.ob_index]; - ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); - - BMEdge *e; - BM_mesh_elem_table_ensure(lcd->vc.em->bm, BM_EDGE); - e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index); - loopcut_update_edge(lcd, exec_data.ob_index, e, 0); - } + const bool is_interactive = (event != NULL); + + /* Use for redo - intentionally wrap int to uint. */ + const struct { + uint ob_index; + uint e_index; + } exec_data = { + .ob_index = (uint)RNA_int_get(op->ptr, "object_index"), + .e_index = (uint)RNA_int_get(op->ptr, "edge_index"), + }; + + ViewLayer *view_layer = CTX_data_view_layer(C); + + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( + view_layer, CTX_wm_view3d(C), &objects_len); + + if (is_interactive) { + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) { + BKE_report( + op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display"); + break; + } + } + } + + view3d_operator_needs_opengl(C); + + /* for re-execution, check edge index is in range before we setup ringsel */ + bool ok = true; + if (is_interactive == false) { + if (exec_data.ob_index >= objects_len) { + return OPERATOR_CANCELLED; + ok = false; + } + else { + Object *ob_iter = objects[exec_data.ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob_iter); + if (exec_data.e_index >= em->bm->totedge) { + ok = false; + } + } + } + + if (!ok || !ringsel_init(C, op, true)) { + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + + /* add a modal handler for this operator - handles loop selection */ + if (is_interactive) { + op->flag |= OP_IS_MODAL_CURSOR_REGION; + WM_event_add_modal_handler(C, op); + } + + RingSelOpData *lcd = op->customdata; + + lcd->objects = objects; + lcd->objects_len = objects_len; + + if (is_interactive) { + copy_v2_v2_int(lcd->vc.mval, event->mval); + loopcut_mouse_move(lcd, is_interactive ? 1 : 0); + } + else { + + Object *ob_iter = objects[exec_data.ob_index]; + ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); + + BMEdge *e; + BM_mesh_elem_table_ensure(lcd->vc.em->bm, BM_EDGE); + e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index); + loopcut_update_edge(lcd, exec_data.ob_index, e, 0); + } #ifdef USE_LOOPSLIDE_HACK - /* for use in macro so we can restore, HACK */ - { - Scene *scene = CTX_data_scene(C); - ToolSettings *settings = scene->toolsettings; - const bool mesh_select_mode[3] = { - (settings->selectmode & SCE_SELECT_VERTEX) != 0, - (settings->selectmode & SCE_SELECT_EDGE) != 0, - (settings->selectmode & SCE_SELECT_FACE) != 0, - }; - - RNA_boolean_set_array(op->ptr, "mesh_select_mode_init", mesh_select_mode); - } + /* for use in macro so we can restore, HACK */ + { + Scene *scene = CTX_data_scene(C); + ToolSettings *settings = scene->toolsettings; + const bool mesh_select_mode[3] = { + (settings->selectmode & SCE_SELECT_VERTEX) != 0, + (settings->selectmode & SCE_SELECT_EDGE) != 0, + (settings->selectmode & SCE_SELECT_FACE) != 0, + }; + + RNA_boolean_set_array(op->ptr, "mesh_select_mode_init", mesh_select_mode); + } #endif - if (is_interactive) { - ED_workspace_status_text(C, IFACE_("Select a ring to be cut, use mouse-wheel or page-up/down for number of cuts, " - "hold Alt for smooth")); - return OPERATOR_RUNNING_MODAL; - } - else { - ringsel_finish(C, op); - ringsel_exit(C, op); - return OPERATOR_FINISHED; - } + if (is_interactive) { + ED_workspace_status_text( + C, + IFACE_("Select a ring to be cut, use mouse-wheel or page-up/down for number of cuts, " + "hold Alt for smooth")); + return OPERATOR_RUNNING_MODAL; + } + else { + ringsel_finish(C, op); + ringsel_exit(C, op); + return OPERATOR_FINISHED; + } } static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - /* When accessed as a tool, get the active edge from the preselection gizmo. */ - { - ARegion *ar = CTX_wm_region(C); - wmGizmoMap *gzmap = ar->gizmo_map; - wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_mesh_preselect_edgering") : NULL; - if ((gzgroup != NULL) && gzgroup->gizmos.first) { - wmGizmo *gz = gzgroup->gizmos.first; - const int object_index = RNA_int_get(gz->ptr, "object_index"); - const int edge_index = RNA_int_get(gz->ptr, "edge_index"); - - if (object_index != -1 && edge_index != -1) { - RNA_int_set(op->ptr, "object_index", object_index); - RNA_int_set(op->ptr, "edge_index", edge_index); - return loopcut_init(C, op, NULL); - } - return OPERATOR_CANCELLED; - } - } - - return loopcut_init(C, op, event); + /* When accessed as a tool, get the active edge from the preselection gizmo. */ + { + ARegion *ar = CTX_wm_region(C); + wmGizmoMap *gzmap = ar->gizmo_map; + wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, + "VIEW3D_GGT_mesh_preselect_edgering") : + NULL; + if ((gzgroup != NULL) && gzgroup->gizmos.first) { + wmGizmo *gz = gzgroup->gizmos.first; + const int object_index = RNA_int_get(gz->ptr, "object_index"); + const int edge_index = RNA_int_get(gz->ptr, "edge_index"); + + if (object_index != -1 && edge_index != -1) { + RNA_int_set(op->ptr, "object_index", object_index); + RNA_int_set(op->ptr, "edge_index", edge_index); + return loopcut_init(C, op, NULL); + } + return OPERATOR_CANCELLED; + } + } + + return loopcut_init(C, op, event); } static int loopcut_exec(bContext *C, wmOperator *op) { - return loopcut_init(C, op, NULL); + return loopcut_init(C, op, NULL); } static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op) { - /* finish */ - ED_region_tag_redraw(lcd->ar); - ED_workspace_status_text(C, NULL); - - if (lcd->eed) { - /* set for redo */ - BM_mesh_elem_index_ensure(lcd->em->bm, BM_EDGE); - RNA_int_set(op->ptr, "object_index", lcd->ob_index); - RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed)); - - /* execute */ - ringsel_finish(C, op); - ringsel_exit(C, op); - } - else { - ringcut_cancel(C, op); - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + /* finish */ + ED_region_tag_redraw(lcd->ar); + ED_workspace_status_text(C, NULL); + + if (lcd->eed) { + /* set for redo */ + BM_mesh_elem_index_ensure(lcd->em->bm, BM_EDGE); + RNA_int_set(op->ptr, "object_index", lcd->ob_index); + RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed)); + + /* execute */ + ringsel_finish(C, op); + ringsel_exit(C, op); + } + else { + ringcut_cancel(C, op); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) { - RingSelOpData *lcd = op->customdata; - float cuts = lcd->cuts; - float smoothness = lcd->smoothness; - bool show_cuts = false; - const bool has_numinput = hasNumInput(&lcd->num); - - em_setup_viewcontext(C, &lcd->vc); - lcd->ar = lcd->vc.ar; - - view3d_operator_needs_opengl(C); - - /* using the keyboard to input the number of cuts */ - /* Modal numinput active, try to handle numeric inputs first... */ - if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) { - float values[2] = {cuts, smoothness}; - applyNumInput(&lcd->num, values); - cuts = values[0]; - smoothness = values[1]; - } - else { - bool handled = false; - switch (event->type) { - case RETKEY: - case PADENTER: - case LEFTMOUSE: /* confirm */ // XXX hardcoded - if (event->val == KM_PRESS) - return loopcut_finish(lcd, C, op); - - ED_region_tag_redraw(lcd->ar); - handled = true; - break; - case RIGHTMOUSE: /* abort */ // XXX hardcoded - ED_region_tag_redraw(lcd->ar); - ringsel_exit(C, op); - ED_workspace_status_text(C, NULL); - - return OPERATOR_CANCELLED; - case ESCKEY: - if (event->val == KM_RELEASE) { - /* cancel */ - ED_region_tag_redraw(lcd->ar); - ED_workspace_status_text(C, NULL); - - ringcut_cancel(C, op); - return OPERATOR_CANCELLED; - } - - ED_region_tag_redraw(lcd->ar); - handled = true; - break; - case MOUSEPAN: - if (event->alt == 0) { - cuts += 0.02f * (event->y - event->prevy); - if (cuts < 1 && lcd->cuts >= 1) - cuts = 1; - } - else { - smoothness += 0.002f * (event->y - event->prevy); - } - handled = true; - break; - case PADPLUSKEY: - case PAGEUPKEY: - case WHEELUPMOUSE: /* change number of cuts */ - if (event->val == KM_RELEASE) - break; - if (event->alt == 0) { - cuts += 1; - } - else { - smoothness += 0.05f; - } - handled = true; - break; - case PADMINUS: - case PAGEDOWNKEY: - case WHEELDOWNMOUSE: /* change number of cuts */ - if (event->val == KM_RELEASE) - break; - if (event->alt == 0) { - cuts = max_ff(cuts - 1, 1); - } - else { - smoothness -= 0.05f; - } - handled = true; - break; - case MOUSEMOVE: /* mouse moved somewhere to select another loop */ - - /* This is normally disabled for all modal operators. - * This is an exception since mouse movement doesn't relate to numeric input. - * - * If numeric input changes we'll need to add this back see: D2973 */ + RingSelOpData *lcd = op->customdata; + float cuts = lcd->cuts; + float smoothness = lcd->smoothness; + bool show_cuts = false; + const bool has_numinput = hasNumInput(&lcd->num); + + em_setup_viewcontext(C, &lcd->vc); + lcd->ar = lcd->vc.ar; + + view3d_operator_needs_opengl(C); + + /* using the keyboard to input the number of cuts */ + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) { + float values[2] = {cuts, smoothness}; + applyNumInput(&lcd->num, values); + cuts = values[0]; + smoothness = values[1]; + } + else { + bool handled = false; + switch (event->type) { + case RETKEY: + case PADENTER: + case LEFTMOUSE: /* confirm */ // XXX hardcoded + if (event->val == KM_PRESS) + return loopcut_finish(lcd, C, op); + + ED_region_tag_redraw(lcd->ar); + handled = true; + break; + case RIGHTMOUSE: /* abort */ // XXX hardcoded + ED_region_tag_redraw(lcd->ar); + ringsel_exit(C, op); + ED_workspace_status_text(C, NULL); + + return OPERATOR_CANCELLED; + case ESCKEY: + if (event->val == KM_RELEASE) { + /* cancel */ + ED_region_tag_redraw(lcd->ar); + ED_workspace_status_text(C, NULL); + + ringcut_cancel(C, op); + return OPERATOR_CANCELLED; + } + + ED_region_tag_redraw(lcd->ar); + handled = true; + break; + case MOUSEPAN: + if (event->alt == 0) { + cuts += 0.02f * (event->y - event->prevy); + if (cuts < 1 && lcd->cuts >= 1) + cuts = 1; + } + else { + smoothness += 0.002f * (event->y - event->prevy); + } + handled = true; + break; + case PADPLUSKEY: + case PAGEUPKEY: + case WHEELUPMOUSE: /* change number of cuts */ + if (event->val == KM_RELEASE) + break; + if (event->alt == 0) { + cuts += 1; + } + else { + smoothness += 0.05f; + } + handled = true; + break; + case PADMINUS: + case PAGEDOWNKEY: + case WHEELDOWNMOUSE: /* change number of cuts */ + if (event->val == KM_RELEASE) + break; + if (event->alt == 0) { + cuts = max_ff(cuts - 1, 1); + } + else { + smoothness -= 0.05f; + } + handled = true; + break; + case MOUSEMOVE: /* mouse moved somewhere to select another loop */ + + /* This is normally disabled for all modal operators. + * This is an exception since mouse movement doesn't relate to numeric input. + * + * If numeric input changes we'll need to add this back see: D2973 */ #if 0 - if (!has_numinput) + if (!has_numinput) #endif - { - lcd->vc.mval[0] = event->mval[0]; - lcd->vc.mval[1] = event->mval[1]; - loopcut_mouse_move(lcd, (int)lcd->cuts); - - ED_region_tag_redraw(lcd->ar); - handled = true; - } - break; - } - - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) { - float values[2] = {cuts, smoothness}; - applyNumInput(&lcd->num, values); - cuts = values[0]; - smoothness = values[1]; - } - } - - if (cuts != lcd->cuts) { - /* allow zero so you can backspace and type in a value - * otherwise 1 as minimum would make more sense */ - lcd->cuts = clamp_i(cuts, 0, SUBD_CUTS_MAX); - RNA_int_set(op->ptr, "number_cuts", (int)lcd->cuts); - ringsel_find_edge(lcd, (int)lcd->cuts); - show_cuts = true; - ED_region_tag_redraw(lcd->ar); - } - - if (smoothness != lcd->smoothness) { - lcd->smoothness = clamp_f(smoothness, -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); - RNA_float_set(op->ptr, "smoothness", lcd->smoothness); - show_cuts = true; - ED_region_tag_redraw(lcd->ar); - } - - if (show_cuts) { - Scene *sce = CTX_data_scene(C); - char buf[UI_MAX_DRAW_STR]; - char str_rep[NUM_STR_REP_LEN * 2]; - if (hasNumInput(&lcd->num)) { - outputNumInput(&lcd->num, str_rep, &sce->unit); - } - else { - BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", (int)lcd->cuts); - BLI_snprintf(str_rep + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%.2f", smoothness); - } - BLI_snprintf(buf, sizeof(buf), IFACE_("Number of Cuts: %s, Smooth: %s (Alt)"), - str_rep, str_rep + NUM_STR_REP_LEN); - ED_workspace_status_text(C, buf); - } - - /* keep going until the user confirms */ - return OPERATOR_RUNNING_MODAL; + { + lcd->vc.mval[0] = event->mval[0]; + lcd->vc.mval[1] = event->mval[1]; + loopcut_mouse_move(lcd, (int)lcd->cuts); + + ED_region_tag_redraw(lcd->ar); + handled = true; + } break; + } + + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) { + float values[2] = {cuts, smoothness}; + applyNumInput(&lcd->num, values); + cuts = values[0]; + smoothness = values[1]; + } + } + + if (cuts != lcd->cuts) { + /* allow zero so you can backspace and type in a value + * otherwise 1 as minimum would make more sense */ + lcd->cuts = clamp_i(cuts, 0, SUBD_CUTS_MAX); + RNA_int_set(op->ptr, "number_cuts", (int)lcd->cuts); + ringsel_find_edge(lcd, (int)lcd->cuts); + show_cuts = true; + ED_region_tag_redraw(lcd->ar); + } + + if (smoothness != lcd->smoothness) { + lcd->smoothness = clamp_f(smoothness, -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); + RNA_float_set(op->ptr, "smoothness", lcd->smoothness); + show_cuts = true; + ED_region_tag_redraw(lcd->ar); + } + + if (show_cuts) { + Scene *sce = CTX_data_scene(C); + char buf[UI_MAX_DRAW_STR]; + char str_rep[NUM_STR_REP_LEN * 2]; + if (hasNumInput(&lcd->num)) { + outputNumInput(&lcd->num, str_rep, &sce->unit); + } + else { + BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", (int)lcd->cuts); + BLI_snprintf(str_rep + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%.2f", smoothness); + } + BLI_snprintf(buf, + sizeof(buf), + IFACE_("Number of Cuts: %s, Smooth: %s (Alt)"), + str_rep, + str_rep + NUM_STR_REP_LEN); + ED_workspace_status_text(C, buf); + } + + /* keep going until the user confirms */ + return OPERATOR_RUNNING_MODAL; } /* for bmesh this tool is in bmesh_select.c */ @@ -655,68 +680,75 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) void MESH_OT_edgering_select(wmOperatorType *ot) { - /* description */ - ot->name = "Edge Ring Select"; - ot->idname = "MESH_OT_edgering_select"; - ot->description = "Select an edge ring"; + /* description */ + ot->name = "Edge Ring Select"; + ot->idname = "MESH_OT_edgering_select"; + ot->description = "Select an edge ring"; - /* callbacks */ - ot->invoke = ringsel_invoke; - ot->poll = ED_operator_editmesh_region_view3d; + /* callbacks */ + ot->invoke = ringsel_invoke; + ot->poll = ED_operator_editmesh_region_view3d; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); } #endif void MESH_OT_loopcut(wmOperatorType *ot) { - PropertyRNA *prop; - - /* description */ - ot->name = "Loop Cut"; - ot->idname = "MESH_OT_loopcut"; - ot->description = "Add a new loop between existing loops"; - - /* callbacks */ - ot->invoke = ringcut_invoke; - ot->exec = loopcut_exec; - ot->modal = loopcut_modal; - ot->cancel = ringcut_cancel; - ot->poll = ED_operator_editmesh_region_view3d; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; - - /* properties */ - prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000000, "Number of Cuts", "", 1, 100); - /* avoid re-using last var because it can cause - * _very_ high poly meshes and annoy users (or worse crash) */ - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - prop = RNA_def_float(ot->srna, "smoothness", 0.0f, -1e3f, 1e3f, - "Smoothness", "Smoothness factor", -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - WM_operatortype_props_advanced_begin(ot); - - prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items); - RNA_def_property_enum_default(prop, PROP_INVSQUARE); - RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather"); - RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */ - - /* For redo only. */ - prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + /* description */ + ot->name = "Loop Cut"; + ot->idname = "MESH_OT_loopcut"; + ot->description = "Add a new loop between existing loops"; + + /* callbacks */ + ot->invoke = ringcut_invoke; + ot->exec = loopcut_exec; + ot->modal = loopcut_modal; + ot->cancel = ringcut_cancel; + ot->poll = ED_operator_editmesh_region_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* properties */ + prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000000, "Number of Cuts", "", 1, 100); + /* avoid re-using last var because it can cause + * _very_ high poly meshes and annoy users (or worse crash) */ + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_float(ot->srna, + "smoothness", + 0.0f, + -1e3f, + 1e3f, + "Smoothness", + "Smoothness factor", + -SUBD_SMOOTH_MAX, + SUBD_SMOOTH_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + WM_operatortype_props_advanced_begin(ot); + + prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items); + RNA_def_property_enum_default(prop, PROP_INVSQUARE); + RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */ + + /* For redo only. */ + prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); #ifdef USE_LOOPSLIDE_HACK - prop = RNA_def_boolean_array(ot->srna, "mesh_select_mode_init", 3, NULL, "", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_boolean_array(ot->srna, "mesh_select_mode_init", 3, NULL, "", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); #endif } diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index d16cd639c0d..c6b1ab9f1f2 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -57,50 +57,56 @@ #include "DEG_depsgraph.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /* -------------------------------------------------------------------- */ /** \name Path Select Struct & Properties * \{ */ struct PathSelectParams { - /** ensure the active element is the last selected item (handy for picking) */ - bool track_active; - bool use_topology_distance; - bool use_face_step; - bool use_fill; - char edge_mode; - struct CheckerIntervalParams interval_params; + /** ensure the active element is the last selected item (handy for picking) */ + bool track_active; + bool use_topology_distance; + bool use_face_step; + bool use_fill; + char edge_mode; + struct CheckerIntervalParams interval_params; }; static void path_select_properties(wmOperatorType *ot) { - RNA_def_boolean( - ot->srna, "use_face_step", false, "Face Stepping", - "Traverse connected faces (includes diagonals and edge-rings)"); - RNA_def_boolean( - ot->srna, "use_topology_distance", false, "Topology Distance", - "Find the minimum number of steps, ignoring spatial distance"); - RNA_def_boolean( - ot->srna, "use_fill", false, "Fill Region", - "Select all paths between the source/destination elements"); - WM_operator_properties_checker_interval(ot, true); + RNA_def_boolean(ot->srna, + "use_face_step", + false, + "Face Stepping", + "Traverse connected faces (includes diagonals and edge-rings)"); + RNA_def_boolean(ot->srna, + "use_topology_distance", + false, + "Topology Distance", + "Find the minimum number of steps, ignoring spatial distance"); + RNA_def_boolean(ot->srna, + "use_fill", + false, + "Fill Region", + "Select all paths between the source/destination elements"); + WM_operator_properties_checker_interval(ot, true); } static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *op_params) { - op_params->edge_mode = EDGE_MODE_SELECT; - op_params->track_active = false; - op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); - op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill"); - op_params->use_topology_distance = RNA_boolean_get(op->ptr, "use_topology_distance"); - WM_operator_properties_checker_interval_from_op(op, &op_params->interval_params); + op_params->edge_mode = EDGE_MODE_SELECT; + op_params->track_active = false; + op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); + op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill"); + op_params->use_topology_distance = RNA_boolean_get(op->ptr, "use_topology_distance"); + WM_operator_properties_checker_interval_from_op(op, &op_params->interval_params); } struct UserData { - BMesh *bm; - Mesh *me; - const struct PathSelectParams *op_params; + BMesh *bm; + Mesh *me; + const struct PathSelectParams *op_params; }; /** \} */ @@ -112,102 +118,104 @@ struct UserData { /* callbacks */ static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v)) { - return !BM_elem_flag_test(v, BM_ELEM_HIDDEN); + return !BM_elem_flag_test(v, BM_ELEM_HIDDEN); } static bool verttag_test_cb(BMVert *v, void *UNUSED(user_data_v)) { - return BM_elem_flag_test_bool(v, BM_ELEM_SELECT); + return BM_elem_flag_test_bool(v, BM_ELEM_SELECT); } static void verttag_set_cb(BMVert *v, bool val, void *user_data_v) { - struct UserData *user_data = user_data_v; - BM_vert_select_set(user_data->bm, v, val); + struct UserData *user_data = user_data_v; + BM_vert_select_set(user_data->bm, v, val); } -static void mouse_mesh_shortest_path_vert( - Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params, - BMVert *v_act, BMVert *v_dst) +static void mouse_mesh_shortest_path_vert(Scene *UNUSED(scene), + Object *obedit, + const struct PathSelectParams *op_params, + BMVert *v_act, + BMVert *v_dst) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - struct UserData user_data = {bm, obedit->data, op_params}; - LinkNode *path = NULL; - bool is_path_ordered = false; - - if (v_act && (v_act != v_dst)) { - if (op_params->use_fill) { - path = BM_mesh_calc_path_region_vert( - bm, (BMElem *)v_act, (BMElem *)v_dst, - verttag_filter_cb, &user_data); - } - else { - is_path_ordered = true; - path = BM_mesh_calc_path_vert( - bm, v_act, v_dst, - &(const struct BMCalcPathParams) { - .use_topology_distance = op_params->use_topology_distance, - .use_step_face = op_params->use_face_step, - }, - verttag_filter_cb, &user_data); - } - - if (path) { - if (op_params->track_active) { - BM_select_history_remove(bm, v_act); - } - } - } - - BMVert *v_dst_last = v_dst; - - if (path) { - /* toggle the flag */ - bool all_set = true; - LinkNode *node; - - node = path; - do { - if (!verttag_test_cb((BMVert *)node->link, &user_data)) { - all_set = false; - break; - } - } while ((node = node->next)); - - /* We need to start as if just *after* a 'skip' block... */ - int depth = op_params->interval_params.skip; - node = path; - do { - if ((is_path_ordered == false) || - WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) - { - verttag_set_cb((BMVert *)node->link, !all_set, &user_data); - if (is_path_ordered) { - v_dst_last = node->link; - } - } - } while ((void)depth++, (node = node->next)); - - BLI_linklist_free(path, NULL); - } - else { - const bool is_act = !verttag_test_cb(v_dst, &user_data); - verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */ - } - - EDBM_selectmode_flush(em); - - if (op_params->track_active) { - /* even if this is selected it may not be in the selection list */ - if (BM_elem_flag_test(v_dst_last, BM_ELEM_SELECT) == 0) { - BM_select_history_remove(bm, v_dst_last); - } - else { - BM_select_history_store(bm, v_dst_last); - } - } - - EDBM_update_generic(em, false, false); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + struct UserData user_data = {bm, obedit->data, op_params}; + LinkNode *path = NULL; + bool is_path_ordered = false; + + if (v_act && (v_act != v_dst)) { + if (op_params->use_fill) { + path = BM_mesh_calc_path_region_vert( + bm, (BMElem *)v_act, (BMElem *)v_dst, verttag_filter_cb, &user_data); + } + else { + is_path_ordered = true; + path = BM_mesh_calc_path_vert(bm, + v_act, + v_dst, + &(const struct BMCalcPathParams){ + .use_topology_distance = op_params->use_topology_distance, + .use_step_face = op_params->use_face_step, + }, + verttag_filter_cb, + &user_data); + } + + if (path) { + if (op_params->track_active) { + BM_select_history_remove(bm, v_act); + } + } + } + + BMVert *v_dst_last = v_dst; + + if (path) { + /* toggle the flag */ + bool all_set = true; + LinkNode *node; + + node = path; + do { + if (!verttag_test_cb((BMVert *)node->link, &user_data)) { + all_set = false; + break; + } + } while ((node = node->next)); + + /* We need to start as if just *after* a 'skip' block... */ + int depth = op_params->interval_params.skip; + node = path; + do { + if ((is_path_ordered == false) || + WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) { + verttag_set_cb((BMVert *)node->link, !all_set, &user_data); + if (is_path_ordered) { + v_dst_last = node->link; + } + } + } while ((void)depth++, (node = node->next)); + + BLI_linklist_free(path, NULL); + } + else { + const bool is_act = !verttag_test_cb(v_dst, &user_data); + verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */ + } + + EDBM_selectmode_flush(em); + + if (op_params->track_active) { + /* even if this is selected it may not be in the selection list */ + if (BM_elem_flag_test(v_dst_last, BM_ELEM_SELECT) == 0) { + BM_select_history_remove(bm, v_dst_last); + } + else { + BM_select_history_store(bm, v_dst_last); + } + } + + EDBM_update_generic(em, false, false); } /** \} */ @@ -219,195 +227,195 @@ static void mouse_mesh_shortest_path_vert( /* callbacks */ static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v)) { - return !BM_elem_flag_test(e, BM_ELEM_HIDDEN); + return !BM_elem_flag_test(e, BM_ELEM_HIDDEN); } static bool edgetag_test_cb(BMEdge *e, void *user_data_v) { - struct UserData *user_data = user_data_v; - const char edge_mode = user_data->op_params->edge_mode; - BMesh *bm = user_data->bm; - - switch (edge_mode) { - case EDGE_MODE_SELECT: - return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false; - case EDGE_MODE_TAG_SEAM: - return BM_elem_flag_test(e, BM_ELEM_SEAM) ? true : false; - case EDGE_MODE_TAG_SHARP: - return BM_elem_flag_test(e, BM_ELEM_SMOOTH) ? false : true; - case EDGE_MODE_TAG_CREASE: - return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? true : false; - case EDGE_MODE_TAG_BEVEL: - return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? true : false; + struct UserData *user_data = user_data_v; + const char edge_mode = user_data->op_params->edge_mode; + BMesh *bm = user_data->bm; + + switch (edge_mode) { + case EDGE_MODE_SELECT: + return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false; + case EDGE_MODE_TAG_SEAM: + return BM_elem_flag_test(e, BM_ELEM_SEAM) ? true : false; + case EDGE_MODE_TAG_SHARP: + return BM_elem_flag_test(e, BM_ELEM_SMOOTH) ? false : true; + case EDGE_MODE_TAG_CREASE: + return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? true : false; + case EDGE_MODE_TAG_BEVEL: + return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? true : false; #ifdef WITH_FREESTYLE - case EDGE_MODE_TAG_FREESTYLE: - { - FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE); - return (!fed) ? false : (fed->flag & FREESTYLE_EDGE_MARK) ? true : false; - } + case EDGE_MODE_TAG_FREESTYLE: { + FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE); + return (!fed) ? false : (fed->flag & FREESTYLE_EDGE_MARK) ? true : false; + } #endif - } - return 0; + } + return 0; } static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v) { - struct UserData *user_data = user_data_v; - const char edge_mode = user_data->op_params->edge_mode; - BMesh *bm = user_data->bm; - - switch (edge_mode) { - case EDGE_MODE_SELECT: - BM_edge_select_set(bm, e, val); - break; - case EDGE_MODE_TAG_SEAM: - BM_elem_flag_set(e, BM_ELEM_SEAM, val); - break; - case EDGE_MODE_TAG_SHARP: - BM_elem_flag_set(e, BM_ELEM_SMOOTH, !val); - break; - case EDGE_MODE_TAG_CREASE: - BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f); - break; - case EDGE_MODE_TAG_BEVEL: - BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f); - break; + struct UserData *user_data = user_data_v; + const char edge_mode = user_data->op_params->edge_mode; + BMesh *bm = user_data->bm; + + switch (edge_mode) { + case EDGE_MODE_SELECT: + BM_edge_select_set(bm, e, val); + break; + case EDGE_MODE_TAG_SEAM: + BM_elem_flag_set(e, BM_ELEM_SEAM, val); + break; + case EDGE_MODE_TAG_SHARP: + BM_elem_flag_set(e, BM_ELEM_SMOOTH, !val); + break; + case EDGE_MODE_TAG_CREASE: + BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f); + break; + case EDGE_MODE_TAG_BEVEL: + BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f); + break; #ifdef WITH_FREESTYLE - case EDGE_MODE_TAG_FREESTYLE: - { - FreestyleEdge *fed; - fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE); - if (!val) - fed->flag &= ~FREESTYLE_EDGE_MARK; - else - fed->flag |= FREESTYLE_EDGE_MARK; - break; - } + case EDGE_MODE_TAG_FREESTYLE: { + FreestyleEdge *fed; + fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE); + if (!val) + fed->flag &= ~FREESTYLE_EDGE_MARK; + else + fed->flag |= FREESTYLE_EDGE_MARK; + break; + } #endif - } + } } static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode) { - BMesh *bm = me->edit_mesh->bm; - - switch (edge_mode) { - case EDGE_MODE_TAG_CREASE: - BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE); - break; - case EDGE_MODE_TAG_BEVEL: - BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT); - break; + BMesh *bm = me->edit_mesh->bm; + + switch (edge_mode) { + case EDGE_MODE_TAG_CREASE: + BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE); + break; + case EDGE_MODE_TAG_BEVEL: + BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT); + break; #ifdef WITH_FREESTYLE - case EDGE_MODE_TAG_FREESTYLE: - if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) { - BM_data_layer_add(bm, &bm->edata, CD_FREESTYLE_EDGE); - } - break; + case EDGE_MODE_TAG_FREESTYLE: + if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) { + BM_data_layer_add(bm, &bm->edata, CD_FREESTYLE_EDGE); + } + break; #endif - default: - break; - } + default: + break; + } } /* mesh shortest path select, uses prev-selected edge */ /* since you want to create paths with multiple selects, it doesn't have extend option */ -static void mouse_mesh_shortest_path_edge( - Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params, - BMEdge *e_act, BMEdge *e_dst) +static void mouse_mesh_shortest_path_edge(Scene *UNUSED(scene), + Object *obedit, + const struct PathSelectParams *op_params, + BMEdge *e_act, + BMEdge *e_dst) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - struct UserData user_data = {bm, obedit->data, op_params}; - LinkNode *path = NULL; - bool is_path_ordered = false; - - edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode); - - if (e_act && (e_act != e_dst)) { - if (op_params->use_fill) { - path = BM_mesh_calc_path_region_edge( - bm, (BMElem *)e_act, (BMElem *)e_dst, - edgetag_filter_cb, &user_data); - } - else { - is_path_ordered = true; - path = BM_mesh_calc_path_edge( - bm, e_act, e_dst, - &(const struct BMCalcPathParams) { - .use_topology_distance = op_params->use_topology_distance, - .use_step_face = op_params->use_face_step, - }, - edgetag_filter_cb, &user_data); - } - - if (path) { - if (op_params->track_active) { - BM_select_history_remove(bm, e_act); - } - } - } - - BMEdge *e_dst_last = e_dst; - - if (path) { - /* toggle the flag */ - bool all_set = true; - LinkNode *node; - - node = path; - do { - if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) { - all_set = false; - break; - } - } while ((node = node->next)); - - /* We need to start as if just *after* a 'skip' block... */ - int depth = op_params->interval_params.skip; - node = path; - do { - if ((is_path_ordered == false) || - WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) - { - edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data); - if (is_path_ordered) { - e_dst_last = node->link; - } - } - } while ((void)depth++, (node = node->next)); - - BLI_linklist_free(path, NULL); - } - else { - const bool is_act = !edgetag_test_cb(e_dst, &user_data); - edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode); - edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */ - } - - if (op_params->edge_mode != EDGE_MODE_SELECT) { - if (op_params->track_active) { - /* simple rules - last edge is _always_ active and selected */ - if (e_act) - BM_edge_select_set(bm, e_act, false); - BM_edge_select_set(bm, e_dst_last, true); - BM_select_history_store(bm, e_dst_last); - } - } - - EDBM_selectmode_flush(em); - - if (op_params->track_active) { - /* even if this is selected it may not be in the selection list */ - if (op_params->edge_mode == EDGE_MODE_SELECT) { - if (edgetag_test_cb(e_dst_last, &user_data) == 0) - BM_select_history_remove(bm, e_dst_last); - else - BM_select_history_store(bm, e_dst_last); - } - } - - EDBM_update_generic(em, false, false); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + struct UserData user_data = {bm, obedit->data, op_params}; + LinkNode *path = NULL; + bool is_path_ordered = false; + + edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode); + + if (e_act && (e_act != e_dst)) { + if (op_params->use_fill) { + path = BM_mesh_calc_path_region_edge( + bm, (BMElem *)e_act, (BMElem *)e_dst, edgetag_filter_cb, &user_data); + } + else { + is_path_ordered = true; + path = BM_mesh_calc_path_edge(bm, + e_act, + e_dst, + &(const struct BMCalcPathParams){ + .use_topology_distance = op_params->use_topology_distance, + .use_step_face = op_params->use_face_step, + }, + edgetag_filter_cb, + &user_data); + } + + if (path) { + if (op_params->track_active) { + BM_select_history_remove(bm, e_act); + } + } + } + + BMEdge *e_dst_last = e_dst; + + if (path) { + /* toggle the flag */ + bool all_set = true; + LinkNode *node; + + node = path; + do { + if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) { + all_set = false; + break; + } + } while ((node = node->next)); + + /* We need to start as if just *after* a 'skip' block... */ + int depth = op_params->interval_params.skip; + node = path; + do { + if ((is_path_ordered == false) || + WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) { + edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data); + if (is_path_ordered) { + e_dst_last = node->link; + } + } + } while ((void)depth++, (node = node->next)); + + BLI_linklist_free(path, NULL); + } + else { + const bool is_act = !edgetag_test_cb(e_dst, &user_data); + edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode); + edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */ + } + + if (op_params->edge_mode != EDGE_MODE_SELECT) { + if (op_params->track_active) { + /* simple rules - last edge is _always_ active and selected */ + if (e_act) + BM_edge_select_set(bm, e_act, false); + BM_edge_select_set(bm, e_dst_last, true); + BM_select_history_store(bm, e_dst_last); + } + } + + EDBM_selectmode_flush(em); + + if (op_params->track_active) { + /* even if this is selected it may not be in the selection list */ + if (op_params->edge_mode == EDGE_MODE_SELECT) { + if (edgetag_test_cb(e_dst_last, &user_data) == 0) + BM_select_history_remove(bm, e_dst_last); + else + BM_select_history_store(bm, e_dst_last); + } + } + + EDBM_update_generic(em, false, false); } /** \} */ @@ -419,107 +427,109 @@ static void mouse_mesh_shortest_path_edge( /* callbacks */ static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v)) { - return !BM_elem_flag_test(f, BM_ELEM_HIDDEN); + return !BM_elem_flag_test(f, BM_ELEM_HIDDEN); } //static bool facetag_test_cb(Scene *UNUSED(scene), BMesh *UNUSED(bm), BMFace *f) static bool facetag_test_cb(BMFace *f, void *UNUSED(user_data_v)) { - return BM_elem_flag_test_bool(f, BM_ELEM_SELECT); + return BM_elem_flag_test_bool(f, BM_ELEM_SELECT); } //static void facetag_set_cb(BMesh *bm, Scene *UNUSED(scene), BMFace *f, const bool val) static void facetag_set_cb(BMFace *f, bool val, void *user_data_v) { - struct UserData *user_data = user_data_v; - BM_face_select_set(user_data->bm, f, val); + struct UserData *user_data = user_data_v; + BM_face_select_set(user_data->bm, f, val); } -static void mouse_mesh_shortest_path_face( - Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params, - BMFace *f_act, BMFace *f_dst) +static void mouse_mesh_shortest_path_face(Scene *UNUSED(scene), + Object *obedit, + const struct PathSelectParams *op_params, + BMFace *f_act, + BMFace *f_dst) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - struct UserData user_data = {bm, obedit->data, op_params}; - LinkNode *path = NULL; - bool is_path_ordered = false; - - if (f_act) { - if (op_params->use_fill) { - path = BM_mesh_calc_path_region_face( - bm, (BMElem *)f_act, (BMElem *)f_dst, - facetag_filter_cb, &user_data); - } - else { - is_path_ordered = true; - path = BM_mesh_calc_path_face( - bm, f_act, f_dst, - &(const struct BMCalcPathParams) { - .use_topology_distance = op_params->use_topology_distance, - .use_step_face = op_params->use_face_step, - }, - facetag_filter_cb, &user_data); - } - - if (f_act != f_dst) { - if (path) { - if (op_params->track_active) { - BM_select_history_remove(bm, f_act); - } - } - } - } - - BMFace *f_dst_last = f_dst; - - if (path) { - /* toggle the flag */ - bool all_set = true; - LinkNode *node; - - node = path; - do { - if (!facetag_test_cb((BMFace *)node->link, &user_data)) { - all_set = false; - break; - } - } while ((node = node->next)); - - /* We need to start as if just *after* a 'skip' block... */ - int depth = op_params->interval_params.skip; - node = path; - do { - if ((is_path_ordered == false) || - WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) - { - facetag_set_cb((BMFace *)node->link, !all_set, &user_data); - if (is_path_ordered) { - f_dst_last = node->link; - } - } - } while ((void)depth++, (node = node->next)); - - BLI_linklist_free(path, NULL); - } - else { - const bool is_act = !facetag_test_cb(f_dst, &user_data); - facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */ - } - - EDBM_selectmode_flush(em); - - if (op_params->track_active) { - /* even if this is selected it may not be in the selection list */ - if (facetag_test_cb(f_dst_last, &user_data) == 0) { - BM_select_history_remove(bm, f_dst_last); - } - else { - BM_select_history_store(bm, f_dst_last); - } - BM_mesh_active_face_set(bm, f_dst_last); - } - - EDBM_update_generic(em, false, false); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + struct UserData user_data = {bm, obedit->data, op_params}; + LinkNode *path = NULL; + bool is_path_ordered = false; + + if (f_act) { + if (op_params->use_fill) { + path = BM_mesh_calc_path_region_face( + bm, (BMElem *)f_act, (BMElem *)f_dst, facetag_filter_cb, &user_data); + } + else { + is_path_ordered = true; + path = BM_mesh_calc_path_face(bm, + f_act, + f_dst, + &(const struct BMCalcPathParams){ + .use_topology_distance = op_params->use_topology_distance, + .use_step_face = op_params->use_face_step, + }, + facetag_filter_cb, + &user_data); + } + + if (f_act != f_dst) { + if (path) { + if (op_params->track_active) { + BM_select_history_remove(bm, f_act); + } + } + } + } + + BMFace *f_dst_last = f_dst; + + if (path) { + /* toggle the flag */ + bool all_set = true; + LinkNode *node; + + node = path; + do { + if (!facetag_test_cb((BMFace *)node->link, &user_data)) { + all_set = false; + break; + } + } while ((node = node->next)); + + /* We need to start as if just *after* a 'skip' block... */ + int depth = op_params->interval_params.skip; + node = path; + do { + if ((is_path_ordered == false) || + WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) { + facetag_set_cb((BMFace *)node->link, !all_set, &user_data); + if (is_path_ordered) { + f_dst_last = node->link; + } + } + } while ((void)depth++, (node = node->next)); + + BLI_linklist_free(path, NULL); + } + else { + const bool is_act = !facetag_test_cb(f_dst, &user_data); + facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */ + } + + EDBM_selectmode_flush(em); + + if (op_params->track_active) { + /* even if this is selected it may not be in the selection list */ + if (facetag_test_cb(f_dst_last, &user_data) == 0) { + BM_select_history_remove(bm, f_dst_last); + } + else { + BM_select_history_store(bm, f_dst_last); + } + BM_mesh_active_face_set(bm, f_dst_last); + } + + EDBM_update_generic(em, false, false); } /** \} */ @@ -528,206 +538,204 @@ static void mouse_mesh_shortest_path_face( /** \name Main Operator for vert/edge/face tag * \{ */ -static bool edbm_shortest_path_pick_ex( - Scene *scene, Object *obedit, const struct PathSelectParams *op_params, - BMElem *ele_src, BMElem *ele_dst) +static bool edbm_shortest_path_pick_ex(Scene *scene, + Object *obedit, + const struct PathSelectParams *op_params, + BMElem *ele_src, + BMElem *ele_dst) { - bool ok = false; - - if (ELEM(NULL, ele_src, ele_dst) || (ele_src->head.htype != ele_dst->head.htype)) { - /* pass */ - } - else if (ele_src->head.htype == BM_VERT) { - mouse_mesh_shortest_path_vert(scene, obedit, op_params, (BMVert *)ele_src, (BMVert *)ele_dst); - ok = true; - } - else if (ele_src->head.htype == BM_EDGE) { - mouse_mesh_shortest_path_edge(scene, obedit, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst); - ok = true; - } - else if (ele_src->head.htype == BM_FACE) { - mouse_mesh_shortest_path_face(scene, obedit, op_params, (BMFace *)ele_src, (BMFace *)ele_dst); - ok = true; - } - - if (ok) { - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); - } - - return ok; + bool ok = false; + + if (ELEM(NULL, ele_src, ele_dst) || (ele_src->head.htype != ele_dst->head.htype)) { + /* pass */ + } + else if (ele_src->head.htype == BM_VERT) { + mouse_mesh_shortest_path_vert(scene, obedit, op_params, (BMVert *)ele_src, (BMVert *)ele_dst); + ok = true; + } + else if (ele_src->head.htype == BM_EDGE) { + mouse_mesh_shortest_path_edge(scene, obedit, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst); + ok = true; + } + else if (ele_src->head.htype == BM_FACE) { + mouse_mesh_shortest_path_face(scene, obedit, op_params, (BMFace *)ele_src, (BMFace *)ele_dst); + ok = true; + } + + if (ok) { + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); + } + + return ok; } static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op); static BMElem *edbm_elem_find_nearest(ViewContext *vc, const char htype) { - BMEditMesh *em = vc->em; - float dist = ED_view3d_select_dist_px(); - - if ((em->selectmode & SCE_SELECT_VERTEX) && (htype == BM_VERT)) { - return (BMElem *)EDBM_vert_find_nearest(vc, &dist); - } - else if ((em->selectmode & SCE_SELECT_EDGE) && (htype == BM_EDGE)) { - return (BMElem *)EDBM_edge_find_nearest(vc, &dist); - } - else if ((em->selectmode & SCE_SELECT_FACE) && (htype == BM_FACE)) { - return (BMElem *)EDBM_face_find_nearest(vc, &dist); - } - - return NULL; + BMEditMesh *em = vc->em; + float dist = ED_view3d_select_dist_px(); + + if ((em->selectmode & SCE_SELECT_VERTEX) && (htype == BM_VERT)) { + return (BMElem *)EDBM_vert_find_nearest(vc, &dist); + } + else if ((em->selectmode & SCE_SELECT_EDGE) && (htype == BM_EDGE)) { + return (BMElem *)EDBM_edge_find_nearest(vc, &dist); + } + else if ((em->selectmode & SCE_SELECT_FACE) && (htype == BM_FACE)) { + return (BMElem *)EDBM_face_find_nearest(vc, &dist); + } + + return NULL; } static BMElem *edbm_elem_active_elem_or_face_get(BMesh *bm) { - BMElem *ele = BM_mesh_active_elem_get(bm); + BMElem *ele = BM_mesh_active_elem_get(bm); - if ((ele == NULL) && bm->act_face && BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT)) { - ele = (BMElem *)bm->act_face; - } + if ((ele == NULL) && bm->act_face && BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT)) { + ele = (BMElem *)bm->act_face; + } - return ele; + return ele; } static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (RNA_struct_property_is_set(op->ptr, "index")) { - return edbm_shortest_path_pick_exec(C, op); - } - - Base *basact = NULL; - BMVert *eve = NULL; - BMEdge *eed = NULL; - BMFace *efa = NULL; - - ViewContext vc; - BMEditMesh *em; - bool track_active = true; - - em_setup_viewcontext(C, &vc); - copy_v2_v2_int(vc.mval, event->mval); - em = vc.em; - - view3d_operator_needs_opengl(C); - - { - int base_index = -1; - uint bases_len = 0; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); - if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) { - basact = bases[base_index]; - ED_view3d_viewcontext_init_object(&vc, basact->object); - em = vc.em; - } - MEM_freeN(bases); - } - - /* If nothing is selected, let's select the picked vertex/edge/face. */ - if ((vc.em->bm->totvertsel == 0) && (eve || eed || efa)) { - /* TODO (dfelinto) right now we try to find the closest element twice. - * The ideal is to refactor EDBM_select_pick so it doesn't - * have to pick the nearest vert/edge/face again. - */ - EDBM_select_pick(C, event->mval, true, false, false); - return OPERATOR_FINISHED; - } - - BMElem *ele_src, *ele_dst; - if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) || - !(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype))) - { - /* special case, toggle edge tags even when we don't have a path */ - if (((em->selectmode & SCE_SELECT_EDGE) && - (vc.scene->toolsettings->edge_mode != EDGE_MODE_SELECT)) && - /* check if we only have a destination edge */ - ((ele_src == NULL) && - (ele_dst = edbm_elem_find_nearest(&vc, BM_EDGE)))) - { - ele_src = ele_dst; - track_active = false; - } - else { - return OPERATOR_PASS_THROUGH; - } - } - - struct PathSelectParams op_params; - - path_select_params_from_op(op, &op_params); - op_params.track_active = track_active; - op_params.edge_mode = vc.scene->toolsettings->edge_mode; - - if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) { - return OPERATOR_PASS_THROUGH; - } - - if (vc.view_layer->basact != basact) { - ED_object_base_activate(C, basact); - } - - /* to support redo */ - BM_mesh_elem_index_ensure(em->bm, ele_dst->head.htype); - int index = EDBM_elem_to_index_any(em, ele_dst); - - RNA_int_set(op->ptr, "index", index); - - return OPERATOR_FINISHED; + if (RNA_struct_property_is_set(op->ptr, "index")) { + return edbm_shortest_path_pick_exec(C, op); + } + + Base *basact = NULL; + BMVert *eve = NULL; + BMEdge *eed = NULL; + BMFace *efa = NULL; + + ViewContext vc; + BMEditMesh *em; + bool track_active = true; + + em_setup_viewcontext(C, &vc); + copy_v2_v2_int(vc.mval, event->mval); + em = vc.em; + + view3d_operator_needs_opengl(C); + + { + int base_index = -1; + uint bases_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); + if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) { + basact = bases[base_index]; + ED_view3d_viewcontext_init_object(&vc, basact->object); + em = vc.em; + } + MEM_freeN(bases); + } + + /* If nothing is selected, let's select the picked vertex/edge/face. */ + if ((vc.em->bm->totvertsel == 0) && (eve || eed || efa)) { + /* TODO (dfelinto) right now we try to find the closest element twice. + * The ideal is to refactor EDBM_select_pick so it doesn't + * have to pick the nearest vert/edge/face again. + */ + EDBM_select_pick(C, event->mval, true, false, false); + return OPERATOR_FINISHED; + } + + BMElem *ele_src, *ele_dst; + if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) || + !(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype))) { + /* special case, toggle edge tags even when we don't have a path */ + if (((em->selectmode & SCE_SELECT_EDGE) && + (vc.scene->toolsettings->edge_mode != EDGE_MODE_SELECT)) && + /* check if we only have a destination edge */ + ((ele_src == NULL) && (ele_dst = edbm_elem_find_nearest(&vc, BM_EDGE)))) { + ele_src = ele_dst; + track_active = false; + } + else { + return OPERATOR_PASS_THROUGH; + } + } + + struct PathSelectParams op_params; + + path_select_params_from_op(op, &op_params); + op_params.track_active = track_active; + op_params.edge_mode = vc.scene->toolsettings->edge_mode; + + if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) { + return OPERATOR_PASS_THROUGH; + } + + if (vc.view_layer->basact != basact) { + ED_object_base_activate(C, basact); + } + + /* to support redo */ + BM_mesh_elem_index_ensure(em->bm, ele_dst->head.htype); + int index = EDBM_elem_to_index_any(em, ele_dst); + + RNA_int_set(op->ptr, "index", index); + + return OPERATOR_FINISHED; } static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - const int index = RNA_int_get(op->ptr, "index"); - if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) { - return OPERATOR_CANCELLED; - } - - BMElem *ele_src, *ele_dst; - if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) || - !(ele_dst = EDBM_elem_from_index_any(em, index))) - { - return OPERATOR_CANCELLED; - } - - struct PathSelectParams op_params; - path_select_params_from_op(op, &op_params); - op_params.track_active = true; - op_params.edge_mode = scene->toolsettings->edge_mode; - - if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) { - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + const int index = RNA_int_get(op->ptr, "index"); + if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) { + return OPERATOR_CANCELLED; + } + + BMElem *ele_src, *ele_dst; + if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) || + !(ele_dst = EDBM_elem_from_index_any(em, index))) { + return OPERATOR_CANCELLED; + } + + struct PathSelectParams op_params; + path_select_params_from_op(op, &op_params); + op_params.track_active = true; + op_params.edge_mode = scene->toolsettings->edge_mode; + + if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) { + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } void MESH_OT_shortest_path_pick(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Pick Shortest Path"; - ot->idname = "MESH_OT_shortest_path_pick"; - ot->description = "Select shortest path between two selections"; + /* identifiers */ + ot->name = "Pick Shortest Path"; + ot->idname = "MESH_OT_shortest_path_pick"; + ot->description = "Select shortest path between two selections"; - /* api callbacks */ - ot->invoke = edbm_shortest_path_pick_invoke; - ot->exec = edbm_shortest_path_pick_exec; - ot->poll = ED_operator_editmesh_region_view3d; + /* api callbacks */ + ot->invoke = edbm_shortest_path_pick_invoke; + ot->exec = edbm_shortest_path_pick_exec; + ot->poll = ED_operator_editmesh_region_view3d; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - path_select_properties(ot); + /* properties */ + path_select_properties(ot); - /* use for redo */ - prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* use for redo */ + prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /** \} */ @@ -738,106 +746,112 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot) static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - bool found_valid_elements = false; - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter; - BMEditSelection *ese_src, *ese_dst; - BMElem *ele_src = NULL, *ele_dst = NULL, *ele; - - if ((em->bm->totvertsel == 0) && - (em->bm->totedgesel == 0) && - (em->bm->totfacesel == 0)) - { - continue; - } - - /* first try to find vertices in edit selection */ - ese_src = bm->selected.last; - if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) { - ele_src = ese_src->ele; - ele_dst = ese_dst->ele; - } - else { - /* if selection history isn't available, find two selected elements */ - ele_src = ele_dst = NULL; - if ((em->selectmode & SCE_SELECT_VERTEX) && (bm->totvertsel >= 2)) { - BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { - if (ele_src == NULL) ele_src = ele; - else if (ele_dst == NULL) ele_dst = ele; - else break; - } - } - } - - if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_EDGE) && (bm->totedgesel >= 2)) { - ele_src = NULL; - BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { - if (ele_src == NULL) ele_src = ele; - else if (ele_dst == NULL) ele_dst = ele; - else break; - } - } - } - - if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_FACE) && (bm->totfacesel >= 2)) { - ele_src = NULL; - BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { - if (ele_src == NULL) ele_src = ele; - else if (ele_dst == NULL) ele_dst = ele; - else break; - } - } - } - } - - if (ele_src && ele_dst) { - struct PathSelectParams op_params; - path_select_params_from_op(op, &op_params); - - edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst); - - found_valid_elements = true; - } - } - MEM_freeN(objects); - - if (!found_valid_elements) { - BKE_report(op->reports, - RPT_WARNING, - "Path selection requires two matching elements to be selected"); - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + bool found_valid_elements = false; + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter iter; + BMEditSelection *ese_src, *ese_dst; + BMElem *ele_src = NULL, *ele_dst = NULL, *ele; + + if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) { + continue; + } + + /* first try to find vertices in edit selection */ + ese_src = bm->selected.last; + if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) { + ele_src = ese_src->ele; + ele_dst = ese_dst->ele; + } + else { + /* if selection history isn't available, find two selected elements */ + ele_src = ele_dst = NULL; + if ((em->selectmode & SCE_SELECT_VERTEX) && (bm->totvertsel >= 2)) { + BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { + if (ele_src == NULL) + ele_src = ele; + else if (ele_dst == NULL) + ele_dst = ele; + else + break; + } + } + } + + if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_EDGE) && (bm->totedgesel >= 2)) { + ele_src = NULL; + BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { + if (ele_src == NULL) + ele_src = ele; + else if (ele_dst == NULL) + ele_dst = ele; + else + break; + } + } + } + + if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_FACE) && (bm->totfacesel >= 2)) { + ele_src = NULL; + BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { + if (ele_src == NULL) + ele_src = ele; + else if (ele_dst == NULL) + ele_dst = ele; + else + break; + } + } + } + } + + if (ele_src && ele_dst) { + struct PathSelectParams op_params; + path_select_params_from_op(op, &op_params); + + edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst); + + found_valid_elements = true; + } + } + MEM_freeN(objects); + + if (!found_valid_elements) { + BKE_report( + op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } void MESH_OT_shortest_path_select(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Shortest Path"; - ot->idname = "MESH_OT_shortest_path_select"; - ot->description = "Selected shortest path between two vertices/edges/faces"; + /* identifiers */ + ot->name = "Select Shortest Path"; + ot->idname = "MESH_OT_shortest_path_select"; + ot->description = "Selected shortest path between two vertices/edges/faces"; - /* api callbacks */ - ot->exec = edbm_shortest_path_select_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_shortest_path_select_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - path_select_properties(ot); + /* properties */ + path_select_properties(ot); } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c index 7decd5f4b2f..088d1672cc9 100644 --- a/source/blender/editors/mesh/editmesh_polybuild.c +++ b/source/blender/editors/mesh/editmesh_polybuild.c @@ -44,7 +44,7 @@ #include "bmesh.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ #include "RNA_access.h" #include "RNA_define.h" @@ -59,70 +59,67 @@ static void edbm_selectmode_ensure(Scene *scene, BMEditMesh *em, short selectmode) { - if ((scene->toolsettings->selectmode & selectmode) == 0) { - scene->toolsettings->selectmode |= selectmode; - em->selectmode = scene->toolsettings->selectmode; - EDBM_selectmode_set(em); - } + if ((scene->toolsettings->selectmode & selectmode) == 0) { + scene->toolsettings->selectmode |= selectmode; + em->selectmode = scene->toolsettings->selectmode; + EDBM_selectmode_set(em); + } } /* Could make public, for now just keep here. */ static void edbm_flag_disable_all_multi(ViewLayer *view_layer, View3D *v3d, const char hflag) { - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; - BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); - BMesh *bm_iter = em_iter->bm; - if (bm_iter->totvertsel) { - EDBM_flag_disable_all(em_iter, hflag); - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); - } - } - MEM_freeN(objects); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, v3d, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); + BMesh *bm_iter = em_iter->bm; + if (bm_iter->totvertsel) { + EDBM_flag_disable_all(em_iter, hflag); + DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + } + } + MEM_freeN(objects); } /* When accessed as a tool, get the active edge from the preselection gizmo. */ -static bool edbm_preselect_or_active( - bContext *C, - const View3D *v3d, - Base **r_base, - BMElem **r_ele) +static bool edbm_preselect_or_active(bContext *C, const View3D *v3d, Base **r_base, BMElem **r_ele) { - ARegion *ar = CTX_wm_region(C); - const bool show_gizmo = !((v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL))); - - wmGizmoMap *gzmap = show_gizmo ? ar->gizmo_map : NULL; - wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_mesh_preselect_elem") : NULL; - if (gzgroup != NULL) { - wmGizmo *gz = gzgroup->gizmos.first; - ED_view3d_gizmo_mesh_preselect_get_active(C, gz, r_base, r_ele); - } - else { - ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base = view_layer->basact; - Object *obedit = base->object; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - *r_base = base; - *r_ele = BM_mesh_active_elem_get(bm); - } - return (*r_ele != NULL); + ARegion *ar = CTX_wm_region(C); + const bool show_gizmo = !((v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL))); + + wmGizmoMap *gzmap = show_gizmo ? ar->gizmo_map : NULL; + wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_mesh_preselect_elem") : + NULL; + if (gzgroup != NULL) { + wmGizmo *gz = gzgroup->gizmos.first; + ED_view3d_gizmo_mesh_preselect_get_active(C, gz, r_base, r_ele); + } + else { + ViewLayer *view_layer = CTX_data_view_layer(C); + Base *base = view_layer->basact; + Object *obedit = base->object; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + *r_base = base; + *r_ele = BM_mesh_active_elem_get(bm); + } + return (*r_ele != NULL); } -static bool edbm_preselect_or_active_init_viewcontext( - bContext *C, - ViewContext *vc, - Base **r_base, - BMElem **r_ele) +static bool edbm_preselect_or_active_init_viewcontext(bContext *C, + ViewContext *vc, + Base **r_base, + BMElem **r_ele) { - em_setup_viewcontext(C, vc); - bool ok = edbm_preselect_or_active(C, vc->v3d, r_base, r_ele); - if (ok) { - ED_view3d_viewcontext_init_object(vc, (*r_base)->object); - } - return ok; + em_setup_viewcontext(C, vc); + bool ok = edbm_preselect_or_active(C, vc->v3d, r_base, r_ele); + if (ok) { + ED_view3d_viewcontext_init_object(vc, (*r_base)->object); + } + return ok; } /** \} */ @@ -131,163 +128,161 @@ static bool edbm_preselect_or_active_init_viewcontext( /** \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 *UNUSED(op), + const wmEvent *event) { - float center[3]; - 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); - - edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX); - - if (ele_act == NULL || ele_act->head.htype == BM_FACE) { - /* Just add vert */ - copy_v3_v3(center, vc.scene->cursor.location); - mul_v3_m4v3(center, 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_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP); - 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); - changed = true; - } - else if (ele_act->head.htype == BM_EDGE) { - BMEdge *e_act = (BMEdge *)ele_act; - BMFace *f_reference = e_act->l ? e_act->l->f : NULL; - - mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co); - 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]); - } - // 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) { - BMVert *v_act = (BMVert *)ele_act; - BMEdge *e_pair[2] = {NULL}; - - 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) { - /* Quad from edge pair. */ - if (BM_edge_calc_length_squared(e_pair[0]) < - BM_edge_calc_length_squared(e_pair[1])) - { - SWAP(BMEdge *, e_pair[0], e_pair[1]); - } - - BMFace *f_reference = e_pair[0]->l ? e_pair[0]->l->f : NULL; - - mul_v3_m4v3(center, vc.obedit->obmat, v_act->co); - ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center); - mul_m4_v3(vc.obedit->imat, center); - - BMVert *v_quad[4]; - v_quad[0] = v_act; - v_quad[1] = BM_edge_other_vert(e_pair[0], v_act); - v_quad[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP); - v_quad[3] = BM_edge_other_vert(e_pair[1], v_act); - if (e_pair[0]->l && e_pair[0]->l->v == v_quad[0]) { - SWAP(BMVert *, v_quad[1], v_quad[3]); - } - // BMFace *f_new = - BM_face_create_verts(bm, v_quad, 4, 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_quad[2], true); - BM_select_history_store(bm, v_quad[2]); - changed = true; - } - else { - /* Just add edge */ - mul_m4_v3(vc.obedit->obmat, center); - ED_view3d_win_to_3d_int(vc.v3d, vc.ar, v_act->co, event->mval, center); - mul_m4_v3(vc.obedit->imat, center); - - BMVert *v_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP); - - BM_edge_create(bm, v_act, v_new, NULL, BM_CREATE_NOP); - - BM_vert_select_set(bm, v_new, true); - BM_select_history_store(bm, v_new); - 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; - } + float center[3]; + 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); + + edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX); + + if (ele_act == NULL || ele_act->head.htype == BM_FACE) { + /* Just add vert */ + copy_v3_v3(center, vc.scene->cursor.location); + mul_v3_m4v3(center, 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_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP); + 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); + changed = true; + } + else if (ele_act->head.htype == BM_EDGE) { + BMEdge *e_act = (BMEdge *)ele_act; + BMFace *f_reference = e_act->l ? e_act->l->f : NULL; + + mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co); + 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]); + } + // 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) { + BMVert *v_act = (BMVert *)ele_act; + BMEdge *e_pair[2] = {NULL}; + + 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) { + /* Quad from edge pair. */ + if (BM_edge_calc_length_squared(e_pair[0]) < BM_edge_calc_length_squared(e_pair[1])) { + SWAP(BMEdge *, e_pair[0], e_pair[1]); + } + + BMFace *f_reference = e_pair[0]->l ? e_pair[0]->l->f : NULL; + + mul_v3_m4v3(center, vc.obedit->obmat, v_act->co); + ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center); + mul_m4_v3(vc.obedit->imat, center); + + BMVert *v_quad[4]; + v_quad[0] = v_act; + v_quad[1] = BM_edge_other_vert(e_pair[0], v_act); + v_quad[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP); + v_quad[3] = BM_edge_other_vert(e_pair[1], v_act); + if (e_pair[0]->l && e_pair[0]->l->v == v_quad[0]) { + SWAP(BMVert *, v_quad[1], v_quad[3]); + } + // BMFace *f_new = + BM_face_create_verts(bm, v_quad, 4, 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_quad[2], true); + BM_select_history_store(bm, v_quad[2]); + changed = true; + } + else { + /* Just add edge */ + mul_m4_v3(vc.obedit->obmat, center); + ED_view3d_win_to_3d_int(vc.v3d, vc.ar, v_act->co, event->mval, center); + mul_m4_v3(vc.obedit->imat, center); + + BMVert *v_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP); + + BM_edge_create(bm, v_act, v_new, NULL, BM_CREATE_NOP); + + BM_vert_select_set(bm, v_new, true); + BM_select_history_store(bm, v_new); + 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_face_at_cursor(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Poly Build Face at Cursor"; - ot->idname = "MESH_OT_polybuild_face_at_cursor"; + /* identifiers */ + ot->name = "Poly Build Face at Cursor"; + ot->idname = "MESH_OT_polybuild_face_at_cursor"; - /* api callbacks */ - ot->invoke = edbm_polybuild_face_at_cursor_invoke; - ot->poll = EDBM_view3d_poll; + /* api callbacks */ + ot->invoke = edbm_polybuild_face_at_cursor_invoke; + ot->poll = EDBM_view3d_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* to give to transform */ - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); + /* to give to transform */ + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); } /** \} */ @@ -296,170 +291,171 @@ void MESH_OT_polybuild_face_at_cursor(wmOperatorType *ot) /** \name Split at Cursor * \{ */ -static int edbm_polybuild_split_at_cursor_invoke( - bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +static int edbm_polybuild_split_at_cursor_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *event) { - float center[3]; - 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); - - edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX); - - if (ele_act == NULL || ele_act->head.hflag == BM_FACE) { - return OPERATOR_PASS_THROUGH; - } - else if (ele_act->head.htype == BM_EDGE) { - BMEdge *e_act = (BMEdge *)ele_act; - mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co); - 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); - - 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); - changed = true; - } - else if (ele_act->head.htype == BM_VERT) { - /* Just do nothing, allow dragging. */ - return OPERATOR_FINISHED; - } - - if (changed) { - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - - WM_event_add_mousemove(C); - - if (vc.view_layer->basact != basact) { - ED_object_base_activate(C, basact); - } - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + float center[3]; + 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); + + edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX); + + if (ele_act == NULL || ele_act->head.hflag == BM_FACE) { + return OPERATOR_PASS_THROUGH; + } + else if (ele_act->head.htype == BM_EDGE) { + BMEdge *e_act = (BMEdge *)ele_act; + mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co); + 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); + + 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); + changed = true; + } + else if (ele_act->head.htype == BM_VERT) { + /* Just do nothing, allow dragging. */ + return OPERATOR_FINISHED; + } + + if (changed) { + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + + WM_event_add_mousemove(C); + + if (vc.view_layer->basact != basact) { + ED_object_base_activate(C, basact); + } + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void MESH_OT_polybuild_split_at_cursor(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Poly Build Split at Cursor"; - ot->idname = "MESH_OT_polybuild_split_at_cursor"; + /* identifiers */ + ot->name = "Poly Build Split at Cursor"; + ot->idname = "MESH_OT_polybuild_split_at_cursor"; - /* api callbacks */ - ot->invoke = edbm_polybuild_split_at_cursor_invoke; - ot->poll = EDBM_view3d_poll; + /* api callbacks */ + ot->invoke = edbm_polybuild_split_at_cursor_invoke; + ot->poll = EDBM_view3d_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* to give to transform */ - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); + /* to give to transform */ + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); } /** \} */ - /* -------------------------------------------------------------------- */ /** \name Dissolve at Cursor * * \{ */ -static int edbm_polybuild_dissolve_at_cursor_invoke( - bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int edbm_polybuild_dissolve_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; - - if (ele_act == NULL) { - /* pass */ - } - else if (ele_act->head.htype == BM_EDGE) { - BMEdge *e_act = (BMEdge *)ele_act; - BMLoop *l_a, *l_b; - if (BM_edge_loop_pair(e_act, &l_a, &l_b)) { - BMFace *f_new = BM_faces_join_pair(bm, l_a, l_b, true); - if (f_new) { - changed = true; - } - } - } - else 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); - } - else { - /* too involved to do inline */ - - /* Avoid using selection so failure wont leave modified state. */ - 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_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT); - - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - - if (vc.view_layer->basact != basact) { - ED_object_base_activate(C, basact); - } - - WM_event_add_mousemove(C); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + 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; + + if (ele_act == NULL) { + /* pass */ + } + else if (ele_act->head.htype == BM_EDGE) { + BMEdge *e_act = (BMEdge *)ele_act; + BMLoop *l_a, *l_b; + if (BM_edge_loop_pair(e_act, &l_a, &l_b)) { + BMFace *f_new = BM_faces_join_pair(bm, l_a, l_b, true); + if (f_new) { + changed = true; + } + } + } + else 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); + } + else { + /* too involved to do inline */ + + /* Avoid using selection so failure wont leave modified state. */ + 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_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT); + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + + 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_dissolve_at_cursor(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Poly Build Dissolve at Cursor"; - ot->idname = "MESH_OT_polybuild_dissolve_at_cursor"; + /* identifiers */ + ot->name = "Poly Build Dissolve at Cursor"; + ot->idname = "MESH_OT_polybuild_dissolve_at_cursor"; - /* api callbacks */ - ot->invoke = edbm_polybuild_dissolve_at_cursor_invoke; - ot->poll = EDBM_view3d_poll; + /* api callbacks */ + ot->invoke = edbm_polybuild_dissolve_at_cursor_invoke; + ot->poll = EDBM_view3d_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_preselect_edgering.c b/source/blender/editors/mesh/editmesh_preselect_edgering.c index 9e761713f7e..b007343e14e 100644 --- a/source/blender/editors/mesh/editmesh_preselect_edgering.c +++ b/source/blender/editors/mesh/editmesh_preselect_edgering.c @@ -47,304 +47,309 @@ static void edgering_vcos_get(BMVert *v[2][2], float r_cos[2][2][3], const float (*coords)[3]) { - if (coords) { - int j, k; - for (j = 0; j < 2; j++) { - for (k = 0; k < 2; k++) { - copy_v3_v3(r_cos[j][k], coords[BM_elem_index_get(v[j][k])]); - } - } - } - else { - int j, k; - for (j = 0; j < 2; j++) { - for (k = 0; k < 2; k++) { - copy_v3_v3(r_cos[j][k], v[j][k]->co); - } - } - } + if (coords) { + int j, k; + for (j = 0; j < 2; j++) { + for (k = 0; k < 2; k++) { + copy_v3_v3(r_cos[j][k], coords[BM_elem_index_get(v[j][k])]); + } + } + } + else { + int j, k; + for (j = 0; j < 2; j++) { + for (k = 0; k < 2; k++) { + copy_v3_v3(r_cos[j][k], v[j][k]->co); + } + } + } } static void edgering_vcos_get_pair(BMVert *v[2], float r_cos[2][3], const float (*coords)[3]) { - if (coords) { - int j; - for (j = 0; j < 2; j++) { - copy_v3_v3(r_cos[j], coords[BM_elem_index_get(v[j])]); - } - } - else { - int j; - for (j = 0; j < 2; j++) { - copy_v3_v3(r_cos[j], v[j]->co); - } - } + if (coords) { + int j; + for (j = 0; j < 2; j++) { + copy_v3_v3(r_cos[j], coords[BM_elem_index_get(v[j])]); + } + } + else { + int j; + for (j = 0; j < 2; j++) { + copy_v3_v3(r_cos[j], v[j]->co); + } + } } - /** * Given two opposite edges in a face, finds the ordering of their vertices so * that cut preview lines won't cross each other. */ -static void edgering_find_order( - BMEdge *eed_last, BMEdge *eed, - BMVert *eve_last, BMVert *v[2][2]) +static void edgering_find_order(BMEdge *eed_last, BMEdge *eed, BMVert *eve_last, BMVert *v[2][2]) { - BMLoop *l = eed->l; - - /* find correct order for v[1] */ - if (!(BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))) { - BMIter liter; - BM_ITER_ELEM (l, &liter, l, BM_LOOPS_OF_LOOP) { - if (BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f)) - break; - } - } - - /* this should never happen */ - if (!l) { - v[0][0] = eed->v1; - v[0][1] = eed->v2; - v[1][0] = eed_last->v1; - v[1][1] = eed_last->v2; - return; - } - - BMLoop *l_other = BM_loop_other_edge_loop(l, eed->v1); - const bool rev = (l_other == l->prev); - while (l_other->v != eed_last->v1 && l_other->v != eed_last->v2) { - l_other = rev ? l_other->prev : l_other->next; - } - - if (l_other->v == eve_last) { - v[0][0] = eed->v1; - v[0][1] = eed->v2; - } - else { - v[0][0] = eed->v2; - v[0][1] = eed->v1; - } + BMLoop *l = eed->l; + + /* find correct order for v[1] */ + if (!(BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))) { + BMIter liter; + BM_ITER_ELEM (l, &liter, l, BM_LOOPS_OF_LOOP) { + if (BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f)) + break; + } + } + + /* this should never happen */ + if (!l) { + v[0][0] = eed->v1; + v[0][1] = eed->v2; + v[1][0] = eed_last->v1; + v[1][1] = eed_last->v2; + return; + } + + BMLoop *l_other = BM_loop_other_edge_loop(l, eed->v1); + const bool rev = (l_other == l->prev); + while (l_other->v != eed_last->v1 && l_other->v != eed_last->v2) { + l_other = rev ? l_other->prev : l_other->next; + } + + if (l_other->v == eve_last) { + v[0][0] = eed->v1; + v[0][1] = eed->v2; + } + else { + v[0][0] = eed->v2; + v[0][1] = eed->v1; + } } struct EditMesh_PreSelEdgeRing { - float (*edges)[2][3]; - int edges_len; + float (*edges)[2][3]; + int edges_len; - float (*verts)[3]; - int verts_len; + float (*verts)[3]; + int verts_len; }; struct EditMesh_PreSelEdgeRing *EDBM_preselect_edgering_create(void) { - struct EditMesh_PreSelEdgeRing *psel = MEM_callocN(sizeof(*psel), __func__); - return psel; + struct EditMesh_PreSelEdgeRing *psel = MEM_callocN(sizeof(*psel), __func__); + return psel; } -void EDBM_preselect_edgering_destroy( - struct EditMesh_PreSelEdgeRing *psel) +void EDBM_preselect_edgering_destroy(struct EditMesh_PreSelEdgeRing *psel) { - EDBM_preselect_edgering_clear(psel); - MEM_freeN(psel); + EDBM_preselect_edgering_clear(psel); + MEM_freeN(psel); } -void EDBM_preselect_edgering_clear( - struct EditMesh_PreSelEdgeRing *psel) +void EDBM_preselect_edgering_clear(struct EditMesh_PreSelEdgeRing *psel) { - MEM_SAFE_FREE(psel->edges); - psel->edges_len = 0; + MEM_SAFE_FREE(psel->edges); + psel->edges_len = 0; - MEM_SAFE_FREE(psel->verts); - psel->verts_len = 0; + MEM_SAFE_FREE(psel->verts); + psel->verts_len = 0; } -void EDBM_preselect_edgering_draw( - struct EditMesh_PreSelEdgeRing *psel, const float matrix[4][4]) +void EDBM_preselect_edgering_draw(struct EditMesh_PreSelEdgeRing *psel, const float matrix[4][4]) { - if ((psel->edges_len == 0) && (psel->verts_len == 0)) { - return; - } + if ((psel->edges_len == 0) && (psel->verts_len == 0)) { + return; + } - GPU_depth_test(false); + GPU_depth_test(false); - GPU_matrix_push(); - GPU_matrix_mul(matrix); + GPU_matrix_push(); + GPU_matrix_mul(matrix); - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformThemeColor3(TH_GIZMO_PRIMARY); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColor3(TH_GIZMO_PRIMARY); - if (psel->edges_len > 0) { - immBegin(GPU_PRIM_LINES, psel->edges_len * 2); + if (psel->edges_len > 0) { + immBegin(GPU_PRIM_LINES, psel->edges_len * 2); - for (int i = 0; i < psel->edges_len; i++) { - immVertex3fv(pos, psel->edges[i][0]); - immVertex3fv(pos, psel->edges[i][1]); - } + for (int i = 0; i < psel->edges_len; i++) { + immVertex3fv(pos, psel->edges[i][0]); + immVertex3fv(pos, psel->edges[i][1]); + } - immEnd(); - } + immEnd(); + } - if (psel->verts_len > 0) { - GPU_point_size(3.0f); + if (psel->verts_len > 0) { + GPU_point_size(3.0f); - immBegin(GPU_PRIM_POINTS, psel->verts_len); + immBegin(GPU_PRIM_POINTS, psel->verts_len); - for (int i = 0; i < psel->verts_len; i++) { - immVertex3fv(pos, psel->verts[i]); - } + for (int i = 0; i < psel->verts_len; i++) { + immVertex3fv(pos, psel->verts[i]); + } - immEnd(); - } + immEnd(); + } - immUnbindProgram(); + immUnbindProgram(); - GPU_matrix_pop(); + GPU_matrix_pop(); - /* Reset default */ - GPU_depth_test(true); + /* Reset default */ + GPU_depth_test(true); } static void view3d_preselect_mesh_edgering_update_verts_from_edge( - struct EditMesh_PreSelEdgeRing *psel, - BMesh *UNUSED(bm), BMEdge *eed_start, int previewlines, const float (*coords)[3]) + struct EditMesh_PreSelEdgeRing *psel, + BMesh *UNUSED(bm), + BMEdge *eed_start, + int previewlines, + const float (*coords)[3]) { - float v_cos[2][3]; - float (*verts)[3]; - int i, tot = 0; + float v_cos[2][3]; + float(*verts)[3]; + int i, tot = 0; - verts = MEM_mallocN(sizeof(*psel->verts) * previewlines, __func__); + verts = MEM_mallocN(sizeof(*psel->verts) * previewlines, __func__); - edgering_vcos_get_pair(&eed_start->v1, v_cos, coords); + edgering_vcos_get_pair(&eed_start->v1, v_cos, coords); - for (i = 1; i <= previewlines; i++) { - const float fac = (i / ((float)previewlines + 1)); - interp_v3_v3v3(verts[tot], v_cos[0], v_cos[1], fac); - tot++; - } + for (i = 1; i <= previewlines; i++) { + const float fac = (i / ((float)previewlines + 1)); + interp_v3_v3v3(verts[tot], v_cos[0], v_cos[1], fac); + tot++; + } - psel->verts = verts; - psel->verts_len = previewlines; + psel->verts = verts; + psel->verts_len = previewlines; } static void view3d_preselect_mesh_edgering_update_edges_from_edge( - struct EditMesh_PreSelEdgeRing *psel, - BMesh *bm, BMEdge *eed_start, int previewlines, const float (*coords)[3]) + struct EditMesh_PreSelEdgeRing *psel, + BMesh *bm, + BMEdge *eed_start, + int previewlines, + const float (*coords)[3]) { - BMWalker walker; - BMEdge *eed, *eed_last; - BMVert *v[2][2] = {{NULL}}, *eve_last; - float (*edges)[2][3] = NULL; - BLI_Stack *edge_stack; - - int i, tot = 0; - - BMW_init(&walker, bm, BMW_EDGERING, - BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - - edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__); - - eed_last = NULL; - for (eed = eed_last = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) { - BLI_stack_push(edge_stack, &eed); - } - BMW_end(&walker); - - - eed_start = *(BMEdge **)BLI_stack_peek(edge_stack); - - edges = MEM_mallocN( - (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines, __func__); - - eve_last = NULL; - eed_last = NULL; - - while (!BLI_stack_is_empty(edge_stack)) { - BLI_stack_pop(edge_stack, &eed); - - if (eed_last) { - if (eve_last) { - v[1][0] = v[0][0]; - v[1][1] = v[0][1]; - } - else { - v[1][0] = eed_last->v1; - v[1][1] = eed_last->v2; - eve_last = eed_last->v1; - } - - edgering_find_order(eed_last, eed, eve_last, v); - eve_last = v[0][0]; - - for (i = 1; i <= previewlines; i++) { - const float fac = (i / ((float)previewlines + 1)); - float v_cos[2][2][3]; - - edgering_vcos_get(v, v_cos, coords); - - interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac); - interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac); - tot++; - } - } - eed_last = eed; - } - - if ((eed_last != eed_start) && + BMWalker walker; + BMEdge *eed, *eed_last; + BMVert *v[2][2] = {{NULL}}, *eve_last; + float(*edges)[2][3] = NULL; + BLI_Stack *edge_stack; + + int i, tot = 0; + + BMW_init(&walker, + bm, + BMW_EDGERING, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__); + + eed_last = NULL; + for (eed = eed_last = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) { + BLI_stack_push(edge_stack, &eed); + } + BMW_end(&walker); + + eed_start = *(BMEdge **)BLI_stack_peek(edge_stack); + + edges = MEM_mallocN((sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * + previewlines, + __func__); + + eve_last = NULL; + eed_last = NULL; + + while (!BLI_stack_is_empty(edge_stack)) { + BLI_stack_pop(edge_stack, &eed); + + if (eed_last) { + if (eve_last) { + v[1][0] = v[0][0]; + v[1][1] = v[0][1]; + } + else { + v[1][0] = eed_last->v1; + v[1][1] = eed_last->v2; + eve_last = eed_last->v1; + } + + edgering_find_order(eed_last, eed, eve_last, v); + eve_last = v[0][0]; + + for (i = 1; i <= previewlines; i++) { + const float fac = (i / ((float)previewlines + 1)); + float v_cos[2][2][3]; + + edgering_vcos_get(v, v_cos, coords); + + interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac); + interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac); + tot++; + } + } + eed_last = eed; + } + + if ((eed_last != eed_start) && #ifdef BMW_EDGERING_NGON - BM_edge_share_face_check(eed_last, eed_start) + BM_edge_share_face_check(eed_last, eed_start) #else - BM_edge_share_quad_check(eed_last, eed_start) + BM_edge_share_quad_check(eed_last, eed_start) #endif - ) - { - v[1][0] = v[0][0]; - v[1][1] = v[0][1]; + ) { + v[1][0] = v[0][0]; + v[1][1] = v[0][1]; - edgering_find_order(eed_last, eed_start, eve_last, v); + edgering_find_order(eed_last, eed_start, eve_last, v); - for (i = 1; i <= previewlines; i++) { - const float fac = (i / ((float)previewlines + 1)); - float v_cos[2][2][3]; + for (i = 1; i <= previewlines; i++) { + const float fac = (i / ((float)previewlines + 1)); + float v_cos[2][2][3]; - if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) { - continue; - } + if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) { + continue; + } - edgering_vcos_get(v, v_cos, coords); + edgering_vcos_get(v, v_cos, coords); - interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac); - interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac); - tot++; - } - } + interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac); + interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac); + tot++; + } + } - BLI_stack_free(edge_stack); + BLI_stack_free(edge_stack); - psel->edges = edges; - psel->edges_len = tot; + psel->edges = edges; + psel->edges_len = tot; } -void EDBM_preselect_edgering_update_from_edge( - struct EditMesh_PreSelEdgeRing *psel, - BMesh *bm, BMEdge *eed_start, int previewlines, const float (*coords)[3]) +void EDBM_preselect_edgering_update_from_edge(struct EditMesh_PreSelEdgeRing *psel, + BMesh *bm, + BMEdge *eed_start, + int previewlines, + const float (*coords)[3]) { - EDBM_preselect_edgering_clear(psel); - - if (coords) { - BM_mesh_elem_index_ensure(bm, BM_VERT); - } - - if (BM_edge_is_wire(eed_start)) { - view3d_preselect_mesh_edgering_update_verts_from_edge(psel, bm, eed_start, previewlines, coords); - } - else { - view3d_preselect_mesh_edgering_update_edges_from_edge(psel, bm, eed_start, previewlines, coords); - } - + EDBM_preselect_edgering_clear(psel); + + if (coords) { + BM_mesh_elem_index_ensure(bm, BM_VERT); + } + + if (BM_edge_is_wire(eed_start)) { + view3d_preselect_mesh_edgering_update_verts_from_edge( + psel, bm, eed_start, previewlines, coords); + } + else { + view3d_preselect_mesh_edgering_update_edges_from_edge( + psel, bm, eed_start, previewlines, coords); + } } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c index 827d47a265c..a3e684a5493 100644 --- a/source/blender/editors/mesh/editmesh_preselect_elem.c +++ b/source/blender/editors/mesh/editmesh_preselect_elem.c @@ -47,166 +47,166 @@ static void vcos_get(BMVert *v, float r_co[3], const float (*coords)[3]) { - if (coords) { - copy_v3_v3(r_co, coords[BM_elem_index_get(v)]); - } - else { - copy_v3_v3(r_co, v->co); - } + if (coords) { + copy_v3_v3(r_co, coords[BM_elem_index_get(v)]); + } + else { + copy_v3_v3(r_co, v->co); + } } static void vcos_get_pair(BMVert *v[2], float r_cos[2][3], const float (*coords)[3]) { - if (coords) { - for (int j = 0; j < 2; j++) { - copy_v3_v3(r_cos[j], coords[BM_elem_index_get(v[j])]); - } - } - else { - for (int j = 0; j < 2; j++) { - copy_v3_v3(r_cos[j], v[j]->co); - } - } + if (coords) { + for (int j = 0; j < 2; j++) { + copy_v3_v3(r_cos[j], coords[BM_elem_index_get(v[j])]); + } + } + else { + for (int j = 0; j < 2; j++) { + copy_v3_v3(r_cos[j], v[j]->co); + } + } } struct EditMesh_PreSelElem { - float (*edges)[2][3]; - int edges_len; + float (*edges)[2][3]; + int edges_len; - float (*verts)[3]; - int verts_len; + float (*verts)[3]; + int verts_len; }; struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void) { - struct EditMesh_PreSelElem *psel = MEM_callocN(sizeof(*psel), __func__); - return psel; + struct EditMesh_PreSelElem *psel = MEM_callocN(sizeof(*psel), __func__); + return psel; } -void EDBM_preselect_elem_destroy( - struct EditMesh_PreSelElem *psel) +void EDBM_preselect_elem_destroy(struct EditMesh_PreSelElem *psel) { - EDBM_preselect_elem_clear(psel); - MEM_freeN(psel); + EDBM_preselect_elem_clear(psel); + MEM_freeN(psel); } -void EDBM_preselect_elem_clear( - struct EditMesh_PreSelElem *psel) +void EDBM_preselect_elem_clear(struct EditMesh_PreSelElem *psel) { - MEM_SAFE_FREE(psel->edges); - psel->edges_len = 0; + MEM_SAFE_FREE(psel->edges); + psel->edges_len = 0; - MEM_SAFE_FREE(psel->verts); - psel->verts_len = 0; + MEM_SAFE_FREE(psel->verts); + psel->verts_len = 0; } -void EDBM_preselect_elem_draw( - struct EditMesh_PreSelElem *psel, const float matrix[4][4]) +void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matrix[4][4]) { - if ((psel->edges_len == 0) && (psel->verts_len == 0)) { - return; - } + if ((psel->edges_len == 0) && (psel->verts_len == 0)) { + return; + } - GPU_depth_test(false); + GPU_depth_test(false); - GPU_matrix_push(); - GPU_matrix_mul(matrix); + GPU_matrix_push(); + GPU_matrix_mul(matrix); - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + 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); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ub(255, 0, 255); - if (psel->edges_len > 0) { - immBegin(GPU_PRIM_LINES, psel->edges_len * 2); + if (psel->edges_len > 0) { + immBegin(GPU_PRIM_LINES, psel->edges_len * 2); - for (int i = 0; i < psel->edges_len; i++) { - immVertex3fv(pos, psel->edges[i][0]); - immVertex3fv(pos, psel->edges[i][1]); - } + for (int i = 0; i < psel->edges_len; i++) { + immVertex3fv(pos, psel->edges[i][0]); + immVertex3fv(pos, psel->edges[i][1]); + } - immEnd(); - } + immEnd(); + } - if (psel->verts_len > 0) { - GPU_point_size(3.0f); + if (psel->verts_len > 0) { + GPU_point_size(3.0f); - immBegin(GPU_PRIM_POINTS, psel->verts_len); + immBegin(GPU_PRIM_POINTS, psel->verts_len); - for (int i = 0; i < psel->verts_len; i++) { - immVertex3fv(pos, psel->verts[i]); - } + for (int i = 0; i < psel->verts_len; i++) { + immVertex3fv(pos, psel->verts[i]); + } - immEnd(); - } + immEnd(); + } - immUnbindProgram(); + immUnbindProgram(); - GPU_matrix_pop(); + GPU_matrix_pop(); - /* Reset default */ - GPU_depth_test(true); + /* Reset default */ + GPU_depth_test(true); } -static void view3d_preselect_mesh_elem_update_from_vert( - struct EditMesh_PreSelElem *psel, - BMesh *UNUSED(bm), BMVert *eve, const float (*coords)[3]) +static void view3d_preselect_mesh_elem_update_from_vert(struct EditMesh_PreSelElem *psel, + BMesh *UNUSED(bm), + BMVert *eve, + const float (*coords)[3]) { - float (*verts)[3] = MEM_mallocN(sizeof(*psel->verts), __func__); - vcos_get(eve, verts[0], coords); - psel->verts = verts; - psel->verts_len = 1; + float(*verts)[3] = MEM_mallocN(sizeof(*psel->verts), __func__); + vcos_get(eve, verts[0], coords); + psel->verts = verts; + psel->verts_len = 1; } -static void view3d_preselect_mesh_elem_update_from_edge( - struct EditMesh_PreSelElem *psel, - BMesh *UNUSED(bm), BMEdge *eed, const float (*coords)[3]) +static void view3d_preselect_mesh_elem_update_from_edge(struct EditMesh_PreSelElem *psel, + BMesh *UNUSED(bm), + BMEdge *eed, + const float (*coords)[3]) { - float (*edges)[2][3] = MEM_mallocN(sizeof(*psel->edges), __func__); - vcos_get_pair(&eed->v1, edges[0], coords); - psel->edges = edges; - psel->edges_len = 1; + float(*edges)[2][3] = MEM_mallocN(sizeof(*psel->edges), __func__); + vcos_get_pair(&eed->v1, edges[0], coords); + psel->edges = edges; + psel->edges_len = 1; } -static void view3d_preselect_mesh_elem_update_from_face( - struct EditMesh_PreSelElem *psel, - BMesh *UNUSED(bm), BMFace *efa, const float (*coords)[3]) +static void view3d_preselect_mesh_elem_update_from_face(struct EditMesh_PreSelElem *psel, + BMesh *UNUSED(bm), + BMFace *efa, + const float (*coords)[3]) { - float (*edges)[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, edges[i++], coords); - } while ((l_iter = l_iter->next) != l_first); - psel->edges = edges; - psel->edges_len = efa->len; + float(*edges)[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, edges[i++], coords); + } while ((l_iter = l_iter->next) != l_first); + psel->edges = edges; + psel->edges_len = efa->len; } -void EDBM_preselect_elem_update_from_single( - struct EditMesh_PreSelElem *psel, - BMesh *bm, BMElem *ele, - const float (*coords)[3]) +void EDBM_preselect_elem_update_from_single(struct EditMesh_PreSelElem *psel, + BMesh *bm, + BMElem *ele, + const float (*coords)[3]) { - EDBM_preselect_elem_clear(psel); - - if (coords) { - BM_mesh_elem_index_ensure(bm, BM_VERT); - } - - switch (ele->head.htype) { - case BM_VERT: - view3d_preselect_mesh_elem_update_from_vert(psel, bm, (BMVert *)ele, coords); - break; - case BM_EDGE: - view3d_preselect_mesh_elem_update_from_edge(psel, bm, (BMEdge *)ele, coords); - break; - case BM_FACE: - view3d_preselect_mesh_elem_update_from_face(psel, bm, (BMFace *)ele, coords); - break; - default: - BLI_assert(0); - } + EDBM_preselect_elem_clear(psel); + + if (coords) { + BM_mesh_elem_index_ensure(bm, BM_VERT); + } + + switch (ele->head.htype) { + case BM_VERT: + view3d_preselect_mesh_elem_update_from_vert(psel, bm, (BMVert *)ele, coords); + break; + case BM_EDGE: + view3d_preselect_mesh_elem_update_from_edge(psel, bm, (BMEdge *)ele, coords); + break; + case BM_FACE: + view3d_preselect_mesh_elem_update_from_face(psel, bm, (BMFace *)ele, coords); + break; + default: + BLI_assert(0); + } } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 2117c2bb689..42521d04008 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -46,7 +46,7 @@ #include "bmesh.h" #include "bmesh_tools.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /** * helper to find edge for edge_rip, @@ -56,30 +56,32 @@ * point and would result in the same distance. */ #define INSET_DEFAULT 0.00001f -static float edbm_rip_edgedist_squared( - ARegion *ar, float mat[4][4], - const float co1[3], const float co2[3], const float mvalf[2], - const float inset) +static float edbm_rip_edgedist_squared(ARegion *ar, + float mat[4][4], + const float co1[3], + const float co2[3], + const float mvalf[2], + const float inset) { - float vec1[2], vec2[2], dist_sq; + float vec1[2], vec2[2], dist_sq; - ED_view3d_project_float_v2_m4(ar, co1, vec1, mat); - ED_view3d_project_float_v2_m4(ar, co2, vec2, mat); + ED_view3d_project_float_v2_m4(ar, co1, vec1, mat); + ED_view3d_project_float_v2_m4(ar, co2, vec2, mat); - if (inset != 0.0f) { - const float dist_2d = len_v2v2(vec1, vec2); - if (dist_2d > FLT_EPSILON) { - const float dist = inset / dist_2d; - BLI_assert(isfinite(dist)); - interp_v2_v2v2(vec1, vec1, vec2, dist); - interp_v2_v2v2(vec2, vec2, vec1, dist); - } - } + if (inset != 0.0f) { + const float dist_2d = len_v2v2(vec1, vec2); + if (dist_2d > FLT_EPSILON) { + const float dist = inset / dist_2d; + BLI_assert(isfinite(dist)); + interp_v2_v2v2(vec1, vec1, vec2, dist); + interp_v2_v2v2(vec2, vec2, vec1, dist); + } + } - dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2); - BLI_assert(isfinite(dist_sq)); + dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2); + BLI_assert(isfinite(dist_sq)); - return dist_sq; + return dist_sq; } #if 0 @@ -87,83 +89,78 @@ static float edbm_rip_linedist( ARegion *ar, float mat[4][4], const float co1[3], const float co2[3], const float mvalf[2]) { - float vec1[2], vec2[2]; + float vec1[2], vec2[2]; - ED_view3d_project_float_v2_m4(ar, co1, vec1, mat); - ED_view3d_project_float_v2_m4(ar, co2, vec2, mat); + ED_view3d_project_float_v2_m4(ar, co1, vec1, mat); + ED_view3d_project_float_v2_m4(ar, co2, vec2, mat); - return dist_to_line_v2(mvalf, vec1, vec2); + return dist_to_line_v2(mvalf, vec1, vec2); } #endif /* calculaters a point along the loop tangent which can be used to measure against edges */ static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3]) { - BM_loop_calc_face_tangent(l, l_mid_co); + BM_loop_calc_face_tangent(l, l_mid_co); - /* scale to average of surrounding edge size, only needs to be approx, but should - * be roughly equivalent to the check below which uses the middle of the edge. */ - mul_v3_fl(l_mid_co, (BM_edge_calc_length(l->e) + BM_edge_calc_length(l->prev->e)) / 2.0f); + /* scale to average of surrounding edge size, only needs to be approx, but should + * be roughly equivalent to the check below which uses the middle of the edge. */ + mul_v3_fl(l_mid_co, (BM_edge_calc_length(l->e) + BM_edge_calc_length(l->prev->e)) / 2.0f); - add_v3_v3(l_mid_co, l->v->co); + add_v3_v3(l_mid_co, l->v->co); } - static float edbm_rip_edge_side_measure( - BMEdge *e, BMLoop *e_l, - ARegion *ar, - float projectMat[4][4], const float fmval[2]) + BMEdge *e, BMLoop *e_l, ARegion *ar, float projectMat[4][4], const float fmval[2]) { - float cent[3] = {0, 0, 0}, mid[3]; + float cent[3] = {0, 0, 0}, mid[3]; - float vec[2]; - float fmval_tweak[2]; - float e_v1_co[2], e_v2_co[2]; - float score; + float vec[2]; + float fmval_tweak[2]; + float e_v1_co[2], e_v2_co[2]; + float score; - BMVert *v1_other; - BMVert *v2_other; + BMVert *v1_other; + BMVert *v2_other; - BLI_assert(BM_vert_in_edge(e, e_l->v)); + BLI_assert(BM_vert_in_edge(e, e_l->v)); - /* method for calculating distance: - * - * for each edge: calculate face center, then made a vector - * from edge midpoint to face center. offset edge midpoint - * by a small amount along this vector. */ + /* method for calculating distance: + * + * for each edge: calculate face center, then made a vector + * from edge midpoint to face center. offset edge midpoint + * by a small amount along this vector. */ - /* rather then the face center, get the middle of - * both edge verts connected to this one */ - v1_other = BM_face_other_vert_loop(e_l->f, e->v2, e->v1)->v; - v2_other = BM_face_other_vert_loop(e_l->f, e->v1, e->v2)->v; - mid_v3_v3v3(cent, v1_other->co, v2_other->co); - mid_v3_v3v3(mid, e->v1->co, e->v2->co); + /* rather then the face center, get the middle of + * both edge verts connected to this one */ + v1_other = BM_face_other_vert_loop(e_l->f, e->v2, e->v1)->v; + v2_other = BM_face_other_vert_loop(e_l->f, e->v1, e->v2)->v; + mid_v3_v3v3(cent, v1_other->co, v2_other->co); + mid_v3_v3v3(mid, e->v1->co, e->v2->co); - ED_view3d_project_float_v2_m4(ar, cent, cent, projectMat); - ED_view3d_project_float_v2_m4(ar, mid, mid, projectMat); + ED_view3d_project_float_v2_m4(ar, cent, cent, projectMat); + ED_view3d_project_float_v2_m4(ar, mid, mid, projectMat); - ED_view3d_project_float_v2_m4(ar, e->v1->co, e_v1_co, projectMat); - ED_view3d_project_float_v2_m4(ar, e->v2->co, e_v2_co, projectMat); + ED_view3d_project_float_v2_m4(ar, e->v1->co, e_v1_co, projectMat); + ED_view3d_project_float_v2_m4(ar, e->v2->co, e_v2_co, projectMat); - sub_v2_v2v2(vec, cent, mid); - normalize_v2_length(vec, 0.01f); + sub_v2_v2v2(vec, cent, mid); + normalize_v2_length(vec, 0.01f); - /* rather then adding to both verts, subtract from the mouse */ - sub_v2_v2v2(fmval_tweak, fmval, vec); + /* rather then adding to both verts, subtract from the mouse */ + sub_v2_v2v2(fmval_tweak, fmval, vec); - score = len_v2v2(e_v1_co, e_v2_co); + score = len_v2v2(e_v1_co, e_v2_co); - if (dist_squared_to_line_segment_v2(fmval_tweak, e_v1_co, e_v2_co) > - dist_squared_to_line_segment_v2(fmval, e_v1_co, e_v2_co)) - { - return score; - } - else { - return -score; - } + if (dist_squared_to_line_segment_v2(fmval_tweak, e_v1_co, e_v2_co) > + dist_squared_to_line_segment_v2(fmval, e_v1_co, e_v2_co)) { + return score; + } + else { + return -score; + } } - /* - Advanced selection handling 'ripsel' functions ----- */ /** @@ -195,195 +192,189 @@ static float edbm_rip_edge_side_measure( * - campbell. */ - -#define IS_VISIT_POSSIBLE(e) (BM_edge_is_manifold(e) && BM_elem_flag_test(e, BM_ELEM_TAG)) +#define IS_VISIT_POSSIBLE(e) (BM_edge_is_manifold(e) && BM_elem_flag_test(e, BM_ELEM_TAG)) #define IS_VISIT_DONE(e) ((e)->l && (BM_elem_index_get((e)->l) != INVALID_UID)) #define INVALID_UID INT_MIN /* mark, assign uid and step */ static BMEdge *edbm_ripsel_edge_mark_step(BMVert *v, const int uid) { - BMIter iter; - BMEdge *e; - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) { - BMLoop *l_a, *l_b; - - BM_edge_loop_pair(e, &l_a, &l_b); /* no need to check, we know this will be true */ - - /* so (IS_VISIT_DONE == true) */ - BM_elem_index_set(l_a, uid); /* set_dirty */ - BM_elem_index_set(l_b, uid); /* set_dirty */ - - return e; - } - } - return NULL; + BMIter iter; + BMEdge *e; + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) { + BMLoop *l_a, *l_b; + + BM_edge_loop_pair(e, &l_a, &l_b); /* no need to check, we know this will be true */ + + /* so (IS_VISIT_DONE == true) */ + BM_elem_index_set(l_a, uid); /* set_dirty */ + BM_elem_index_set(l_b, uid); /* set_dirty */ + + return e; + } + } + return NULL; } typedef struct EdgeLoopPair { - BMLoop *l_a; - BMLoop *l_b; + BMLoop *l_a; + BMLoop *l_b; } EdgeLoopPair; static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm) { - BMIter fiter; - BMIter liter; - - BMFace *f; - BMLoop *l; - - int uid_start; - int uid_end; - int uid = bm->totedge; /* can start anywhere */ - - EdgeLoopPair *eloop_pairs = NULL; - BLI_array_declare(eloop_pairs); - EdgeLoopPair *lp; - - /* initialize loops with dummy invalid index values */ - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BM_elem_index_set(l, INVALID_UID); /* set_dirty */ - } - } - bm->elem_index_dirty |= BM_LOOP; - - /* set contiguous loops ordered 'uid' values for walking after split */ - while (true) { - int tot = 0; - BMIter eiter; - BMEdge *e_step; - BMVert *v_step; - BMEdge *e; - BMEdge *e_first; - BMEdge *e_last; - - e_first = NULL; - BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) { - e_first = e; - break; - } - } - - if (e_first == NULL) { - break; - } - - /* initialize */ - e_first = e; - v_step = e_first->v1; - e_step = NULL; /* quiet warning, will never remain this value */ - - uid_start = uid; - while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) { - v_step = BM_edge_other_vert((e_step = e), v_step); - uid++; /* only different line */ - tot++; - } - - /* this edges loops have the highest uid's, store this to walk down later */ - e_last = e_step; - - /* always store the highest 'uid' edge for the stride */ - uid_end = uid - 1; - uid = uid_start - 1; - - /* initialize */ - v_step = e_first->v1; - - while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) { - v_step = BM_edge_other_vert((e_step = e), v_step); - uid--; /* only different line */ - tot++; - } - - /* stride far enough not to _ever_ overlap range */ - uid_start = uid; - uid = uid_end + bm->totedge; - - lp = BLI_array_append_ret(eloop_pairs); - /* no need to check, we know this will be true */ - BM_edge_loop_pair(e_last, &lp->l_a, &lp->l_b); - - - BLI_assert(tot == uid_end - uid_start); + BMIter fiter; + BMIter liter; + + BMFace *f; + BMLoop *l; + + int uid_start; + int uid_end; + int uid = bm->totedge; /* can start anywhere */ + + EdgeLoopPair *eloop_pairs = NULL; + BLI_array_declare(eloop_pairs); + EdgeLoopPair *lp; + + /* initialize loops with dummy invalid index values */ + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BM_elem_index_set(l, INVALID_UID); /* set_dirty */ + } + } + bm->elem_index_dirty |= BM_LOOP; + + /* set contiguous loops ordered 'uid' values for walking after split */ + while (true) { + int tot = 0; + BMIter eiter; + BMEdge *e_step; + BMVert *v_step; + BMEdge *e; + BMEdge *e_first; + BMEdge *e_last; + + e_first = NULL; + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) { + e_first = e; + break; + } + } + + if (e_first == NULL) { + break; + } + + /* initialize */ + e_first = e; + v_step = e_first->v1; + e_step = NULL; /* quiet warning, will never remain this value */ + + uid_start = uid; + while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) { + v_step = BM_edge_other_vert((e_step = e), v_step); + uid++; /* only different line */ + tot++; + } + + /* this edges loops have the highest uid's, store this to walk down later */ + e_last = e_step; + + /* always store the highest 'uid' edge for the stride */ + uid_end = uid - 1; + uid = uid_start - 1; + + /* initialize */ + v_step = e_first->v1; + + while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) { + v_step = BM_edge_other_vert((e_step = e), v_step); + uid--; /* only different line */ + tot++; + } + + /* stride far enough not to _ever_ overlap range */ + uid_start = uid; + uid = uid_end + bm->totedge; + + lp = BLI_array_append_ret(eloop_pairs); + /* no need to check, we know this will be true */ + BM_edge_loop_pair(e_last, &lp->l_a, &lp->l_b); + + BLI_assert(tot == uid_end - uid_start); #if 0 - printf("%s: found contiguous edge loop of (%d)\n", __func__, uid_end - uid_start); + printf("%s: found contiguous edge loop of (%d)\n", __func__, uid_end - uid_start); #endif + } - } - - /* null terminate */ - lp = BLI_array_append_ret(eloop_pairs); - lp->l_a = lp->l_b = NULL; + /* null terminate */ + lp = BLI_array_append_ret(eloop_pairs); + lp->l_a = lp->l_b = NULL; - return eloop_pairs; + return eloop_pairs; } - /* - De-Select the worst rip-edge side -------------------------------- */ - static BMEdge *edbm_ripsel_edge_uid_step(BMEdge *e_orig, BMVert **v_prev) { - BMIter eiter; - BMEdge *e; - BMVert *v = BM_edge_other_vert(e_orig, *v_prev); - const int uid_cmp = BM_elem_index_get(e_orig->l) - 1; - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BM_elem_index_get(e->l) == uid_cmp) { - *v_prev = v; - return e; - } - } - return NULL; + BMIter eiter; + BMEdge *e; + BMVert *v = BM_edge_other_vert(e_orig, *v_prev); + const int uid_cmp = BM_elem_index_get(e_orig->l) - 1; + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_elem_index_get(e->l) == uid_cmp) { + *v_prev = v; + return e; + } + } + return NULL; } static BMVert *edbm_ripsel_edloop_pair_start_vert(BMEdge *e) { - /* try step in a direction, if it fails we know do go the other way */ - BMVert *v_test = e->v1; - return (edbm_ripsel_edge_uid_step(e, &v_test)) ? e->v1 : e->v2; + /* try step in a direction, if it fails we know do go the other way */ + BMVert *v_test = e->v1; + return (edbm_ripsel_edge_uid_step(e, &v_test)) ? e->v1 : e->v2; } -static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs, - ARegion *ar, float projectMat[4][4], float fmval[2]) +static void edbm_ripsel_deselect_helper( + BMesh *bm, EdgeLoopPair *eloop_pairs, ARegion *ar, float projectMat[4][4], float fmval[2]) { - EdgeLoopPair *lp; - - for (lp = eloop_pairs; lp->l_a; lp++) { - BMEdge *e; - BMVert *v_prev; - - float score_a = 0.0f; - float score_b = 0.0f; - - e = lp->l_a->e; - v_prev = edbm_ripsel_edloop_pair_start_vert(e); - for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { - score_a += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval); - } - e = lp->l_b->e; - v_prev = edbm_ripsel_edloop_pair_start_vert(e); - for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { - score_b += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval); - } - - e = (score_a > score_b) ? lp->l_a->e : lp->l_b->e; - v_prev = edbm_ripsel_edloop_pair_start_vert(e); - for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { - BM_edge_select_set(bm, e, false); - } - } + EdgeLoopPair *lp; + + for (lp = eloop_pairs; lp->l_a; lp++) { + BMEdge *e; + BMVert *v_prev; + + float score_a = 0.0f; + float score_b = 0.0f; + + e = lp->l_a->e; + v_prev = edbm_ripsel_edloop_pair_start_vert(e); + for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { + score_a += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval); + } + e = lp->l_b->e; + v_prev = edbm_ripsel_edloop_pair_start_vert(e); + for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { + score_b += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval); + } + + e = (score_a > score_b) ? lp->l_a->e : lp->l_b->e; + v_prev = edbm_ripsel_edloop_pair_start_vert(e); + for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { + BM_edge_select_set(bm, e, false); + } + } } /* --- end 'ripsel' selection handling code --- */ - /* --- face-fill code --- */ /** * return an un-ordered array of loop pairs @@ -396,120 +387,121 @@ static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs, */ typedef struct UnorderedLoopPair { - BMLoop *l_pair[2]; - char flag; + BMLoop *l_pair[2]; + char flag; } UnorderedLoopPair; enum { - ULP_FLIP_0 = (1 << 0), - ULP_FLIP_1 = (1 << 1), + ULP_FLIP_0 = (1 << 0), + ULP_FLIP_1 = (1 << 1), }; static UnorderedLoopPair *edbm_tagged_loop_pairs_to_fill(BMesh *bm) { - BMIter iter; - BMEdge *e; - - unsigned int total_tag = 0; - /* count tags, could be pre-calculated */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - total_tag++; - } - } - - if (total_tag) { - UnorderedLoopPair *uloop_pairs = MEM_mallocN(total_tag * sizeof(UnorderedLoopPair), __func__); - UnorderedLoopPair *ulp = uloop_pairs; - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BMLoop *l1, *l2; - if (BM_edge_loop_pair(e, &l1, &l2)) { - BMVert *v_cmp = l1->e->v1; - ulp->flag = (((l1->v != v_cmp) ? ULP_FLIP_0 : 0) | - ((l2->v == v_cmp) ? ULP_FLIP_1 : 0)); - } - else { - ulp->flag = 0; - } - ulp->l_pair[0] = l1; - ulp->l_pair[1] = l2; - - ulp++; - } - } - - return uloop_pairs; - } - else { - return NULL; - } + BMIter iter; + BMEdge *e; + + unsigned int total_tag = 0; + /* count tags, could be pre-calculated */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + total_tag++; + } + } + + if (total_tag) { + UnorderedLoopPair *uloop_pairs = MEM_mallocN(total_tag * sizeof(UnorderedLoopPair), __func__); + UnorderedLoopPair *ulp = uloop_pairs; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BMLoop *l1, *l2; + if (BM_edge_loop_pair(e, &l1, &l2)) { + BMVert *v_cmp = l1->e->v1; + ulp->flag = (((l1->v != v_cmp) ? ULP_FLIP_0 : 0) | ((l2->v == v_cmp) ? ULP_FLIP_1 : 0)); + } + else { + ulp->flag = 0; + } + ulp->l_pair[0] = l1; + ulp->l_pair[1] = l2; + + ulp++; + } + } + + return uloop_pairs; + } + else { + return NULL; + } } static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *uloop_pairs) { - UnorderedLoopPair *ulp; - unsigned int total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair); - unsigned int i; - - for (i = 0, ulp = uloop_pairs; i < total_tag; i++, ulp++) { - if ((ulp->l_pair[0] && ulp->l_pair[1]) && - (ulp->l_pair[0]->e != ulp->l_pair[1]->e)) - { - /* time has come to make a face! */ - BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e); - BMFace *f, *f_example = ulp->l_pair[0]->f; - BMLoop *l_iter; - BMVert *f_verts[4]; - - if (v_shared == NULL) { - /* quad */ - f_verts[0] = ulp->l_pair[0]->e->v1; - f_verts[1] = ulp->l_pair[1]->e->v1; - f_verts[2] = ulp->l_pair[1]->e->v2; - f_verts[3] = ulp->l_pair[0]->e->v2; - - if (ulp->flag & ULP_FLIP_0) { - SWAP(BMVert *, f_verts[0], f_verts[3]); - } - if (ulp->flag & ULP_FLIP_1) { - SWAP(BMVert *, f_verts[1], f_verts[2]); - } - } - else { - /* tri */ - f_verts[0] = v_shared; - f_verts[1] = BM_edge_other_vert(ulp->l_pair[0]->e, v_shared); - f_verts[2] = BM_edge_other_vert(ulp->l_pair[1]->e, v_shared); - f_verts[3] = NULL; - - /* don't use the flip flags */ - if (v_shared == ulp->l_pair[0]->v) { - SWAP(BMVert *, f_verts[0], f_verts[1]); - } - } - - /* face should never exist */ - BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3)); - - f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true); - - l_iter = BM_FACE_FIRST_LOOP(f); - - if (f_verts[3]) { - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); - } - else { - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); - } - - } - } + UnorderedLoopPair *ulp; + unsigned int total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair); + unsigned int i; + + for (i = 0, ulp = uloop_pairs; i < total_tag; i++, ulp++) { + if ((ulp->l_pair[0] && ulp->l_pair[1]) && (ulp->l_pair[0]->e != ulp->l_pair[1]->e)) { + /* time has come to make a face! */ + BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e); + BMFace *f, *f_example = ulp->l_pair[0]->f; + BMLoop *l_iter; + BMVert *f_verts[4]; + + if (v_shared == NULL) { + /* quad */ + f_verts[0] = ulp->l_pair[0]->e->v1; + f_verts[1] = ulp->l_pair[1]->e->v1; + f_verts[2] = ulp->l_pair[1]->e->v2; + f_verts[3] = ulp->l_pair[0]->e->v2; + + if (ulp->flag & ULP_FLIP_0) { + SWAP(BMVert *, f_verts[0], f_verts[3]); + } + if (ulp->flag & ULP_FLIP_1) { + SWAP(BMVert *, f_verts[1], f_verts[2]); + } + } + else { + /* tri */ + f_verts[0] = v_shared; + f_verts[1] = BM_edge_other_vert(ulp->l_pair[0]->e, v_shared); + f_verts[2] = BM_edge_other_vert(ulp->l_pair[1]->e, v_shared); + f_verts[3] = NULL; + + /* don't use the flip flags */ + if (v_shared == ulp->l_pair[0]->v) { + SWAP(BMVert *, f_verts[0], f_verts[1]); + } + } + + /* face should never exist */ + BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3)); + + f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true); + + l_iter = BM_FACE_FIRST_LOOP(f); + + if (f_verts[3]) { + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); + l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); + l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); + l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); + } + else { + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); + l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); + l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); + } + } + } } /* --- end 'face-fill' code --- */ @@ -519,357 +511,355 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u */ static int edbm_rip_invoke__vert(bContext *C, const wmEvent *event, Object *obedit, bool do_fill) { - UnorderedLoopPair *fill_uloop_pairs = NULL; - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter, liter; - BMLoop *l; - BMEdge *e_best; - BMVert *v; - const int totvert_orig = bm->totvert; - int i; - float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; - float dist_sq = FLT_MAX; - float d; - bool is_wire, is_manifold_region; - - BMEditSelection ese; - int totboundary_edge = 0; - - ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); - - /* find selected vert - same some time and check history first */ - if (BM_select_history_active_get(bm, &ese) && ese.htype == BM_VERT) { - v = (BMVert *)ese.ele; - } - else { - ese.ele = NULL; - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) - break; - } - } - - /* (v == NULL) should be impossible */ - if ((v == NULL) || (v->e == NULL)) { - return OPERATOR_CANCELLED; - } - - is_wire = BM_vert_is_wire(v); - is_manifold_region = BM_vert_is_manifold_region(v); - - e_best = NULL; - - { - BMEdge *e; - /* find closest edge to mouse cursor */ - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - /* consider wire as boundary for this purpose, - * otherwise we can't a face away from a wire edge */ - totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e)); - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - if ((is_manifold_region == false) || BM_edge_is_manifold(e)) { - d = edbm_rip_edgedist_squared(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT); - if ((e_best == NULL) || (d < dist_sq)) { - dist_sq = d; - e_best = e; - } - } - } - } - } - - if (e_best && e_best->l && (is_manifold_region == false)) { - /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */ - BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next; - BMVert *v_new; - - BLI_assert(l_sep->v == v); - v_new = BM_face_loop_separate_multi_isolated(bm, l_sep); - BLI_assert(BM_vert_find_first_loop(v)); - - BM_vert_select_set(bm, v, false); - BM_select_history_remove(bm, v); - - BM_vert_select_set(bm, v_new, true); - if (ese.ele) { - BM_select_history_store(bm, v_new); - } - - if (do_fill) { - BM_edge_create(bm, v, v_new, NULL, BM_CREATE_NOP); - } - - return OPERATOR_FINISHED; - } - - /* if we are ripping a single vertex from 3 faces, - * then measure the distance to the face corner as well as the edge */ - if (BM_vert_face_count_is_equal(v, 3) && - BM_vert_edge_count_is_equal(v, 3)) - { - BMEdge *e_all[3]; - BMLoop *l_all[3]; - int i1, i2; - - BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3); - BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3); - - /* not do a loop similar to the one above, but test against loops */ - for (i1 = 0; i1 < 3; i1++) { - /* consider wire as boundary for this purpose, - * otherwise we can't a face away from a wire edge */ - float l_mid_co[3]; - l = l_all[i1]; - edbm_calc_loop_co(l, l_mid_co); - d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT); - if ((e_best == NULL) || (d < dist_sq)) { - dist_sq = d; - - /* find the edge that is not in this loop */ - e_best = NULL; - for (i2 = 0; i2 < 3; i2++) { - if (!BM_edge_in_loop(e_all[i2], l)) { - e_best = e_all[i2]; - break; - } - } - BLI_assert(e_best != NULL); - } - } - } - - /* should we go ahead with edge rip or do we need to do special case, split off vertex?: - * split off vertex if... - * - we cant find an edge - this means we are ripping a faces vert that is connected to other - * geometry only at the vertex. - * - the boundary edge total is greater than 2, - * in this case edge split _can_ work but we get far nicer results if we use this special case. - * - there are only 2 edges but we are a wire vert. */ - if ((is_wire == false && totboundary_edge > 2) || - (is_wire == true && totboundary_edge > 1)) - { - BMVert **vout; - int vout_len; - - BM_vert_select_set(bm, v, false); - - bmesh_kernel_vert_separate(bm, v, &vout, &vout_len, true); - - if (vout_len < 2) { - MEM_freeN(vout); - /* set selection back to avoid active-unselected vertex */ - BM_vert_select_set(bm, v, true); - /* should never happen */ - return OPERATOR_CANCELLED; - } - else { - int vi_best = 0; - - if (ese.ele) { - BM_select_history_remove(bm, ese.ele); - } - - dist_sq = FLT_MAX; - - /* in the loop below we find the best vertex to drag based on its connected geometry, - * either by its face corner, or connected edge (when no faces are attached) */ - for (i = 0; i < vout_len; i++) { - - if (BM_vert_is_wire(vout[i]) == false) { - /* find the best face corner */ - BM_ITER_ELEM (l, &iter, vout[i], BM_LOOPS_OF_VERT) { - if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) { - float l_mid_co[3]; - - edbm_calc_loop_co(l, l_mid_co); - d = edbm_rip_edgedist_squared(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT); - - if (d < dist_sq) { - dist_sq = d; - vi_best = i; - } - } - } - } - else { - BMEdge *e; - /* a wire vert, find the best edge */ - BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - float e_mid_co[3]; - - mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co); - d = edbm_rip_edgedist_squared(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT); - - if (d < dist_sq) { - dist_sq = d; - vi_best = i; - } - } - } - } - } - - /* vout[0] == best - * vout[1] == glue - * vout[2+] == splice with glue (when vout_len > 2) - */ - if (vi_best != 0) { - SWAP(BMVert *, vout[0], vout[vi_best]); - vi_best = 0; - } - - /* select the vert from the best region */ - v = vout[vi_best]; - BM_vert_select_set(bm, v, true); - - if (ese.ele) { - BM_select_history_store(bm, v); - } - - /* splice all others back together */ - if (vout_len > 2) { - for (i = 2; i < vout_len; i++) { - BM_vert_splice(bm, vout[1], vout[i]); - } - } - - if (do_fill) { - /* match extrude vert-order */ - BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP); - } - - MEM_freeN(vout); - - return OPERATOR_FINISHED; - } - } - - if (!e_best) { - return OPERATOR_CANCELLED; - } - - /* *** Execute the split! *** */ - /* unlike edge split, for single vertex split we only use the operator in one of the cases - * but both allocate fill */ - - { - BMVert *v_rip; - BMLoop *larr[2]; - int larr_len = 0; - - /* rip two adjacent edges */ - if (BM_edge_is_boundary(e_best) || BM_vert_face_count_is_equal(v, 2)) { - /* Don't run the edge split operator in this case */ - - l = BM_edge_vert_share_loop(e_best->l, v); - larr[larr_len] = l; - larr_len++; - - /* only tag for face-fill (we don't call the operator) */ - if (BM_edge_is_boundary(e_best)) { - BM_elem_flag_enable(e_best, BM_ELEM_TAG); - } - else { - BM_elem_flag_enable(l->e, BM_ELEM_TAG); - BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG); - } - } - else { - if (BM_edge_is_manifold(e_best)) { - BMLoop *l_iter, *l_first; - l_iter = l_first = e_best->l; - do { - larr[larr_len] = BM_edge_vert_share_loop(l_iter, v); - - if (do_fill) { - /* Only needed when filling... - * Also, we never want to tag best edge, - * that one won't change during split. See T44618. */ - if (larr[larr_len]->e == e_best) { - BM_elem_flag_enable(larr[larr_len]->prev->e, BM_ELEM_TAG); - } - else { - BM_elem_flag_enable(larr[larr_len]->e, BM_ELEM_TAG); - } - } - larr_len++; - } while ((l_iter = l_iter->radial_next) != l_first); - } - else { - /* looks like there are no split edges, we could just return/report-error? - Campbell */ - } - } - - /* keep directly before edgesplit */ - if (do_fill) { - fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); - } - - if (larr_len) { - v_rip = BM_face_loop_separate_multi(bm, larr, larr_len); - } - else { - v_rip = NULL; - } - - if (v_rip) { - BM_vert_select_set(bm, v_rip, true); - } - else { - if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs); - return OPERATOR_CANCELLED; - } - } - - { - /* --- select which vert --- */ - BMVert *v_best = NULL; - float l_corner_co[3]; - - dist_sq = FLT_MAX; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - /* disable by default, re-enable winner at end */ - BM_vert_select_set(bm, v, false); - BM_select_history_remove(bm, v); - - BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - - /* check if v_best is null in the _rare_ case there are numeric issues */ - edbm_calc_loop_co(l, l_corner_co); - d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT); - if ((v_best == NULL) || (d < dist_sq)) { - v_best = v; - dist_sq = d; - } - } - } - } - - if (v_best) { - BM_vert_select_set(bm, v_best, true); - if (ese.ele) { - BM_select_history_store(bm, v_best); - } - } - } - - if (do_fill && fill_uloop_pairs) { - edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs); - MEM_freeN(fill_uloop_pairs); - } - - - if (totvert_orig == bm->totvert) { - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + UnorderedLoopPair *fill_uloop_pairs = NULL; + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter iter, liter; + BMLoop *l; + BMEdge *e_best; + BMVert *v; + const int totvert_orig = bm->totvert; + int i; + float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; + float dist_sq = FLT_MAX; + float d; + bool is_wire, is_manifold_region; + + BMEditSelection ese; + int totboundary_edge = 0; + + ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); + + /* find selected vert - same some time and check history first */ + if (BM_select_history_active_get(bm, &ese) && ese.htype == BM_VERT) { + v = (BMVert *)ese.ele; + } + else { + ese.ele = NULL; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) + break; + } + } + + /* (v == NULL) should be impossible */ + if ((v == NULL) || (v->e == NULL)) { + return OPERATOR_CANCELLED; + } + + is_wire = BM_vert_is_wire(v); + is_manifold_region = BM_vert_is_manifold_region(v); + + e_best = NULL; + + { + BMEdge *e; + /* find closest edge to mouse cursor */ + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + /* consider wire as boundary for this purpose, + * otherwise we can't a face away from a wire edge */ + totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e)); + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if ((is_manifold_region == false) || BM_edge_is_manifold(e)) { + d = edbm_rip_edgedist_squared( + ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT); + if ((e_best == NULL) || (d < dist_sq)) { + dist_sq = d; + e_best = e; + } + } + } + } + } + + if (e_best && e_best->l && (is_manifold_region == false)) { + /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */ + BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next; + BMVert *v_new; + + BLI_assert(l_sep->v == v); + v_new = BM_face_loop_separate_multi_isolated(bm, l_sep); + BLI_assert(BM_vert_find_first_loop(v)); + + BM_vert_select_set(bm, v, false); + BM_select_history_remove(bm, v); + + BM_vert_select_set(bm, v_new, true); + if (ese.ele) { + BM_select_history_store(bm, v_new); + } + + if (do_fill) { + BM_edge_create(bm, v, v_new, NULL, BM_CREATE_NOP); + } + + return OPERATOR_FINISHED; + } + + /* if we are ripping a single vertex from 3 faces, + * then measure the distance to the face corner as well as the edge */ + if (BM_vert_face_count_is_equal(v, 3) && BM_vert_edge_count_is_equal(v, 3)) { + BMEdge *e_all[3]; + BMLoop *l_all[3]; + int i1, i2; + + BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3); + BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3); + + /* not do a loop similar to the one above, but test against loops */ + for (i1 = 0; i1 < 3; i1++) { + /* consider wire as boundary for this purpose, + * otherwise we can't a face away from a wire edge */ + float l_mid_co[3]; + l = l_all[i1]; + edbm_calc_loop_co(l, l_mid_co); + d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT); + if ((e_best == NULL) || (d < dist_sq)) { + dist_sq = d; + + /* find the edge that is not in this loop */ + e_best = NULL; + for (i2 = 0; i2 < 3; i2++) { + if (!BM_edge_in_loop(e_all[i2], l)) { + e_best = e_all[i2]; + break; + } + } + BLI_assert(e_best != NULL); + } + } + } + + /* should we go ahead with edge rip or do we need to do special case, split off vertex?: + * split off vertex if... + * - we cant find an edge - this means we are ripping a faces vert that is connected to other + * geometry only at the vertex. + * - the boundary edge total is greater than 2, + * in this case edge split _can_ work but we get far nicer results if we use this special case. + * - there are only 2 edges but we are a wire vert. */ + if ((is_wire == false && totboundary_edge > 2) || (is_wire == true && totboundary_edge > 1)) { + BMVert **vout; + int vout_len; + + BM_vert_select_set(bm, v, false); + + bmesh_kernel_vert_separate(bm, v, &vout, &vout_len, true); + + if (vout_len < 2) { + MEM_freeN(vout); + /* set selection back to avoid active-unselected vertex */ + BM_vert_select_set(bm, v, true); + /* should never happen */ + return OPERATOR_CANCELLED; + } + else { + int vi_best = 0; + + if (ese.ele) { + BM_select_history_remove(bm, ese.ele); + } + + dist_sq = FLT_MAX; + + /* in the loop below we find the best vertex to drag based on its connected geometry, + * either by its face corner, or connected edge (when no faces are attached) */ + for (i = 0; i < vout_len; i++) { + + if (BM_vert_is_wire(vout[i]) == false) { + /* find the best face corner */ + BM_ITER_ELEM (l, &iter, vout[i], BM_LOOPS_OF_VERT) { + if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) { + float l_mid_co[3]; + + edbm_calc_loop_co(l, l_mid_co); + d = edbm_rip_edgedist_squared(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT); + + if (d < dist_sq) { + dist_sq = d; + vi_best = i; + } + } + } + } + else { + BMEdge *e; + /* a wire vert, find the best edge */ + BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + float e_mid_co[3]; + + mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co); + d = edbm_rip_edgedist_squared(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT); + + if (d < dist_sq) { + dist_sq = d; + vi_best = i; + } + } + } + } + } + + /* vout[0] == best + * vout[1] == glue + * vout[2+] == splice with glue (when vout_len > 2) + */ + if (vi_best != 0) { + SWAP(BMVert *, vout[0], vout[vi_best]); + vi_best = 0; + } + + /* select the vert from the best region */ + v = vout[vi_best]; + BM_vert_select_set(bm, v, true); + + if (ese.ele) { + BM_select_history_store(bm, v); + } + + /* splice all others back together */ + if (vout_len > 2) { + for (i = 2; i < vout_len; i++) { + BM_vert_splice(bm, vout[1], vout[i]); + } + } + + if (do_fill) { + /* match extrude vert-order */ + BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP); + } + + MEM_freeN(vout); + + return OPERATOR_FINISHED; + } + } + + if (!e_best) { + return OPERATOR_CANCELLED; + } + + /* *** Execute the split! *** */ + /* unlike edge split, for single vertex split we only use the operator in one of the cases + * but both allocate fill */ + + { + BMVert *v_rip; + BMLoop *larr[2]; + int larr_len = 0; + + /* rip two adjacent edges */ + if (BM_edge_is_boundary(e_best) || BM_vert_face_count_is_equal(v, 2)) { + /* Don't run the edge split operator in this case */ + + l = BM_edge_vert_share_loop(e_best->l, v); + larr[larr_len] = l; + larr_len++; + + /* only tag for face-fill (we don't call the operator) */ + if (BM_edge_is_boundary(e_best)) { + BM_elem_flag_enable(e_best, BM_ELEM_TAG); + } + else { + BM_elem_flag_enable(l->e, BM_ELEM_TAG); + BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG); + } + } + else { + if (BM_edge_is_manifold(e_best)) { + BMLoop *l_iter, *l_first; + l_iter = l_first = e_best->l; + do { + larr[larr_len] = BM_edge_vert_share_loop(l_iter, v); + + if (do_fill) { + /* Only needed when filling... + * Also, we never want to tag best edge, + * that one won't change during split. See T44618. */ + if (larr[larr_len]->e == e_best) { + BM_elem_flag_enable(larr[larr_len]->prev->e, BM_ELEM_TAG); + } + else { + BM_elem_flag_enable(larr[larr_len]->e, BM_ELEM_TAG); + } + } + larr_len++; + } while ((l_iter = l_iter->radial_next) != l_first); + } + else { + /* looks like there are no split edges, we could just return/report-error? - Campbell */ + } + } + + /* keep directly before edgesplit */ + if (do_fill) { + fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); + } + + if (larr_len) { + v_rip = BM_face_loop_separate_multi(bm, larr, larr_len); + } + else { + v_rip = NULL; + } + + if (v_rip) { + BM_vert_select_set(bm, v_rip, true); + } + else { + if (fill_uloop_pairs) + MEM_freeN(fill_uloop_pairs); + return OPERATOR_CANCELLED; + } + } + + { + /* --- select which vert --- */ + BMVert *v_best = NULL; + float l_corner_co[3]; + + dist_sq = FLT_MAX; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + /* disable by default, re-enable winner at end */ + BM_vert_select_set(bm, v, false); + BM_select_history_remove(bm, v); + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + + /* check if v_best is null in the _rare_ case there are numeric issues */ + edbm_calc_loop_co(l, l_corner_co); + d = edbm_rip_edgedist_squared( + ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT); + if ((v_best == NULL) || (d < dist_sq)) { + v_best = v; + dist_sq = d; + } + } + } + } + + if (v_best) { + BM_vert_select_set(bm, v_best, true); + if (ese.ele) { + BM_select_history_store(bm, v_best); + } + } + } + + if (do_fill && fill_uloop_pairs) { + edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs); + MEM_freeN(fill_uloop_pairs); + } + + if (totvert_orig == bm->totvert) { + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } /** @@ -877,247 +867,246 @@ static int edbm_rip_invoke__vert(bContext *C, const wmEvent *event, Object *obed */ static int edbm_rip_invoke__edge(bContext *C, const wmEvent *event, Object *obedit, bool do_fill) { - UnorderedLoopPair *fill_uloop_pairs = NULL; - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter, eiter; - BMLoop *l; - BMEdge *e_best; - BMVert *v; - const int totedge_orig = bm->totedge; - float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; - - EdgeLoopPair *eloop_pairs; - - ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); - - /* important this runs on the original selection, before tampering with tagging */ - eloop_pairs = edbm_ripsel_looptag_helper(bm); - - /* expand edge selection */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMEdge *e; - bool all_manifold; - int totedge_manifold; /* manifold, visible edges */ - int i; - - e_best = NULL; - i = 0; - totedge_manifold = 0; - all_manifold = true; - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - - if (!BM_edge_is_wire(e) && - !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) - { - /* important to check selection rather then tag here - * else we get feedback loop */ - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - e_best = e; - i++; - } - totedge_manifold++; - } - - /** #BM_vert_other_disk_edge has no hidden checks so don't check hidden here */ - if ((all_manifold == true) && (BM_edge_is_manifold(e) == false)) { - all_manifold = false; - } - } - - /* single edge, extend */ - if (i == 1 && e_best->l) { - /* note: if the case of 3 edges has one change in loop stepping, - * if this becomes more involved we may be better off splitting - * the 3 edge case into its own else-if branch */ - if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) { - BMLoop *l_a = e_best->l; - BMLoop *l_b = l_a->radial_next; - - /* find the best face to follow, this way the edge won't point away from - * the mouse when there are more than 4 (takes the shortest face fan around) */ - l = (edbm_rip_edge_side_measure(e_best, l_a, ar, projectMat, fmval) < - edbm_rip_edge_side_measure(e_best, l_b, ar, projectMat, fmval)) ? l_a : l_b; - - l = BM_loop_other_edge_loop(l, v); - /* important edge is manifold else we can be attempting to split off a fan that don't budge, - * not crashing but adds duplicate edge. */ - if (BM_edge_is_manifold(l->e)) { - l = l->radial_next; - - if (totedge_manifold != 3) - l = BM_loop_other_edge_loop(l, v); - - if (l) { - BLI_assert(!BM_elem_flag_test(l->e, BM_ELEM_TAG)); - BM_elem_flag_enable(l->e, BM_ELEM_TAG); - } - } - } - else { - e = BM_vert_other_disk_edge(v, e_best); - - if (e) { - BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG)); - BM_elem_flag_enable(e, BM_ELEM_TAG); - } - } - } - } - - /* keep directly before edgesplit */ - if (do_fill) { - fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); - } - - BM_mesh_edgesplit(em->bm, true, true, true); - - /* note: the output of the bmesh operator is ignored, since we built - * the contiguous loop pairs to split already, its possible that some - * edge did not split even though it was tagged which would not work - * as expected (but not crash), however there are checks to ensure - * tagged edges will split. So far its not been an issue. */ - edbm_ripsel_deselect_helper(bm, eloop_pairs, - ar, projectMat, fmval); - MEM_freeN(eloop_pairs); - - /* deselect loose verts */ - BM_mesh_select_mode_clean_ex(bm, SCE_SELECT_EDGE); - - if (do_fill && fill_uloop_pairs) { - edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs); - MEM_freeN(fill_uloop_pairs); - } - - if (totedge_orig == bm->totedge) { - return OPERATOR_CANCELLED; - } - - BM_select_history_validate(bm); - - return OPERATOR_FINISHED; + UnorderedLoopPair *fill_uloop_pairs = NULL; + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter iter, eiter; + BMLoop *l; + BMEdge *e_best; + BMVert *v; + const int totedge_orig = bm->totedge; + float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; + + EdgeLoopPair *eloop_pairs; + + ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); + + /* important this runs on the original selection, before tampering with tagging */ + eloop_pairs = edbm_ripsel_looptag_helper(bm); + + /* expand edge selection */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BMEdge *e; + bool all_manifold; + int totedge_manifold; /* manifold, visible edges */ + int i; + + e_best = NULL; + i = 0; + totedge_manifold = 0; + all_manifold = true; + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + + if (!BM_edge_is_wire(e) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + /* important to check selection rather then tag here + * else we get feedback loop */ + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + e_best = e; + i++; + } + totedge_manifold++; + } + + /** #BM_vert_other_disk_edge has no hidden checks so don't check hidden here */ + if ((all_manifold == true) && (BM_edge_is_manifold(e) == false)) { + all_manifold = false; + } + } + + /* single edge, extend */ + if (i == 1 && e_best->l) { + /* note: if the case of 3 edges has one change in loop stepping, + * if this becomes more involved we may be better off splitting + * the 3 edge case into its own else-if branch */ + if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) { + BMLoop *l_a = e_best->l; + BMLoop *l_b = l_a->radial_next; + + /* find the best face to follow, this way the edge won't point away from + * the mouse when there are more than 4 (takes the shortest face fan around) */ + l = (edbm_rip_edge_side_measure(e_best, l_a, ar, projectMat, fmval) < + edbm_rip_edge_side_measure(e_best, l_b, ar, projectMat, fmval)) ? + l_a : + l_b; + + l = BM_loop_other_edge_loop(l, v); + /* important edge is manifold else we can be attempting to split off a fan that don't budge, + * not crashing but adds duplicate edge. */ + if (BM_edge_is_manifold(l->e)) { + l = l->radial_next; + + if (totedge_manifold != 3) + l = BM_loop_other_edge_loop(l, v); + + if (l) { + BLI_assert(!BM_elem_flag_test(l->e, BM_ELEM_TAG)); + BM_elem_flag_enable(l->e, BM_ELEM_TAG); + } + } + } + else { + e = BM_vert_other_disk_edge(v, e_best); + + if (e) { + BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG)); + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + } + } + } + + /* keep directly before edgesplit */ + if (do_fill) { + fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); + } + + BM_mesh_edgesplit(em->bm, true, true, true); + + /* note: the output of the bmesh operator is ignored, since we built + * the contiguous loop pairs to split already, its possible that some + * edge did not split even though it was tagged which would not work + * as expected (but not crash), however there are checks to ensure + * tagged edges will split. So far its not been an issue. */ + edbm_ripsel_deselect_helper(bm, eloop_pairs, ar, projectMat, fmval); + MEM_freeN(eloop_pairs); + + /* deselect loose verts */ + BM_mesh_select_mode_clean_ex(bm, SCE_SELECT_EDGE); + + if (do_fill && fill_uloop_pairs) { + edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs); + MEM_freeN(fill_uloop_pairs); + } + + if (totedge_orig == bm->totedge) { + return OPERATOR_CANCELLED; + } + + BM_select_history_validate(bm); + + return OPERATOR_FINISHED; } /* based on mouse cursor position, it defines how is being ripped */ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - const bool do_fill = RNA_boolean_get(op->ptr, "use_fill"); - - bool no_vertex_selected = true; - bool error_face_selected = true; - bool error_disconnected_vertices = true; - bool error_rip_failed = true; - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - BMesh *bm = em->bm; - BMIter iter; - BMEdge *e; - const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0); - int ret; - - if (em->bm->totvertsel == 0) { - continue; - } - no_vertex_selected = false; - - /* running in face mode hardly makes sense, so convert to region loop and rip */ - if (bm->totfacesel) { - /* highly nifty but hard to support since the operator can fail and we're left - * with modified selection */ - // WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL); - continue; - } - error_face_selected = false; - - /* we could support this, but not for now */ - if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) { - continue; - } - error_disconnected_vertices = false; - - /* note on selection: - * When calling edge split we operate on tagged edges rather then selected - * this is important because the edges to operate on are extended by one, - * but the selection is left alone. - * - * After calling edge split - the duplicated edges have the same selection state as the - * original, so all we do is de-select the far side from the mouse and we have a - * useful selection for grabbing. - */ - - /* BM_ELEM_SELECT --> BM_ELEM_TAG */ - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); - } - - /* split 2 main parts of this operator out into vertex and edge ripping */ - if (singlesel) { - ret = edbm_rip_invoke__vert(C, event, obedit, do_fill); - } - else { - ret = edbm_rip_invoke__edge(C, event, obedit, do_fill); - } - - if (ret != OPERATOR_FINISHED) { - continue; - } - - BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0)); - - if (bm->totvertsel == 0) { - continue; - } - error_rip_failed = false; - - EDBM_update_generic(em, true, true); - } - - MEM_freeN(objects); - - if (no_vertex_selected) { - /* Ignore it. */ - return OPERATOR_CANCELLED; - } - else if (error_face_selected) { - BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces"); - return OPERATOR_CANCELLED; - } - else if (error_disconnected_vertices) { - BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices"); - return OPERATOR_CANCELLED; - } - else if (error_rip_failed) { - BKE_report(op->reports, RPT_ERROR, "Rip failed"); - return OPERATOR_CANCELLED; - } - /* No errors, everything went fine. */ - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + const bool do_fill = RNA_boolean_get(op->ptr, "use_fill"); + + bool no_vertex_selected = true; + bool error_face_selected = true; + bool error_disconnected_vertices = true; + bool error_rip_failed = true; + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + BMesh *bm = em->bm; + BMIter iter; + BMEdge *e; + const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0); + int ret; + + if (em->bm->totvertsel == 0) { + continue; + } + no_vertex_selected = false; + + /* running in face mode hardly makes sense, so convert to region loop and rip */ + if (bm->totfacesel) { + /* highly nifty but hard to support since the operator can fail and we're left + * with modified selection */ + // WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL); + continue; + } + error_face_selected = false; + + /* we could support this, but not for now */ + if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) { + continue; + } + error_disconnected_vertices = false; + + /* note on selection: + * When calling edge split we operate on tagged edges rather then selected + * this is important because the edges to operate on are extended by one, + * but the selection is left alone. + * + * After calling edge split - the duplicated edges have the same selection state as the + * original, so all we do is de-select the far side from the mouse and we have a + * useful selection for grabbing. + */ + + /* BM_ELEM_SELECT --> BM_ELEM_TAG */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + } + + /* split 2 main parts of this operator out into vertex and edge ripping */ + if (singlesel) { + ret = edbm_rip_invoke__vert(C, event, obedit, do_fill); + } + else { + ret = edbm_rip_invoke__edge(C, event, obedit, do_fill); + } + + if (ret != OPERATOR_FINISHED) { + continue; + } + + BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0)); + + if (bm->totvertsel == 0) { + continue; + } + error_rip_failed = false; + + EDBM_update_generic(em, true, true); + } + + MEM_freeN(objects); + + if (no_vertex_selected) { + /* Ignore it. */ + return OPERATOR_CANCELLED; + } + else if (error_face_selected) { + BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces"); + return OPERATOR_CANCELLED; + } + else if (error_disconnected_vertices) { + BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices"); + return OPERATOR_CANCELLED; + } + else if (error_rip_failed) { + BKE_report(op->reports, RPT_ERROR, "Rip failed"); + return OPERATOR_CANCELLED; + } + /* No errors, everything went fine. */ + return OPERATOR_FINISHED; } - void MESH_OT_rip(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Rip"; - ot->idname = "MESH_OT_rip"; - ot->description = "Disconnect vertex or edges from connected geometry"; + /* identifiers */ + ot->name = "Rip"; + ot->idname = "MESH_OT_rip"; + ot->description = "Disconnect vertex or edges from connected geometry"; - /* api callbacks */ - ot->invoke = edbm_rip_invoke; - ot->poll = EDBM_view3d_poll; + /* api callbacks */ + ot->invoke = edbm_rip_invoke; + ot->poll = EDBM_view3d_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* to give to transform */ - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); - RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill the ripped region"); + /* to give to transform */ + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); + RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill the ripped region"); } diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c index e449f96bc05..e2b77d8c83b 100644 --- a/source/blender/editors/mesh/editmesh_rip_edge.c +++ b/source/blender/editors/mesh/editmesh_rip_edge.c @@ -40,213 +40,211 @@ #include "bmesh.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /* uses total number of selected edges around a vertex to choose how to extend */ #define USE_TRICKY_EXTEND static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - BMIter viter; - BMVert *v; - const float mval_fl[2] = { UNPACK2(event->mval) }; - float cent_sco[2]; - int cent_tot; - bool changed = false; - - /* mouse direction to view center */ - float mval_dir[2]; - - float projectMat[4][4]; - - if (bm->totvertsel == 0) - continue; - - ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); - - zero_v2(cent_sco); - cent_tot = 0; - - /* clear tags and calc screen center */ - BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(v, BM_ELEM_TAG); - - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - float v_sco[2]; - ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat); - - add_v2_v2(cent_sco, v_sco); - cent_tot += 1; - } - } - mul_v2_fl(cent_sco, 1.0f / (float)cent_tot); - - /* not essential, but gives more expected results with edge selection */ - if (bm->totedgesel) { - /* angle against center can give odd result, - * try re-position the center to the closest edge */ - BMIter eiter; - BMEdge *e; - float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl); - - BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - float e_sco[2][2]; - float cent_sco_test[2]; - float dist_sq_test; - - ED_view3d_project_float_v2_m4(ar, e->v1->co, e_sco[0], projectMat); - ED_view3d_project_float_v2_m4(ar, e->v2->co, e_sco[1], projectMat); - - closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]); - dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl); - if (dist_sq_test < dist_sq_best) { - dist_sq_best = dist_sq_test; - - /* we have a new screen center */ - copy_v2_v2(cent_sco, cent_sco_test); - } - } - } - } - - sub_v2_v2v2(mval_dir, mval_fl, cent_sco); - normalize_v2(mval_dir); - - /* operate on selected verts */ - BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) { - BMIter eiter; - BMEdge *e; - float v_sco[2]; - - if (BM_elem_flag_test(v, BM_ELEM_SELECT) && - BM_elem_flag_test(v, BM_ELEM_TAG) == false) - { - /* Rules for */ - float angle_best = FLT_MAX; - BMEdge *e_best = NULL; + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + BMIter viter; + BMVert *v; + const float mval_fl[2] = {UNPACK2(event->mval)}; + float cent_sco[2]; + int cent_tot; + bool changed = false; + + /* mouse direction to view center */ + float mval_dir[2]; + + float projectMat[4][4]; + + if (bm->totvertsel == 0) + continue; + + ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); + + zero_v2(cent_sco); + cent_tot = 0; + + /* clear tags and calc screen center */ + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(v, BM_ELEM_TAG); + + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + float v_sco[2]; + ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat); + + add_v2_v2(cent_sco, v_sco); + cent_tot += 1; + } + } + mul_v2_fl(cent_sco, 1.0f / (float)cent_tot); + + /* not essential, but gives more expected results with edge selection */ + if (bm->totedgesel) { + /* angle against center can give odd result, + * try re-position the center to the closest edge */ + BMIter eiter; + BMEdge *e; + float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl); + + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + float e_sco[2][2]; + float cent_sco_test[2]; + float dist_sq_test; + + ED_view3d_project_float_v2_m4(ar, e->v1->co, e_sco[0], projectMat); + ED_view3d_project_float_v2_m4(ar, e->v2->co, e_sco[1], projectMat); + + closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]); + dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl); + if (dist_sq_test < dist_sq_best) { + dist_sq_best = dist_sq_test; + + /* we have a new screen center */ + copy_v2_v2(cent_sco, cent_sco_test); + } + } + } + } + + sub_v2_v2v2(mval_dir, mval_fl, cent_sco); + normalize_v2(mval_dir); + + /* operate on selected verts */ + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + BMIter eiter; + BMEdge *e; + float v_sco[2]; + + if (BM_elem_flag_test(v, BM_ELEM_SELECT) && BM_elem_flag_test(v, BM_ELEM_TAG) == false) { + /* Rules for */ + float angle_best = FLT_MAX; + BMEdge *e_best = NULL; #ifdef USE_TRICKY_EXTEND - /* first check if we can select the edge to split based on selection-only */ - int tot_sel = 0, tot = 0; - - BM_ITER_ELEM(e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - e_best = e; - tot_sel += 1; - } - tot += 1; - } - } - if (tot_sel != 1) { - e_best = NULL; - } - - /* only one edge selected, operate on that */ - if (e_best) { - goto found_edge; - } - /* none selected, fall through and find one */ - else if (tot_sel == 0) { - /* pass */ - } - /* selection not 0 or 1, do nothing */ - else { - goto found_edge; - } + /* first check if we can select the edge to split based on selection-only */ + int tot_sel = 0, tot = 0; + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + e_best = e; + tot_sel += 1; + } + tot += 1; + } + } + if (tot_sel != 1) { + e_best = NULL; + } + + /* only one edge selected, operate on that */ + if (e_best) { + goto found_edge; + } + /* none selected, fall through and find one */ + else if (tot_sel == 0) { + /* pass */ + } + /* selection not 0 or 1, do nothing */ + else { + goto found_edge; + } #endif - ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat); + ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat); - BM_ITER_ELEM(e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - BMVert *v_other = BM_edge_other_vert(e, v); - float v_other_sco[2]; - float angle_test; + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + BMVert *v_other = BM_edge_other_vert(e, v); + float v_other_sco[2]; + float angle_test; - ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat); + ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat); - /* avoid comparing with view-axis aligned edges (less than a pixel) */ - if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) { - float v_dir[2]; + /* avoid comparing with view-axis aligned edges (less than a pixel) */ + if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) { + float v_dir[2]; - sub_v2_v2v2(v_dir, v_other_sco, v_sco); - normalize_v2(v_dir); + sub_v2_v2v2(v_dir, v_other_sco, v_sco); + normalize_v2(v_dir); - angle_test = angle_normalized_v2v2(mval_dir, v_dir); + angle_test = angle_normalized_v2v2(mval_dir, v_dir); - if (angle_test < angle_best) { - angle_best = angle_test; - e_best = e; - } - } - } - } + if (angle_test < angle_best) { + angle_best = angle_test; + e_best = e; + } + } + } + } #ifdef USE_TRICKY_EXTEND -found_edge : + found_edge: #endif - if (e_best) { - const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT); - BMVert *v_new; - BMEdge *e_new; + if (e_best) { + const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT); + BMVert *v_new; + BMEdge *e_new; - v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f); + v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f); - BM_vert_select_set(bm, v, false); - BM_edge_select_set(bm, e_new, false); + BM_vert_select_set(bm, v, false); + BM_edge_select_set(bm, e_new, false); - BM_vert_select_set(bm, v_new, true); - if (e_select) { - BM_edge_select_set(bm, e_best, true); - } - BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */ + BM_vert_select_set(bm, v_new, true); + if (e_select) { + BM_edge_select_set(bm, e_best, true); + } + BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */ - changed = true; - } - } - } + changed = true; + } + } + } - if (changed) { - BM_select_history_clear(bm); + if (changed) { + BM_select_history_clear(bm); - BM_mesh_select_mode_flush(bm); + BM_mesh_select_mode_flush(bm); - EDBM_update_generic(em, true, true); - } - } + EDBM_update_generic(em, true, true); + } + } - MEM_freeN(objects); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } - void MESH_OT_rip_edge(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Extend Vertices"; - ot->idname = "MESH_OT_rip_edge"; - ot->description = "Extend vertices along the edge closest to the cursor"; + /* identifiers */ + ot->name = "Extend Vertices"; + ot->idname = "MESH_OT_rip_edge"; + ot->description = "Extend vertices along the edge closest to the cursor"; - /* api callbacks */ - ot->invoke = edbm_rip_edge_invoke; - ot->poll = EDBM_view3d_poll; + /* api callbacks */ + ot->invoke = edbm_rip_edge_invoke; + ot->poll = EDBM_view3d_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* to give to transform */ - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); + /* to give to transform */ + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 8b75b511319..94886266d24 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -67,7 +67,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /* use bmesh operator flags for a few operators */ #define BMO_ELE_TAG 1 @@ -77,94 +77,92 @@ * \{ */ void EDBM_select_mirrored( - BMEditMesh *em, const int axis, const bool extend, - int *r_totmirr, int *r_totfail) + BMEditMesh *em, const int axis, const bool extend, int *r_totmirr, int *r_totfail) { - Mesh *me = (Mesh *)em->ob->data; - BMesh *bm = em->bm; - BMIter iter; - int totmirr = 0; - int totfail = 0; - bool use_topology = (me && (me->editflag & ME_EDIT_MIRROR_TOPO)); - - *r_totmirr = *r_totfail = 0; - - /* select -> tag */ - if (bm->selectmode & SCE_SELECT_VERTEX) { - BMVert *v; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT)); - } - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *e; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); - } - } - else { - BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT)); - } - } - - EDBM_verts_mirror_cache_begin(em, axis, true, true, use_topology); - - if (!extend) - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - - - if (bm->selectmode & SCE_SELECT_VERTEX) { - BMVert *v; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_TAG)) { - BMVert *v_mirr = EDBM_verts_mirror_get(em, v); - if (v_mirr && !BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) { - BM_vert_select_set(bm, v_mirr, true); - totmirr++; - } - else { - totfail++; - } - } - } - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *e; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, BM_ELEM_TAG)) { - BMEdge *e_mirr = EDBM_verts_mirror_get_edge(em, e); - if (e_mirr && !BM_elem_flag_test(e_mirr, BM_ELEM_HIDDEN)) { - BM_edge_select_set(bm, e_mirr, true); - totmirr++; - } - else { - totfail++; - } - } - } - } - else { - BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN) && BM_elem_flag_test(f, BM_ELEM_TAG)) { - BMFace *f_mirr = EDBM_verts_mirror_get_face(em, f); - if (f_mirr && !BM_elem_flag_test(f_mirr, BM_ELEM_HIDDEN)) { - BM_face_select_set(bm, f_mirr, true); - totmirr++; - } - else { - totfail++; - } - } - } - } - - EDBM_verts_mirror_cache_end(em); - - *r_totmirr = totmirr; - *r_totfail = totfail; + Mesh *me = (Mesh *)em->ob->data; + BMesh *bm = em->bm; + BMIter iter; + int totmirr = 0; + int totfail = 0; + bool use_topology = (me && (me->editflag & ME_EDIT_MIRROR_TOPO)); + + *r_totmirr = *r_totfail = 0; + + /* select -> tag */ + if (bm->selectmode & SCE_SELECT_VERTEX) { + BMVert *v; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT)); + } + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BMEdge *e; + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + } + } + else { + BMFace *f; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT)); + } + } + + EDBM_verts_mirror_cache_begin(em, axis, true, true, use_topology); + + if (!extend) + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + if (bm->selectmode & SCE_SELECT_VERTEX) { + BMVert *v; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_TAG)) { + BMVert *v_mirr = EDBM_verts_mirror_get(em, v); + if (v_mirr && !BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) { + BM_vert_select_set(bm, v_mirr, true); + totmirr++; + } + else { + totfail++; + } + } + } + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BMEdge *e; + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, BM_ELEM_TAG)) { + BMEdge *e_mirr = EDBM_verts_mirror_get_edge(em, e); + if (e_mirr && !BM_elem_flag_test(e_mirr, BM_ELEM_HIDDEN)) { + BM_edge_select_set(bm, e_mirr, true); + totmirr++; + } + else { + totfail++; + } + } + } + } + else { + BMFace *f; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN) && BM_elem_flag_test(f, BM_ELEM_TAG)) { + BMFace *f_mirr = EDBM_verts_mirror_get_face(em, f); + if (f_mirr && !BM_elem_flag_test(f_mirr, BM_ELEM_HIDDEN)) { + BM_face_select_set(bm, f_mirr, true); + totmirr++; + } + else { + totfail++; + } + } + } + } + + EDBM_verts_mirror_cache_end(em); + + *r_totmirr = totmirr; + *r_totfail = totfail; } /** \} */ @@ -177,17 +175,18 @@ void EDBM_select_mirrored( 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); - } + 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); + } } /** \} */ @@ -204,173 +203,175 @@ static BLI_bitmap *selbuf = NULL; static BLI_bitmap *edbm_backbuf_alloc(const int size) { - return BLI_BITMAP_NEW(size, "selbuf"); + return BLI_BITMAP_NEW(size, "selbuf"); } /* reads rect, and builds selection array for quick lookup */ /* returns if all is OK */ -bool EDBM_backbuf_border_init( - ViewContext *vc, short xmin, - short ymin, short xmax, short ymax) +bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xmax, short ymax) { - uint *buf, *dr, buf_len; - - if (vc->obedit == NULL || XRAY_FLAG_ENABLED(vc->v3d)) { - return false; - } - - buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, &buf_len); - if ((buf == NULL) || (bm_vertoffs == 0)) { - return false; - } - - dr = buf; - - /* build selection lookup */ - selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - - while (buf_len--) { - if (*dr > 0 && *dr <= bm_vertoffs) { - BLI_BITMAP_ENABLE(selbuf, *dr); - } - dr++; - } - MEM_freeN(buf); - return true; + uint *buf, *dr, buf_len; + + if (vc->obedit == NULL || XRAY_FLAG_ENABLED(vc->v3d)) { + return false; + } + + buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, &buf_len); + if ((buf == NULL) || (bm_vertoffs == 0)) { + return false; + } + + dr = buf; + + /* build selection lookup */ + selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); + + while (buf_len--) { + if (*dr > 0 && *dr <= bm_vertoffs) { + BLI_BITMAP_ENABLE(selbuf, *dr); + } + dr++; + } + MEM_freeN(buf); + return true; } bool EDBM_backbuf_check(unsigned int index) { - /* odd logic, if selbuf is NULL we assume no zbuf-selection is enabled - * and just ignore the depth buffer, this is error prone since its possible - * code doesn't set the depth buffer by accident, but leave for now. - Campbell */ - if (selbuf == NULL) - return true; + /* odd logic, if selbuf is NULL we assume no zbuf-selection is enabled + * and just ignore the depth buffer, this is error prone since its possible + * code doesn't set the depth buffer by accident, but leave for now. - Campbell */ + if (selbuf == NULL) + return true; - if (index > 0 && index <= bm_vertoffs) - return BLI_BITMAP_TEST_BOOL(selbuf, index); + if (index > 0 && index <= bm_vertoffs) + return BLI_BITMAP_TEST_BOOL(selbuf, index); - return false; + return false; } void EDBM_backbuf_free(void) { - if (selbuf) MEM_freeN(selbuf); - selbuf = NULL; + if (selbuf) + MEM_freeN(selbuf); + selbuf = NULL; } struct LassoMaskData { - unsigned int *px; - int width; + unsigned int *px; + int width; }; static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data) { - struct LassoMaskData *data = user_data; - unsigned int *px = &data->px[(y * data->width) + x]; - do { - *px = true; - px++; - } while (++x != x_end); + struct LassoMaskData *data = user_data; + unsigned int *px = &data->px[(y * data->width) + x]; + do { + *px = true; + px++; + } while (++x != x_end); } - /* mcords is a polygon mask * - grab backbuffer, * - draw with black in backbuffer, * - grab again and compare * returns 'OK' */ -bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax) +bool EDBM_backbuf_border_mask_init(ViewContext *vc, + const int mcords[][2], + short tot, + short xmin, + short ymin, + short xmax, + short ymax) { - uint *buf, *dr, *dr_mask, *dr_mask_arr, buf_len; - struct LassoMaskData lasso_mask_data; - - /* method in use for face selecting too */ - if (vc->obedit == NULL) { - if (!BKE_paint_select_elem_test(vc->obact)) { - return false; - } - } - else if (XRAY_FLAG_ENABLED(vc->v3d)) { - return false; - } - - buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, &buf_len); - if ((buf == NULL) || (bm_vertoffs == 0)) { - return false; - } - - dr = buf; - - dr_mask = dr_mask_arr = MEM_callocN(sizeof(*dr_mask) * buf_len, __func__); - lasso_mask_data.px = dr_mask; - lasso_mask_data.width = (xmax - xmin) + 1; - - BLI_bitmap_draw_2d_poly_v2i_n( - xmin, ymin, xmax + 1, ymax + 1, - mcords, tot, - edbm_mask_lasso_px_cb, &lasso_mask_data); - - /* build selection lookup */ - selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - - while (buf_len--) { - if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) { - BLI_BITMAP_ENABLE(selbuf, *dr); - } - dr++; dr_mask++; - } - MEM_freeN(buf); - MEM_freeN(dr_mask_arr); - - return true; + uint *buf, *dr, *dr_mask, *dr_mask_arr, buf_len; + struct LassoMaskData lasso_mask_data; + + /* method in use for face selecting too */ + if (vc->obedit == NULL) { + if (!BKE_paint_select_elem_test(vc->obact)) { + return false; + } + } + else if (XRAY_FLAG_ENABLED(vc->v3d)) { + return false; + } + + buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, &buf_len); + if ((buf == NULL) || (bm_vertoffs == 0)) { + return false; + } + + dr = buf; + + dr_mask = dr_mask_arr = MEM_callocN(sizeof(*dr_mask) * buf_len, __func__); + lasso_mask_data.px = dr_mask; + lasso_mask_data.width = (xmax - xmin) + 1; + + BLI_bitmap_draw_2d_poly_v2i_n( + xmin, ymin, xmax + 1, ymax + 1, mcords, tot, edbm_mask_lasso_px_cb, &lasso_mask_data); + + /* build selection lookup */ + selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); + + while (buf_len--) { + if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) { + BLI_BITMAP_ENABLE(selbuf, *dr); + } + dr++; + dr_mask++; + } + MEM_freeN(buf); + MEM_freeN(dr_mask_arr); + + return true; } /* circle shaped sample area */ -bool EDBM_backbuf_circle_init( - ViewContext *vc, - short xs, short ys, short rads) +bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) { - uint *buf, *dr; - short xmin, ymin, xmax, ymax, xc, yc; - int radsq; - - /* method in use for face selecting too */ - if (vc->obedit == NULL) { - if (!BKE_paint_select_elem_test(vc->obact)) { - return false; - } - } - else if (XRAY_FLAG_ENABLED(vc->v3d)) { - return false; - } - - xmin = xs - rads; xmax = xs + rads; - ymin = ys - rads; ymax = ys + rads; - buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, NULL); - if ((buf == NULL) || (bm_vertoffs == 0)) { - return false; - } - - dr = buf; - - /* build selection lookup */ - selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - radsq = rads * rads; - for (yc = -rads; yc <= rads; yc++) { - for (xc = -rads; xc <= rads; xc++, dr++) { - if (xc * xc + yc * yc < radsq) { - if (*dr > 0 && *dr <= bm_vertoffs) { - BLI_BITMAP_ENABLE(selbuf, *dr); - } - } - } - } - - MEM_freeN(buf); - return true; - + uint *buf, *dr; + short xmin, ymin, xmax, ymax, xc, yc; + int radsq; + + /* method in use for face selecting too */ + if (vc->obedit == NULL) { + if (!BKE_paint_select_elem_test(vc->obact)) { + return false; + } + } + else if (XRAY_FLAG_ENABLED(vc->v3d)) { + return false; + } + + xmin = xs - rads; + xmax = xs + rads; + ymin = ys - rads; + ymax = ys + rads; + buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, NULL); + if ((buf == NULL) || (bm_vertoffs == 0)) { + return false; + } + + dr = buf; + + /* build selection lookup */ + selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); + radsq = rads * rads; + for (yc = -rads; yc <= rads; yc++) { + for (xc = -rads; xc <= rads; xc++, dr++) { + if (xc * xc + yc * yc < radsq) { + if (*dr > 0 && *dr <= bm_vertoffs) { + BLI_BITMAP_ENABLE(selbuf, *dr); + } + } + } + } + + MEM_freeN(buf); + return true; } /** \} */ @@ -387,66 +388,69 @@ bool EDBM_backbuf_circle_init( * \{ */ #define FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, select_mode_required) \ - short select_mode = select_mode_required; \ - bool fake_select_mode = (select_mode & (vc)->scene->toolsettings->selectmode) == 0; \ - if (fake_select_mode) { \ - (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \ - } ((void)0) + short select_mode = select_mode_required; \ + bool fake_select_mode = (select_mode & (vc)->scene->toolsettings->selectmode) == 0; \ + if (fake_select_mode) { \ + (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \ + } \ + ((void)0) #define FAKE_SELECT_MODE_END(vc, fake_select_mode) \ - if (fake_select_mode) { \ - (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \ - } ((void)0) + if (fake_select_mode) { \ + (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \ + } \ + ((void)0) #define FIND_NEAR_SELECT_BIAS 5 #define FIND_NEAR_CYCLE_THRESHOLD_MIN 3 struct NearestVertUserData_Hit { - float dist; - float dist_bias; - int index; - BMVert *vert; + float dist; + float dist_bias; + int index; + BMVert *vert; }; struct NearestVertUserData { - float mval_fl[2]; - bool use_select_bias; - bool use_cycle; - int cycle_index_prev; + float mval_fl[2]; + bool use_select_bias; + bool use_cycle; + int cycle_index_prev; - struct NearestVertUserData_Hit hit; - struct NearestVertUserData_Hit hit_cycle; + struct NearestVertUserData_Hit hit; + struct NearestVertUserData_Hit hit_cycle; }; -static void findnearestvert__doClosest(void *userData, BMVert *eve, const float screen_co[2], int index) +static void findnearestvert__doClosest(void *userData, + BMVert *eve, + const float screen_co[2], + int index) { - struct NearestVertUserData *data = userData; - float dist_test, dist_test_bias; - - dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); - - if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - dist_test_bias += FIND_NEAR_SELECT_BIAS; - } - - if (dist_test_bias < data->hit.dist_bias) { - data->hit.dist_bias = dist_test_bias; - data->hit.dist = dist_test; - data->hit.index = index; - data->hit.vert = eve; - } - - if (data->use_cycle) { - if ((data->hit_cycle.vert == NULL) && - (index > data->cycle_index_prev) && - (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) - { - data->hit_cycle.dist_bias = dist_test_bias; - data->hit_cycle.dist = dist_test; - data->hit_cycle.index = index; - data->hit_cycle.vert = eve; - } - } + struct NearestVertUserData *data = userData; + float dist_test, dist_test_bias; + + dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); + + if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + dist_test_bias += FIND_NEAR_SELECT_BIAS; + } + + if (dist_test_bias < data->hit.dist_bias) { + data->hit.dist_bias = dist_test_bias; + data->hit.dist = dist_test; + data->hit.index = index; + data->hit.vert = eve; + } + + if (data->use_cycle) { + if ((data->hit_cycle.vert == NULL) && (index > data->cycle_index_prev) && + (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { + data->hit_cycle.dist_bias = dist_test_bias; + data->hit_cycle.dist = dist_test; + data->hit_cycle.index = index; + data->hit_cycle.vert = eve; + } + } } /** @@ -458,618 +462,632 @@ static void findnearestvert__doClosest(void *userData, BMVert *eve, const float * - When false, unselected vertices are given the bias. * \param use_cycle: Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index. */ -BMVert *EDBM_vert_find_nearest_ex( - ViewContext *vc, float *r_dist, - const bool use_select_bias, bool use_cycle) +BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, + float *r_dist, + const bool use_select_bias, + bool use_cycle) { - BMesh *bm = vc->em->bm; - - if (!XRAY_FLAG_ENABLED(vc->v3d)) { - uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist); - unsigned int index; - BMVert *eve; - - /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ - { - FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX); - ED_view3d_select_id_validate_with_select_mode(vc, select_mode); - - index = ED_view3d_select_id_read_nearest(vc, vc->mval, bm_wireoffs, 0xFFFFFF, &dist_px); - eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL; - - FAKE_SELECT_MODE_END(vc, fake_select_mode); - } - - if (eve) { - if (dist_px < *r_dist) { - *r_dist = dist_px; - return eve; - } - } - return NULL; - } - else { - struct NearestVertUserData data = {{0}}; - const struct NearestVertUserData_Hit *hit; - const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; - - static int prev_select_index = 0; - static const BMVert *prev_select_elem = NULL; - - if ((use_cycle == false) || - (prev_select_elem && (prev_select_elem != BM_vert_at_index_find_or_table(bm, prev_select_index)))) - { - prev_select_index = 0; - prev_select_elem = NULL; - } - - data.mval_fl[0] = vc->mval[0]; - data.mval_fl[1] = vc->mval[1]; - data.use_select_bias = use_select_bias; - data.use_cycle = use_cycle; - data.hit.dist = data.hit_cycle.dist = \ - data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; - data.cycle_index_prev = prev_select_index; - - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag); - - hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit; - *r_dist = hit->dist; - - prev_select_elem = hit->vert; - prev_select_index = hit->index; - - return hit->vert; - } + BMesh *bm = vc->em->bm; + + if (!XRAY_FLAG_ENABLED(vc->v3d)) { + uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist); + unsigned int index; + BMVert *eve; + + /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ + { + FAKE_SELECT_MODE_BEGIN (vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX) + ; + ED_view3d_select_id_validate_with_select_mode(vc, select_mode); + + index = ED_view3d_select_id_read_nearest(vc, vc->mval, bm_wireoffs, 0xFFFFFF, &dist_px); + eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL; + + FAKE_SELECT_MODE_END(vc, fake_select_mode); + } + + if (eve) { + if (dist_px < *r_dist) { + *r_dist = dist_px; + return eve; + } + } + return NULL; + } + else { + struct NearestVertUserData data = {{0}}; + const struct NearestVertUserData_Hit *hit; + const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; + + static int prev_select_index = 0; + static const BMVert *prev_select_elem = NULL; + + if ((use_cycle == false) || + (prev_select_elem && + (prev_select_elem != BM_vert_at_index_find_or_table(bm, prev_select_index)))) { + prev_select_index = 0; + prev_select_elem = NULL; + } + + data.mval_fl[0] = vc->mval[0]; + data.mval_fl[1] = vc->mval[1]; + data.use_select_bias = use_select_bias; + data.use_cycle = use_cycle; + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; + data.cycle_index_prev = prev_select_index; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag); + + hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit; + *r_dist = hit->dist; + + prev_select_elem = hit->vert; + prev_select_index = hit->index; + + return hit->vert; + } } BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist) { - return EDBM_vert_find_nearest_ex(vc, r_dist, false, false); + return EDBM_vert_find_nearest_ex(vc, r_dist, false, false); } /* find the distance to the edge we already have */ struct NearestEdgeUserData_ZBuf { - float mval_fl[2]; - float dist; - const BMEdge *edge_test; + float mval_fl[2]; + float dist; + const BMEdge *edge_test; }; -static void find_nearest_edge_center__doZBuf( - void *userData, BMEdge *eed, - const float screen_co_a[2], const float screen_co_b[2], - int UNUSED(index)) +static void find_nearest_edge_center__doZBuf(void *userData, + BMEdge *eed, + const float screen_co_a[2], + const float screen_co_b[2], + int UNUSED(index)) { - struct NearestEdgeUserData_ZBuf *data = userData; + struct NearestEdgeUserData_ZBuf *data = userData; - if (eed == data->edge_test) { - float dist_test; - float screen_co_mid[2]; + if (eed == data->edge_test) { + float dist_test; + float screen_co_mid[2]; - mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); - dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid); + mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); + dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid); - if (dist_test < data->dist) { - data->dist = dist_test; - } - } + if (dist_test < data->dist) { + data->dist = dist_test; + } + } } struct NearestEdgeUserData_Hit { - float dist; - float dist_bias; - int index; - BMEdge *edge; - - /* edges only, un-biased manhatten distance to which ever edge we pick - * (not used for choosing) */ - float dist_center; + float dist; + float dist_bias; + int index; + BMEdge *edge; + + /* edges only, un-biased manhatten distance to which ever edge we pick + * (not used for choosing) */ + float dist_center; }; struct NearestEdgeUserData { - ViewContext vc; - float mval_fl[2]; - bool use_select_bias; - bool use_cycle; - int cycle_index_prev; - - struct NearestEdgeUserData_Hit hit; - struct NearestEdgeUserData_Hit hit_cycle; + ViewContext vc; + float mval_fl[2]; + bool use_select_bias; + bool use_cycle; + int cycle_index_prev; + + struct NearestEdgeUserData_Hit hit; + struct NearestEdgeUserData_Hit hit_cycle; }; /* note; uses v3d, so needs active 3d window */ static void find_nearest_edge__doClosest( - void *userData, BMEdge *eed, - const float screen_co_a[2], const float screen_co_b[2], - int index) + void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { - struct NearestEdgeUserData *data = userData; - float dist_test, dist_test_bias; - - float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b); - float screen_co[2]; - - if (fac <= 0.0f) { - fac = 0.0f; - copy_v2_v2(screen_co, screen_co_a); - } - else if (fac >= 1.0f) { - fac = 1.0f; - copy_v2_v2(screen_co, screen_co_b); - } - else { - interp_v2_v2v2(screen_co, screen_co_a, screen_co_b, fac); - } - - dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); - - if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - dist_test_bias += FIND_NEAR_SELECT_BIAS; - } - - if (data->vc.rv3d->rflag & RV3D_CLIPPING) { - float vec[3]; - - interp_v3_v3v3(vec, eed->v1->co, eed->v2->co, fac); - if (ED_view3d_clipping_test(data->vc.rv3d, vec, true)) { - return; - } - } - - if (dist_test_bias < data->hit.dist_bias) { - float screen_co_mid[2]; - - data->hit.dist_bias = dist_test_bias; - data->hit.dist = dist_test; - data->hit.index = index; - data->hit.edge = eed; - - mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); - data->hit.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid); - } - - if (data->use_cycle) { - if ((data->hit_cycle.edge == NULL) && - (index > data->cycle_index_prev) && - (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) - { - float screen_co_mid[2]; - - data->hit_cycle.dist_bias = dist_test_bias; - data->hit_cycle.dist = dist_test; - data->hit_cycle.index = index; - data->hit_cycle.edge = eed; - - mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); - data->hit_cycle.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid); - } - } + struct NearestEdgeUserData *data = userData; + float dist_test, dist_test_bias; + + float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b); + float screen_co[2]; + + if (fac <= 0.0f) { + fac = 0.0f; + copy_v2_v2(screen_co, screen_co_a); + } + else if (fac >= 1.0f) { + fac = 1.0f; + copy_v2_v2(screen_co, screen_co_b); + } + else { + interp_v2_v2v2(screen_co, screen_co_a, screen_co_b, fac); + } + + dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); + + if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + dist_test_bias += FIND_NEAR_SELECT_BIAS; + } + + if (data->vc.rv3d->rflag & RV3D_CLIPPING) { + float vec[3]; + + interp_v3_v3v3(vec, eed->v1->co, eed->v2->co, fac); + if (ED_view3d_clipping_test(data->vc.rv3d, vec, true)) { + return; + } + } + + if (dist_test_bias < data->hit.dist_bias) { + float screen_co_mid[2]; + + data->hit.dist_bias = dist_test_bias; + data->hit.dist = dist_test; + data->hit.index = index; + data->hit.edge = eed; + + mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); + data->hit.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid); + } + + if (data->use_cycle) { + if ((data->hit_cycle.edge == NULL) && (index > data->cycle_index_prev) && + (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { + float screen_co_mid[2]; + + data->hit_cycle.dist_bias = dist_test_bias; + data->hit_cycle.dist = dist_test; + data->hit_cycle.index = index; + data->hit_cycle.edge = eed; + + mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); + data->hit_cycle.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid); + } + } } -BMEdge *EDBM_edge_find_nearest_ex( - ViewContext *vc, float *r_dist, - float *r_dist_center, - const bool use_select_bias, const bool use_cycle, - BMEdge **r_eed_zbuf) +BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, + float *r_dist, + float *r_dist_center, + const bool use_select_bias, + const bool use_cycle, + BMEdge **r_eed_zbuf) { - BMesh *bm = vc->em->bm; - - if (!XRAY_FLAG_ENABLED(vc->v3d)) { - uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist); - unsigned int index; - BMEdge *eed; - - /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ - { - FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_EDGE); - ED_view3d_select_id_validate_with_select_mode(vc, select_mode); - - index = ED_view3d_select_id_read_nearest(vc, vc->mval, bm_solidoffs, bm_wireoffs, &dist_px); - eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL; - - FAKE_SELECT_MODE_END(vc, fake_select_mode); - } - - if (r_eed_zbuf) { - *r_eed_zbuf = eed; - } - - /* exception for faces (verts don't need this) */ - if (r_dist_center && eed) { - struct NearestEdgeUserData_ZBuf data; - - data.mval_fl[0] = vc->mval[0]; - data.mval_fl[1] = vc->mval[1]; - data.dist = FLT_MAX; - data.edge_test = eed; - - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - - mesh_foreachScreenEdge(vc, find_nearest_edge_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT); - - *r_dist_center = data.dist; - } - /* end exception */ - - if (eed) { - if (dist_px < *r_dist) { - *r_dist = dist_px; - return eed; - } - } - return NULL; - } - else { - struct NearestEdgeUserData data = {{0}}; - const struct NearestEdgeUserData_Hit *hit; - /* interpolate along the edge before doing a clipping plane test */ - const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; - - static int prev_select_index = 0; - static const BMEdge *prev_select_elem = NULL; - - if ((use_cycle == false) || - (prev_select_elem && (prev_select_elem != BM_edge_at_index_find_or_table(bm, prev_select_index)))) - { - prev_select_index = 0; - prev_select_elem = NULL; - } - - data.vc = *vc; - data.mval_fl[0] = vc->mval[0]; - data.mval_fl[1] = vc->mval[1]; - data.use_select_bias = use_select_bias; - data.use_cycle = use_cycle; - data.hit.dist = data.hit_cycle.dist = \ - data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; - data.cycle_index_prev = prev_select_index; - - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag); - - hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit; - *r_dist = hit->dist; - if (r_dist_center) { - *r_dist_center = hit->dist_center; - } - - prev_select_elem = hit->edge; - prev_select_index = hit->index; - - return hit->edge; - } + BMesh *bm = vc->em->bm; + + if (!XRAY_FLAG_ENABLED(vc->v3d)) { + uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist); + unsigned int index; + BMEdge *eed; + + /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ + { + FAKE_SELECT_MODE_BEGIN (vc, fake_select_mode, select_mode, SCE_SELECT_EDGE) + ; + ED_view3d_select_id_validate_with_select_mode(vc, select_mode); + + index = ED_view3d_select_id_read_nearest(vc, vc->mval, bm_solidoffs, bm_wireoffs, &dist_px); + eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL; + + FAKE_SELECT_MODE_END(vc, fake_select_mode); + } + + if (r_eed_zbuf) { + *r_eed_zbuf = eed; + } + + /* exception for faces (verts don't need this) */ + if (r_dist_center && eed) { + struct NearestEdgeUserData_ZBuf data; + + data.mval_fl[0] = vc->mval[0]; + data.mval_fl[1] = vc->mval[1]; + data.dist = FLT_MAX; + data.edge_test = eed; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + + mesh_foreachScreenEdge( + vc, find_nearest_edge_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + *r_dist_center = data.dist; + } + /* end exception */ + + if (eed) { + if (dist_px < *r_dist) { + *r_dist = dist_px; + return eed; + } + } + return NULL; + } + else { + struct NearestEdgeUserData data = {{0}}; + const struct NearestEdgeUserData_Hit *hit; + /* interpolate along the edge before doing a clipping plane test */ + const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; + + static int prev_select_index = 0; + static const BMEdge *prev_select_elem = NULL; + + if ((use_cycle == false) || + (prev_select_elem && + (prev_select_elem != BM_edge_at_index_find_or_table(bm, prev_select_index)))) { + prev_select_index = 0; + prev_select_elem = NULL; + } + + data.vc = *vc; + data.mval_fl[0] = vc->mval[0]; + data.mval_fl[1] = vc->mval[1]; + data.use_select_bias = use_select_bias; + data.use_cycle = use_cycle; + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; + data.cycle_index_prev = prev_select_index; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag); + + hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit; + *r_dist = hit->dist; + if (r_dist_center) { + *r_dist_center = hit->dist_center; + } + + prev_select_elem = hit->edge; + prev_select_index = hit->index; + + return hit->edge; + } } -BMEdge *EDBM_edge_find_nearest( - ViewContext *vc, float *r_dist) +BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *r_dist) { - return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL); + return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL); } /* find the distance to the face we already have */ struct NearestFaceUserData_ZBuf { - float mval_fl[2]; - float dist; - const BMFace *face_test; + float mval_fl[2]; + float dist; + const BMFace *face_test; }; -static void find_nearest_face_center__doZBuf(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index)) +static void find_nearest_face_center__doZBuf(void *userData, + BMFace *efa, + const float screen_co[2], + int UNUSED(index)) { - struct NearestFaceUserData_ZBuf *data = userData; + struct NearestFaceUserData_ZBuf *data = userData; - if (efa == data->face_test) { - const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co); + if (efa == data->face_test) { + const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co); - if (dist_test < data->dist) { - data->dist = dist_test; - } - } + if (dist_test < data->dist) { + data->dist = dist_test; + } + } } - struct NearestFaceUserData_Hit { - float dist; - float dist_bias; - int index; - BMFace *face; + float dist; + float dist_bias; + int index; + BMFace *face; }; struct NearestFaceUserData { - float mval_fl[2]; - bool use_select_bias; - bool use_cycle; - int cycle_index_prev; + float mval_fl[2]; + bool use_select_bias; + bool use_cycle; + int cycle_index_prev; - struct NearestFaceUserData_Hit hit; - struct NearestFaceUserData_Hit hit_cycle; + struct NearestFaceUserData_Hit hit; + struct NearestFaceUserData_Hit hit_cycle; }; -static void findnearestface__doClosest(void *userData, BMFace *efa, const float screen_co[2], int index) +static void findnearestface__doClosest(void *userData, + BMFace *efa, + const float screen_co[2], + int index) { - struct NearestFaceUserData *data = userData; - float dist_test, dist_test_bias; - - dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); - - if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - dist_test_bias += FIND_NEAR_SELECT_BIAS; - } - - if (dist_test_bias < data->hit.dist_bias) { - data->hit.dist_bias = dist_test_bias; - data->hit.dist = dist_test; - data->hit.index = index; - data->hit.face = efa; - } - - if (data->use_cycle) { - if ((data->hit_cycle.face == NULL) && - (index > data->cycle_index_prev) && - (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) - { - data->hit_cycle.dist_bias = dist_test_bias; - data->hit_cycle.dist = dist_test; - data->hit_cycle.index = index; - data->hit_cycle.face = efa; - } - } + struct NearestFaceUserData *data = userData; + float dist_test, dist_test_bias; + + dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); + + if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + dist_test_bias += FIND_NEAR_SELECT_BIAS; + } + + if (dist_test_bias < data->hit.dist_bias) { + data->hit.dist_bias = dist_test_bias; + data->hit.dist = dist_test; + data->hit.index = index; + data->hit.face = efa; + } + + if (data->use_cycle) { + if ((data->hit_cycle.face == NULL) && (index > data->cycle_index_prev) && + (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { + data->hit_cycle.dist_bias = dist_test_bias; + data->hit_cycle.dist = dist_test; + data->hit_cycle.index = index; + data->hit_cycle.face = efa; + } + } } - -BMFace *EDBM_face_find_nearest_ex( - ViewContext *vc, float *r_dist, - float *r_dist_center, - const bool use_select_bias, const bool use_cycle, - BMFace **r_efa_zbuf) +BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, + float *r_dist, + float *r_dist_center, + const bool use_select_bias, + const bool use_cycle, + BMFace **r_efa_zbuf) { - BMesh *bm = vc->em->bm; - - if (!XRAY_FLAG_ENABLED(vc->v3d)) { - float dist_test = 0.0f; - unsigned int index; - BMFace *efa; - - { - FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_FACE); - ED_view3d_select_id_validate_with_select_mode(vc, select_mode); - - index = ED_view3d_select_id_sample(vc, vc->mval[0], vc->mval[1]); - efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL; - - FAKE_SELECT_MODE_END(vc, fake_select_mode); - } - - if (r_efa_zbuf) { - *r_efa_zbuf = efa; - } - - /* exception for faces (verts don't need this) */ - if (r_dist_center && efa) { - struct NearestFaceUserData_ZBuf data; - - data.mval_fl[0] = vc->mval[0]; - data.mval_fl[1] = vc->mval[1]; - data.dist = FLT_MAX; - data.face_test = efa; - - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - - mesh_foreachScreenFace(vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT); - - *r_dist_center = data.dist; - } - /* end exception */ - - if (efa) { - if (dist_test < *r_dist) { - *r_dist = dist_test; - return efa; - } - } - return NULL; - } - else { - struct NearestFaceUserData data = {{0}}; - const struct NearestFaceUserData_Hit *hit; - const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; - - static int prev_select_index = 0; - static const BMFace *prev_select_elem = NULL; - - if ((use_cycle == false) || - (prev_select_elem && (prev_select_elem != BM_face_at_index_find_or_table(bm, prev_select_index)))) - { - prev_select_index = 0; - prev_select_elem = NULL; - } - - data.mval_fl[0] = vc->mval[0]; - data.mval_fl[1] = vc->mval[1]; - data.use_select_bias = use_select_bias; - data.use_cycle = use_cycle; - data.hit.dist = data.hit_cycle.dist = \ - data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; - data.cycle_index_prev = prev_select_index; - - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag); - - hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit; - *r_dist = hit->dist; - if (r_dist_center) { - *r_dist_center = hit->dist; - } - - prev_select_elem = hit->face; - prev_select_index = hit->index; - - return hit->face; - } + BMesh *bm = vc->em->bm; + + if (!XRAY_FLAG_ENABLED(vc->v3d)) { + float dist_test = 0.0f; + unsigned int index; + BMFace *efa; + + { + FAKE_SELECT_MODE_BEGIN (vc, fake_select_mode, select_mode, SCE_SELECT_FACE) + ; + ED_view3d_select_id_validate_with_select_mode(vc, select_mode); + + index = ED_view3d_select_id_sample(vc, vc->mval[0], vc->mval[1]); + efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL; + + FAKE_SELECT_MODE_END(vc, fake_select_mode); + } + + if (r_efa_zbuf) { + *r_efa_zbuf = efa; + } + + /* exception for faces (verts don't need this) */ + if (r_dist_center && efa) { + struct NearestFaceUserData_ZBuf data; + + data.mval_fl[0] = vc->mval[0]; + data.mval_fl[1] = vc->mval[1]; + data.dist = FLT_MAX; + data.face_test = efa; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + + mesh_foreachScreenFace( + vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + *r_dist_center = data.dist; + } + /* end exception */ + + if (efa) { + if (dist_test < *r_dist) { + *r_dist = dist_test; + return efa; + } + } + return NULL; + } + else { + struct NearestFaceUserData data = {{0}}; + const struct NearestFaceUserData_Hit *hit; + const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; + + static int prev_select_index = 0; + static const BMFace *prev_select_elem = NULL; + + if ((use_cycle == false) || + (prev_select_elem && + (prev_select_elem != BM_face_at_index_find_or_table(bm, prev_select_index)))) { + prev_select_index = 0; + prev_select_elem = NULL; + } + + data.mval_fl[0] = vc->mval[0]; + data.mval_fl[1] = vc->mval[1]; + data.use_select_bias = use_select_bias; + data.use_cycle = use_cycle; + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; + data.cycle_index_prev = prev_select_index; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag); + + hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit; + *r_dist = hit->dist; + if (r_dist_center) { + *r_dist_center = hit->dist; + } + + prev_select_elem = hit->face; + prev_select_index = hit->index; + + return hit->face; + } } BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist) { - return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL); + return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL); } #undef FIND_NEAR_SELECT_BIAS #undef FIND_NEAR_CYCLE_THRESHOLD_MIN - /* best distance based on screen coords. * use em->selectmode to define how to use * selected vertices and edges get disadvantage * return 1 if found one */ -static bool unified_findnearest( - ViewContext *vc, Base **bases, const uint bases_len, - int *r_base_index, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) +static bool unified_findnearest(ViewContext *vc, + Base **bases, + const uint bases_len, + int *r_base_index, + BMVert **r_eve, + BMEdge **r_eed, + BMFace **r_efa) { - BMEditMesh *em = vc->em; - static short mval_prev[2] = {-1, -1}; - /* only cycle while the mouse remains still */ - const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1])); - const float dist_init = ED_view3d_select_dist_px(); - /* since edges select lines, we give dots advantage of ~20 pix */ - const float dist_margin = (dist_init / 2); - float dist = dist_init; - - struct { - struct { - BMVert *ele; - int base_index; - } v; - struct { - BMEdge *ele; - int base_index; - } e, e_zbuf; - struct { - BMFace *ele; - int base_index; - } f, f_zbuf; - } hit = {{NULL}}; - - /* TODO(campbell): perform selection as one pass - * instead of many smaller passes (which doesn't work for zbuf occlusion). */ - - /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - - if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) { - float dist_center = 0.0f; - float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL; - - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - ED_view3d_viewcontext_init_object(vc, obedit); - BLI_assert(vc->em->selectmode == em->selectmode); - BMFace *efa_zbuf = NULL; - BMFace *efa_test = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf); - if (efa_test && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } - if (efa_test) { - hit.f.base_index = base_index; - hit.f.ele = efa_test; - } - if (efa_zbuf) { - hit.f_zbuf.base_index = base_index; - hit.f_zbuf.ele = efa_zbuf; - } - } /* bases */ - } - - if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) { - float dist_center = 0.0f; - float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL; - - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - ED_view3d_viewcontext_init_object(vc, obedit); - BMEdge *eed_zbuf = NULL; - BMEdge *eed_test = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf); - if (eed_test && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } - if (eed_test) { - hit.e.base_index = base_index; - hit.e.ele = eed_test; - } - if (eed_zbuf) { - hit.e_zbuf.base_index = base_index; - hit.e_zbuf.ele = eed_zbuf; - } - } /* bases */ - } - - if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) { - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - ED_view3d_viewcontext_init_object(vc, obedit); - BMVert *eve_test = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle); - if (eve_test) { - hit.v.base_index = base_index; - hit.v.ele = eve_test; - } - } /* bases */ - } - - /* return only one of 3 pointers, for frontbuffer redraws */ - if (hit.v.ele) { - hit.f.ele = NULL; - hit.e.ele = NULL; - } - else if (hit.e.ele) { - hit.f.ele = NULL; - } - - /* there may be a face under the cursor, who's center if too far away - * use this if all else fails, it makes sense to select this */ - if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) { - if (hit.e_zbuf.ele) { - hit.e.base_index = hit.e_zbuf.base_index; - hit.e.ele = hit.e_zbuf.ele; - } - else if (hit.f_zbuf.ele) { - hit.f.base_index = hit.f_zbuf.base_index; - hit.f.ele = hit.f_zbuf.ele; - } - } - - mval_prev[0] = vc->mval[0]; - mval_prev[1] = vc->mval[1]; - - /* Only one element type will be non-null. */ - BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1); - - if (hit.v.ele) { - *r_base_index = hit.v.base_index; - } - if (hit.e.ele) { - *r_base_index = hit.e.base_index; - } - if (hit.f.ele) { - *r_base_index = hit.f.base_index; - } - - *r_eve = hit.v.ele; - *r_eed = hit.e.ele; - *r_efa = hit.f.ele; - - return (hit.v.ele || hit.e.ele || hit.f.ele); + BMEditMesh *em = vc->em; + static short mval_prev[2] = {-1, -1}; + /* only cycle while the mouse remains still */ + const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1])); + const float dist_init = ED_view3d_select_dist_px(); + /* since edges select lines, we give dots advantage of ~20 pix */ + const float dist_margin = (dist_init / 2); + float dist = dist_init; + + struct { + struct { + BMVert *ele; + int base_index; + } v; + struct { + BMEdge *ele; + int base_index; + } e, e_zbuf; + struct { + BMFace *ele; + int base_index; + } f, f_zbuf; + } hit = {{NULL}}; + + /* TODO(campbell): perform selection as one pass + * instead of many smaller passes (which doesn't work for zbuf occlusion). */ + + /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ + + if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) { + float dist_center = 0.0f; + float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? + &dist_center : + NULL; + + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *obedit = base_iter->object; + ED_view3d_viewcontext_init_object(vc, obedit); + BLI_assert(vc->em->selectmode == em->selectmode); + BMFace *efa_zbuf = NULL; + BMFace *efa_test = EDBM_face_find_nearest_ex( + vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf); + if (efa_test && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (efa_test) { + hit.f.base_index = base_index; + hit.f.ele = efa_test; + } + if (efa_zbuf) { + hit.f_zbuf.base_index = base_index; + hit.f_zbuf.ele = efa_zbuf; + } + } /* bases */ + } + + if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) { + float dist_center = 0.0f; + float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL; + + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *obedit = base_iter->object; + ED_view3d_viewcontext_init_object(vc, obedit); + BMEdge *eed_zbuf = NULL; + BMEdge *eed_test = EDBM_edge_find_nearest_ex( + vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf); + if (eed_test && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (eed_test) { + hit.e.base_index = base_index; + hit.e.ele = eed_test; + } + if (eed_zbuf) { + hit.e_zbuf.base_index = base_index; + hit.e_zbuf.ele = eed_zbuf; + } + } /* bases */ + } + + if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) { + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *obedit = base_iter->object; + ED_view3d_viewcontext_init_object(vc, obedit); + BMVert *eve_test = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle); + if (eve_test) { + hit.v.base_index = base_index; + hit.v.ele = eve_test; + } + } /* bases */ + } + + /* return only one of 3 pointers, for frontbuffer redraws */ + if (hit.v.ele) { + hit.f.ele = NULL; + hit.e.ele = NULL; + } + else if (hit.e.ele) { + hit.f.ele = NULL; + } + + /* there may be a face under the cursor, who's center if too far away + * use this if all else fails, it makes sense to select this */ + if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) { + if (hit.e_zbuf.ele) { + hit.e.base_index = hit.e_zbuf.base_index; + hit.e.ele = hit.e_zbuf.ele; + } + else if (hit.f_zbuf.ele) { + hit.f.base_index = hit.f_zbuf.base_index; + hit.f.ele = hit.f_zbuf.ele; + } + } + + mval_prev[0] = vc->mval[0]; + mval_prev[1] = vc->mval[1]; + + /* Only one element type will be non-null. */ + BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1); + + if (hit.v.ele) { + *r_base_index = hit.v.base_index; + } + if (hit.e.ele) { + *r_base_index = hit.e.base_index; + } + if (hit.f.ele) { + *r_base_index = hit.f.base_index; + } + + *r_eve = hit.v.ele; + *r_eed = hit.e.ele; + *r_efa = hit.f.ele; + + return (hit.v.ele || hit.e.ele || hit.f.ele); } #undef FAKE_SELECT_MODE_BEGIN #undef FAKE_SELECT_MODE_END -bool EDBM_unified_findnearest( - ViewContext *vc, Base **bases, const uint bases_len, - int *r_base_index, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) +bool EDBM_unified_findnearest(ViewContext *vc, + Base **bases, + const uint bases_len, + int *r_base_index, + BMVert **r_eve, + BMEdge **r_eed, + BMFace **r_efa) { - return unified_findnearest(vc, bases, bases_len, r_base_index, r_eve, r_eed, r_efa); + return unified_findnearest(vc, bases, bases_len, r_base_index, r_eve, r_eed, r_efa); } /** \} */ @@ -1081,205 +1099,202 @@ bool EDBM_unified_findnearest( * currently used for poly-build. * \{ */ -bool EDBM_unified_findnearest_from_raycast( - ViewContext *vc, - Base **bases, const uint bases_len, - bool use_boundary, - int *r_base_index, - struct BMVert **r_eve, - struct BMEdge **r_eed, - struct BMFace **r_efa) +bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, + Base **bases, + const uint bases_len, + bool use_boundary, + int *r_base_index, + struct BMVert **r_eve, + struct BMEdge **r_eed, + struct BMFace **r_efa) { - const float mval_fl[2] = {UNPACK2(vc->mval)}; - float ray_origin[3], ray_direction[3]; - - struct { - uint base_index; - BMElem *ele; - } best = {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; - - const bool use_vert = (r_eve != NULL); - const bool use_edge = (r_eed != NULL); - const bool use_face = (r_efa != NULL); - - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - float imat3[3][3]; - - ED_view3d_viewcontext_init_object(vc, obedit); - copy_m3_m4(imat3, obedit->obmat); - invert_m3(imat3); - - const float (*coords)[3] = NULL; - { - Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, obedit->data); - if (me_eval->runtime.edit_data) { - coords = me_eval->runtime.edit_data->vertexCos; - } - } - - if (coords != NULL) { - BM_mesh_elem_index_ensure(bm, BM_VERT); - } - - if (use_boundary && (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) { - 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) { - dist_sq_best = dist_sq_test; - best.base_index = base_index; - best.ele = (BMElem *)v; - } - } - } - - if (use_edge) { - float point[3]; + const float mval_fl[2] = {UNPACK2(vc->mval)}; + float ray_origin[3], ray_direction[3]; + + struct { + uint base_index; + BMElem *ele; + } best = {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; + + const bool use_vert = (r_eve != NULL); + const bool use_edge = (r_eed != NULL); + const bool use_face = (r_efa != NULL); + + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *obedit = base_iter->object; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + float imat3[3][3]; + + ED_view3d_viewcontext_init_object(vc, obedit); + copy_m3_m4(imat3, obedit->obmat); + invert_m3(imat3); + + const float(*coords)[3] = NULL; + { + Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, obedit->data); + if (me_eval->runtime.edit_data) { + coords = me_eval->runtime.edit_data->vertexCos; + } + } + + if (coords != NULL) { + BM_mesh_elem_index_ensure(bm, BM_VERT); + } + + if (use_boundary && (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) { + 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) { + dist_sq_best = dist_sq_test; + best.base_index = base_index; + best.ele = (BMElem *)v; + } + } + } + + if (use_edge) { + float point[3]; #if 0 - const float dist_sq_test = dist_squared_ray_to_seg_v3( - ray_origin, ray_direction, - e->v1->co, e->v2->co, - point, &depth); + const float dist_sq_test = dist_squared_ray_to_seg_v3( + ray_origin, ray_direction, + e->v1->co, e->v2->co, + point, &depth); #else - 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 (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; + } #endif - } - } - } - } - 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; - } - } - } - } - 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_face) { - BMFace *f; - BMIter fiter; - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == false) { - float point[3]; - if (coords) { - BM_face_calc_center_median_vcos(bm, f, point, coords); - } - else { - BM_face_calc_center_median(f, point); - } - 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 *)f; - } - } - } - } - } - } - - *r_base_index = best.base_index; - if (r_eve) { - *r_eve = NULL; - } - if (r_eed) { - *r_eed = NULL; - } - if (r_efa) { - *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); - } - } - return (best.ele != NULL); + } + } + } + } + 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; + } + } + } + } + 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_face) { + BMFace *f; + BMIter fiter; + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == false) { + float point[3]; + if (coords) { + BM_face_calc_center_median_vcos(bm, f, point, coords); + } + else { + BM_face_calc_center_median(f, point); + } + 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 *)f; + } + } + } + } + } + } + + *r_base_index = best.base_index; + if (r_eve) { + *r_eve = NULL; + } + if (r_eed) { + *r_eed = NULL; + } + if (r_efa) { + *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); + } + } + return (best.ele != NULL); } /** \} */ @@ -1290,90 +1305,87 @@ bool EDBM_unified_findnearest_from_raycast( static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - bool changed = false; - - /* group vars */ - int *groups_array; - int (*group_index)[2]; - int group_tot; - int i; - - if (bm->totfacesel < 2) { - BKE_report(op->reports, RPT_ERROR, "No face regions selected"); - return OPERATOR_CANCELLED; - } - - groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); - group_tot = BM_mesh_calc_face_groups( - bm, groups_array, &group_index, - NULL, NULL, - BM_ELEM_SELECT, BM_VERT); - - BM_mesh_elem_table_ensure(bm, BM_FACE); - - for (i = 0; i < group_tot; i++) { - ListBase faces_regions; - int tot; - - const int fg_sta = group_index[i][0]; - const int fg_len = group_index[i][1]; - int j; - BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__); - - - for (j = 0; j < fg_len; j++) { - fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]); - } - - tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions); - - MEM_freeN(fg); - - if (tot) { - LinkData *link; - while ((link = BLI_pophead(&faces_regions))) { - BMFace *f, **faces = link->data; - while ((f = *(faces++))) { - BM_face_select_set(bm, f, true); - } - MEM_freeN(link->data); - MEM_freeN(link); - - changed = true; - } - } - } - - MEM_freeN(groups_array); - MEM_freeN(group_index); - - if (changed) { - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - else { - BKE_report(op->reports, RPT_WARNING, "No matching face regions found"); - } - - return OPERATOR_FINISHED; + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + bool changed = false; + + /* group vars */ + int *groups_array; + int(*group_index)[2]; + int group_tot; + int i; + + if (bm->totfacesel < 2) { + BKE_report(op->reports, RPT_ERROR, "No face regions selected"); + return OPERATOR_CANCELLED; + } + + groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); + group_tot = BM_mesh_calc_face_groups( + bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT); + + BM_mesh_elem_table_ensure(bm, BM_FACE); + + for (i = 0; i < group_tot; i++) { + ListBase faces_regions; + int tot; + + const int fg_sta = group_index[i][0]; + const int fg_len = group_index[i][1]; + int j; + BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__); + + for (j = 0; j < fg_len; j++) { + fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]); + } + + tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions); + + MEM_freeN(fg); + + if (tot) { + LinkData *link; + while ((link = BLI_pophead(&faces_regions))) { + BMFace *f, **faces = link->data; + while ((f = *(faces++))) { + BM_face_select_set(bm, f, true); + } + MEM_freeN(link->data); + MEM_freeN(link); + + changed = true; + } + } + } + + MEM_freeN(groups_array); + MEM_freeN(group_index); + + if (changed) { + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + else { + BKE_report(op->reports, RPT_WARNING, "No matching face regions found"); + } + + return OPERATOR_FINISHED; } void MESH_OT_select_similar_region(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Similar Regions"; - ot->idname = "MESH_OT_select_similar_region"; - ot->description = "Select similar face regions to the current selection"; + /* identifiers */ + ot->name = "Select Similar Regions"; + ot->idname = "MESH_OT_select_similar_region"; + ot->description = "Select similar face regions to the current selection"; - /* api callbacks */ - ot->exec = edbm_select_similar_region_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_select_similar_region_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -1384,85 +1396,86 @@ void MESH_OT_select_similar_region(wmOperatorType *ot) static int edbm_select_mode_exec(bContext *C, wmOperator *op) { - const int type = RNA_enum_get(op->ptr, "type"); - const int action = RNA_enum_get(op->ptr, "action"); - const bool use_extend = RNA_boolean_get(op->ptr, "use_extend"); - const bool use_expand = RNA_boolean_get(op->ptr, "use_expand"); - - if (EDBM_selectmode_toggle(C, type, action, use_extend, use_expand)) { - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + const int type = RNA_enum_get(op->ptr, "type"); + const int action = RNA_enum_get(op->ptr, "action"); + const bool use_extend = RNA_boolean_get(op->ptr, "use_extend"); + const bool use_expand = RNA_boolean_get(op->ptr, "use_expand"); + + if (EDBM_selectmode_toggle(C, type, action, use_extend, use_expand)) { + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - /* Bypass when in UV non sync-select mode, fall through to keymap that edits. */ - if (CTX_wm_space_image(C)) { - ToolSettings *ts = CTX_data_tool_settings(C); - if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { - return OPERATOR_PASS_THROUGH; - } - /* Bypass when no action is needed. */ - if (!RNA_struct_property_is_set(op->ptr, "type")) { - return OPERATOR_CANCELLED; - } - } - - /* detecting these options based on shift/ctrl here is weak, but it's done - * to make this work when clicking buttons or menus */ - if (!RNA_struct_property_is_set(op->ptr, "use_extend")) - RNA_boolean_set(op->ptr, "use_extend", event->shift); - if (!RNA_struct_property_is_set(op->ptr, "use_expand")) - RNA_boolean_set(op->ptr, "use_expand", event->ctrl); - - return edbm_select_mode_exec(C, op); + /* Bypass when in UV non sync-select mode, fall through to keymap that edits. */ + if (CTX_wm_space_image(C)) { + ToolSettings *ts = CTX_data_tool_settings(C); + if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { + return OPERATOR_PASS_THROUGH; + } + /* Bypass when no action is needed. */ + if (!RNA_struct_property_is_set(op->ptr, "type")) { + return OPERATOR_CANCELLED; + } + } + + /* detecting these options based on shift/ctrl here is weak, but it's done + * to make this work when clicking buttons or menus */ + if (!RNA_struct_property_is_set(op->ptr, "use_extend")) + RNA_boolean_set(op->ptr, "use_extend", event->shift); + if (!RNA_struct_property_is_set(op->ptr, "use_expand")) + RNA_boolean_set(op->ptr, "use_expand", event->ctrl); + + return edbm_select_mode_exec(C, op); } void MESH_OT_select_mode(wmOperatorType *ot) { - PropertyRNA *prop; - - static const EnumPropertyItem elem_items[] = { - {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertices", ""}, - {SCE_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edges", ""}, - {SCE_SELECT_FACE, "FACE", ICON_FACESEL, "Faces", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem actions_items[] = { - {0, "DISABLE", 0, "Disable", "Disable selected markers"}, - {1, "ENABLE", 0, "Enable", "Enable selected markers"}, - {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Select Mode"; - ot->idname = "MESH_OT_select_mode"; - ot->description = "Change selection mode"; - - /* api callbacks */ - ot->invoke = edbm_select_mode_invoke; - ot->exec = edbm_select_mode_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - /* Hide all, not to show redo panel. */ - prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - ot->prop = prop = RNA_def_enum(ot->srna, "type", elem_items, 0, "Type", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - - prop = RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + static const EnumPropertyItem elem_items[] = { + {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertices", ""}, + {SCE_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edges", ""}, + {SCE_SELECT_FACE, "FACE", ICON_FACESEL, "Faces", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem actions_items[] = { + {0, "DISABLE", 0, "Disable", "Disable selected markers"}, + {1, "ENABLE", 0, "Enable", "Enable selected markers"}, + {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Select Mode"; + ot->idname = "MESH_OT_select_mode"; + ot->description = "Change selection mode"; + + /* api callbacks */ + ot->invoke = edbm_select_mode_invoke; + ot->exec = edbm_select_mode_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + /* Hide all, not to show redo panel. */ + prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + ot->prop = prop = RNA_def_enum(ot->srna, "type", elem_items, 0, "Type", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_enum( + ot->srna, "action", actions_items, 2, "Action", "Selection action to execute"); + RNA_def_property_flag(prop, PROP_HIDDEN); } /** \} */ @@ -1471,132 +1484,145 @@ void MESH_OT_select_mode(wmOperatorType *ot) /** \name Select Loop (Non Modal) Operator * \{ */ -static void walker_select_count( - BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix, - int *r_totsel, int *r_totunsel) +static void walker_select_count(BMEditMesh *em, + int walkercode, + void *start, + const bool select, + const bool select_mix, + int *r_totsel, + int *r_totunsel) { - BMesh *bm = em->bm; - BMElem *ele; - BMWalker walker; - int tot[2] = {0, 0}; - - BMW_init(&walker, bm, walkercode, - BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) { - tot[(BM_elem_flag_test_bool(ele, BM_ELEM_SELECT) != select)] += 1; - - if (!select_mix && tot[0] && tot[1]) { - tot[0] = tot[1] = -1; - break; - } - } - - *r_totsel = tot[0]; - *r_totunsel = tot[1]; - - BMW_end(&walker); + BMesh *bm = em->bm; + BMElem *ele; + BMWalker walker; + int tot[2] = {0, 0}; + + BMW_init(&walker, + bm, + walkercode, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) { + tot[(BM_elem_flag_test_bool(ele, BM_ELEM_SELECT) != select)] += 1; + + if (!select_mix && tot[0] && tot[1]) { + tot[0] = tot[1] = -1; + break; + } + } + + *r_totsel = tot[0]; + *r_totunsel = tot[1]; + + BMW_end(&walker); } static void walker_select(BMEditMesh *em, int walkercode, void *start, const bool select) { - BMesh *bm = em->bm; - BMElem *ele; - BMWalker walker; - - BMW_init(&walker, bm, walkercode, - BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) { - if (!select) { - BM_select_history_remove(bm, ele); - } - BM_elem_select_set(bm, ele, select); - } - BMW_end(&walker); + BMesh *bm = em->bm; + BMElem *ele; + BMWalker walker; + + BMW_init(&walker, + bm, + walkercode, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) { + if (!select) { + BM_select_history_remove(bm, ele); + } + BM_elem_select_set(bm, ele, select); + } + BMW_end(&walker); } static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) { - const bool is_ring = RNA_boolean_get(op->ptr, "ring"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totedgesel == 0) { - continue; - } - - BMEdge *eed; - BMEdge **edarray; - int edindex; - BMIter iter; - int totedgesel = 0; - - BM_ITER_MESH(eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - totedgesel++; - } - } - - edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array"); - edindex = 0; - - BM_ITER_MESH(eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - edarray[edindex] = eed; - edindex++; - } - } - - if (is_ring) { - for (edindex = 0; edindex < totedgesel; edindex += 1) { - eed = edarray[edindex]; - walker_select(em, BMW_EDGERING, eed, true); - } - EDBM_selectmode_flush(em); - } - else { - for (edindex = 0; edindex < totedgesel; edindex += 1) { - eed = edarray[edindex]; - walker_select(em, BMW_EDGELOOP, eed, true); - } - EDBM_selectmode_flush(em); - } - MEM_freeN(edarray); - // if (EM_texFaceCheck()) - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const bool is_ring = RNA_boolean_get(op->ptr, "ring"); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totedgesel == 0) { + continue; + } + + BMEdge *eed; + BMEdge **edarray; + int edindex; + BMIter iter; + int totedgesel = 0; + + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + totedgesel++; + } + } + + edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array"); + edindex = 0; + + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + edarray[edindex] = eed; + edindex++; + } + } + + if (is_ring) { + for (edindex = 0; edindex < totedgesel; edindex += 1) { + eed = edarray[edindex]; + walker_select(em, BMW_EDGERING, eed, true); + } + EDBM_selectmode_flush(em); + } + else { + for (edindex = 0; edindex < totedgesel; edindex += 1) { + eed = edarray[edindex]; + walker_select(em, BMW_EDGELOOP, eed, true); + } + EDBM_selectmode_flush(em); + } + MEM_freeN(edarray); + // if (EM_texFaceCheck()) + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_loop_multi_select(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Multi Select Loops"; - ot->idname = "MESH_OT_loop_multi_select"; - ot->description = "Select a loop of connected edges by connection type"; + /* identifiers */ + ot->name = "Multi Select Loops"; + ot->idname = "MESH_OT_loop_multi_select"; + ot->description = "Select a loop of connected edges by connection type"; - /* api callbacks */ - ot->exec = edbm_loop_multiselect_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_loop_multiselect_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - RNA_def_boolean(ot->srna, "ring", 0, "Ring", ""); + /* properties */ + RNA_def_boolean(ot->srna, "ring", 0, "Ring", ""); } /** \} */ @@ -1607,285 +1633,281 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot) static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear) { - if (select_clear) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - } + if (select_clear) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } - walker_select(em, BMW_FACELOOP, eed, select); + walker_select(em, BMW_FACELOOP, eed, select); } static void mouse_mesh_loop_edge_ring(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear) { - if (select_clear) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - } + if (select_clear) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } - walker_select(em, BMW_EDGERING, eed, select); + walker_select(em, BMW_EDGERING, eed, select); } -static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear, bool select_cycle) +static void mouse_mesh_loop_edge( + BMEditMesh *em, BMEdge *eed, bool select, bool select_clear, bool select_cycle) { - bool edge_boundary = false; - - /* cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY */ - if (select_cycle && BM_edge_is_boundary(eed)) { - int tot[2]; - - /* if the loops selected toggle the boundaries */ - walker_select_count(em, BMW_EDGELOOP, eed, select, false, - &tot[0], &tot[1]); - if (tot[select] == 0) { - edge_boundary = true; - - /* if the boundaries selected, toggle back to the loop */ - walker_select_count(em, BMW_EDGEBOUNDARY, eed, select, false, - &tot[0], &tot[1]); - if (tot[select] == 0) { - edge_boundary = false; - } - } - } - - if (select_clear) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - } - - if (edge_boundary) { - walker_select(em, BMW_EDGEBOUNDARY, eed, select); - } - else { - walker_select(em, BMW_EDGELOOP, eed, select); - } + bool edge_boundary = false; + + /* cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY */ + if (select_cycle && BM_edge_is_boundary(eed)) { + int tot[2]; + + /* if the loops selected toggle the boundaries */ + walker_select_count(em, BMW_EDGELOOP, eed, select, false, &tot[0], &tot[1]); + if (tot[select] == 0) { + edge_boundary = true; + + /* if the boundaries selected, toggle back to the loop */ + walker_select_count(em, BMW_EDGEBOUNDARY, eed, select, false, &tot[0], &tot[1]); + if (tot[select] == 0) { + edge_boundary = false; + } + } + } + + if (select_clear) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } + + if (edge_boundary) { + walker_select(em, BMW_EDGEBOUNDARY, eed, select); + } + else { + walker_select(em, BMW_EDGELOOP, eed, select); + } } -static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring) +static bool mouse_mesh_loop( + bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring) { - Base *basact = NULL; - BMVert *eve = NULL; - BMEdge *eed = NULL; - BMFace *efa = NULL; - - ViewContext vc; - BMEditMesh *em; - bool select = true; - bool select_clear = false; - bool select_cycle = true; - float mvalf[2]; - - em_setup_viewcontext(C, &vc); - mvalf[0] = (float)(vc.mval[0] = mval[0]); - mvalf[1] = (float)(vc.mval[1] = mval[1]); - - BMEditMesh *em_original = vc.em; - const short selectmode = em_original->selectmode; - em_original->selectmode = SCE_SELECT_EDGE; - - uint bases_len; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); - - { - int base_index = -1; - if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) { - basact = bases[base_index]; - ED_view3d_viewcontext_init_object(&vc, basact->object); - em = vc.em; - } - else { - em = NULL; - } - } - - em_original->selectmode = selectmode; - - if (em == NULL || eed == NULL) { - MEM_freeN(bases); - return false; - } - - if (extend == false && deselect == false && toggle == false) { - select_clear = true; - } - - if (extend) { - select = true; - } - else if (deselect) { - select = false; - } - else if (select_clear || (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0)) { - select = true; - } - else if (toggle) { - select = false; - select_cycle = false; - } - - if (select_clear) { - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *ob_iter = base_iter->object; - BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); - - if (em_iter->bm->totvertsel == 0) { - continue; - } - - if (em_iter == em) { - continue; - } - - EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); - } - } - - if (em->selectmode & SCE_SELECT_FACE) { - mouse_mesh_loop_face(em, eed, select, select_clear); - } - else { - if (ring) { - mouse_mesh_loop_edge_ring(em, eed, select, select_clear); - } - else { - mouse_mesh_loop_edge(em, eed, select, select_clear, select_cycle); - } - } - - EDBM_selectmode_flush(em); - - /* sets as active, useful for other tools */ - if (select) { - if (em->selectmode & SCE_SELECT_VERTEX) { - /* Find nearest vert from mouse - * (initialize to large values in case only one vertex can be projected) */ - float v1_co[2], v2_co[2]; - float length_1 = FLT_MAX; - float length_2 = FLT_MAX; - - /* We can't be sure this has already been set... */ - ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - - if (ED_view3d_project_float_object( - vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) - { - length_1 = len_squared_v2v2(mvalf, v1_co); - } - - if (ED_view3d_project_float_object( - vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) - { - length_2 = len_squared_v2v2(mvalf, v2_co); - } + Base *basact = NULL; + BMVert *eve = NULL; + BMEdge *eed = NULL; + BMFace *efa = NULL; + + ViewContext vc; + BMEditMesh *em; + bool select = true; + bool select_clear = false; + bool select_cycle = true; + float mvalf[2]; + + em_setup_viewcontext(C, &vc); + mvalf[0] = (float)(vc.mval[0] = mval[0]); + mvalf[1] = (float)(vc.mval[1] = mval[1]); + + BMEditMesh *em_original = vc.em; + const short selectmode = em_original->selectmode; + em_original->selectmode = SCE_SELECT_EDGE; + + uint bases_len; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); + + { + int base_index = -1; + if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) { + basact = bases[base_index]; + ED_view3d_viewcontext_init_object(&vc, basact->object); + em = vc.em; + } + else { + em = NULL; + } + } + + em_original->selectmode = selectmode; + + if (em == NULL || eed == NULL) { + MEM_freeN(bases); + return false; + } + + if (extend == false && deselect == false && toggle == false) { + select_clear = true; + } + + if (extend) { + select = true; + } + else if (deselect) { + select = false; + } + else if (select_clear || (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0)) { + select = true; + } + else if (toggle) { + select = false; + select_cycle = false; + } + + if (select_clear) { + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *ob_iter = base_iter->object; + BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); + + if (em_iter->bm->totvertsel == 0) { + continue; + } + + if (em_iter == em) { + continue; + } + + EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); + DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + } + } + + if (em->selectmode & SCE_SELECT_FACE) { + mouse_mesh_loop_face(em, eed, select, select_clear); + } + else { + if (ring) { + mouse_mesh_loop_edge_ring(em, eed, select, select_clear); + } + else { + mouse_mesh_loop_edge(em, eed, select, select_clear, select_cycle); + } + } + + EDBM_selectmode_flush(em); + + /* sets as active, useful for other tools */ + if (select) { + if (em->selectmode & SCE_SELECT_VERTEX) { + /* Find nearest vert from mouse + * (initialize to large values in case only one vertex can be projected) */ + float v1_co[2], v2_co[2]; + float length_1 = FLT_MAX; + float length_2 = FLT_MAX; + + /* We can't be sure this has already been set... */ + ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); + + if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == + V3D_PROJ_RET_OK) { + length_1 = len_squared_v2v2(mvalf, v1_co); + } + + if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == + V3D_PROJ_RET_OK) { + length_2 = len_squared_v2v2(mvalf, v2_co); + } #if 0 - printf("mouse to v1: %f\nmouse to v2: %f\n", len_squared_v2v2(mvalf, v1_co), - len_squared_v2v2(mvalf, v2_co)); + printf("mouse to v1: %f\nmouse to v2: %f\n", len_squared_v2v2(mvalf, v1_co), + len_squared_v2v2(mvalf, v2_co)); #endif - BM_select_history_store(em->bm, (length_1 < length_2) ? eed->v1 : eed->v2); - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BM_select_history_store(em->bm, eed); - } - else if (em->selectmode & SCE_SELECT_FACE) { - /* Select the face of eed which is the nearest of mouse. */ - BMFace *f; - BMIter iterf; - float best_dist = FLT_MAX; - efa = NULL; - - /* We can't be sure this has already been set... */ - ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - - BM_ITER_ELEM (f, &iterf, eed, BM_FACES_OF_EDGE) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - float cent[3]; - float co[2], tdist; - - BM_face_calc_center_median(f, cent); - if (ED_view3d_project_float_object( - vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) - { - tdist = len_squared_v2v2(mvalf, co); - if (tdist < best_dist) { -/* printf("Best face: %p (%f)\n", f, tdist);*/ - best_dist = tdist; - efa = f; - } - } - } - } - if (efa) { - BM_mesh_active_face_set(em->bm, efa); - BM_select_history_store(em->bm, efa); - } - } - } - - MEM_freeN(bases); - - DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); - - return true; + BM_select_history_store(em->bm, (length_1 < length_2) ? eed->v1 : eed->v2); + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BM_select_history_store(em->bm, eed); + } + else if (em->selectmode & SCE_SELECT_FACE) { + /* Select the face of eed which is the nearest of mouse. */ + BMFace *f; + BMIter iterf; + float best_dist = FLT_MAX; + efa = NULL; + + /* We can't be sure this has already been set... */ + ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); + + BM_ITER_ELEM (f, &iterf, eed, BM_FACES_OF_EDGE) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + float cent[3]; + float co[2], tdist; + + BM_face_calc_center_median(f, cent); + if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == + V3D_PROJ_RET_OK) { + tdist = len_squared_v2v2(mvalf, co); + if (tdist < best_dist) { + /* printf("Best face: %p (%f)\n", f, tdist);*/ + best_dist = tdist; + efa = f; + } + } + } + } + if (efa) { + BM_mesh_active_face_set(em->bm, efa); + BM_select_history_store(em->bm, efa); + } + } + } + + MEM_freeN(bases); + + DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); + + return true; } static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - view3d_operator_needs_opengl(C); - - if (mouse_mesh_loop( - C, event->mval, - RNA_boolean_get(op->ptr, "extend"), - RNA_boolean_get(op->ptr, "deselect"), - RNA_boolean_get(op->ptr, "toggle"), - RNA_boolean_get(op->ptr, "ring"))) - { - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + view3d_operator_needs_opengl(C); + + if (mouse_mesh_loop(C, + event->mval, + RNA_boolean_get(op->ptr, "extend"), + RNA_boolean_get(op->ptr, "deselect"), + RNA_boolean_get(op->ptr, "toggle"), + RNA_boolean_get(op->ptr, "ring"))) { + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void MESH_OT_loop_select(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Loop Select"; - ot->idname = "MESH_OT_loop_select"; - ot->description = "Select a loop of connected edges"; - - /* api callbacks */ - ot->invoke = edbm_select_loop_invoke; - ot->poll = ED_operator_editmesh_region_view3d; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection"); - RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection"); - RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection"); - RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring"); + /* identifiers */ + ot->name = "Loop Select"; + ot->idname = "MESH_OT_loop_select"; + ot->description = "Select a loop of connected edges"; + + /* api callbacks */ + ot->invoke = edbm_select_loop_invoke; + ot->poll = ED_operator_editmesh_region_view3d; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection"); + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection"); + RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection"); + RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring"); } void MESH_OT_edgering_select(wmOperatorType *ot) { - /* description */ - ot->name = "Edge Ring Select"; - ot->idname = "MESH_OT_edgering_select"; - ot->description = "Select an edge ring"; - - /* callbacks */ - ot->invoke = edbm_select_loop_invoke; - ot->poll = ED_operator_editmesh_region_view3d; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); - RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection"); - RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection"); - RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring"); + /* description */ + ot->name = "Edge Ring Select"; + ot->idname = "MESH_OT_edgering_select"; + ot->description = "Select an edge ring"; + + /* callbacks */ + ot->invoke = edbm_select_loop_invoke; + ot->poll = ED_operator_editmesh_region_view3d; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection"); + RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection"); + RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring"); } /** \} */ @@ -1896,63 +1918,64 @@ void MESH_OT_edgering_select(wmOperatorType *ot) static int edbm_select_all_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - int action = RNA_enum_get(op->ptr, "action"); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - if (action == SEL_TOGGLE) { - action = SEL_SELECT; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) { - action = SEL_DESELECT; - break; - } - } - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - switch (action) { - case SEL_SELECT: - EDBM_flag_enable_all(em, BM_ELEM_SELECT); - break; - case SEL_DESELECT: - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - break; - case SEL_INVERT: - EDBM_select_swap(em); - EDBM_selectmode_flush(em); - break; - } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + int action = RNA_enum_get(op->ptr, "action"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + if (action == SEL_TOGGLE) { + action = SEL_SELECT; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) { + action = SEL_DESELECT; + break; + } + } + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + switch (action) { + case SEL_SELECT: + EDBM_flag_enable_all(em, BM_ELEM_SELECT); + break; + case SEL_DESELECT: + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + break; + case SEL_INVERT: + EDBM_select_swap(em); + EDBM_selectmode_flush(em); + break; + } + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_select_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "(De)select All"; - ot->idname = "MESH_OT_select_all"; - ot->description = "(De)select all vertices, edges or faces"; + /* identifiers */ + ot->name = "(De)select All"; + ot->idname = "MESH_OT_select_all"; + ot->description = "(De)select all vertices, edges or faces"; - /* api callbacks */ - ot->exec = edbm_select_all_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_select_all_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_select_all(ot); + WM_operator_properties_select_all(ot); } /** \} */ @@ -1963,39 +1986,40 @@ void MESH_OT_select_all(wmOperatorType *ot) static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op)) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (!EDBM_select_interior_faces(em)) { - continue; - } + if (!EDBM_select_interior_faces(em)) { + continue; + } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - MEM_freeN(objects); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_select_interior_faces(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Interior Faces"; - ot->idname = "MESH_OT_select_interior_faces"; - ot->description = "Select faces where all edges have more than 2 face users"; + /* identifiers */ + ot->name = "Select Interior Faces"; + ot->idname = "MESH_OT_select_interior_faces"; + ot->description = "Select faces where all edges have more than 2 face users"; - /* api callbacks */ - ot->exec = edbm_faces_select_interior_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_faces_select_interior_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -2009,163 +2033,162 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot) bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { - ViewContext vc; - - int base_index_active = -1; - BMVert *eve = NULL; - BMEdge *eed = NULL; - BMFace *efa = NULL; - - /* setup view context for argument to callbacks */ - em_setup_viewcontext(C, &vc); - vc.mval[0] = mval[0]; - vc.mval[1] = mval[1]; - - uint bases_len = 0; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); - - bool ok = false; - - if (unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa)) { - Base *basact = bases[base_index_active]; - ED_view3d_viewcontext_init_object(&vc, basact->object); - - /* Deselect everything */ - if (extend == false && deselect == false && toggle == false) { - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *ob_iter = base_iter->object; - EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT); - if (basact->object != ob_iter) { - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); - } - } - } - - if (efa) { - if (extend) { - /* set the last selected face */ - BM_mesh_active_face_set(vc.em->bm, efa); - - /* Work-around: deselect first, so we can guarantee it will */ - /* be active even if it was already selected */ - BM_select_history_remove(vc.em->bm, efa); - BM_face_select_set(vc.em->bm, efa, false); - BM_select_history_store(vc.em->bm, efa); - BM_face_select_set(vc.em->bm, efa, true); - } - else if (deselect) { - BM_select_history_remove(vc.em->bm, efa); - BM_face_select_set(vc.em->bm, efa, false); - } - else { - /* set the last selected face */ - BM_mesh_active_face_set(vc.em->bm, efa); - - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_select_history_store(vc.em->bm, efa); - BM_face_select_set(vc.em->bm, efa, true); - } - else if (toggle) { - BM_select_history_remove(vc.em->bm, efa); - BM_face_select_set(vc.em->bm, efa, false); - } - } - } - else if (eed) { - if (extend) { - /* Work-around: deselect first, so we can guarantee it will */ - /* be active even if it was already selected */ - BM_select_history_remove(vc.em->bm, eed); - BM_edge_select_set(vc.em->bm, eed, false); - BM_select_history_store(vc.em->bm, eed); - BM_edge_select_set(vc.em->bm, eed, true); - } - else if (deselect) { - BM_select_history_remove(vc.em->bm, eed); - BM_edge_select_set(vc.em->bm, eed, false); - } - else { - if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - BM_select_history_store(vc.em->bm, eed); - BM_edge_select_set(vc.em->bm, eed, true); - } - else if (toggle) { - BM_select_history_remove(vc.em->bm, eed); - BM_edge_select_set(vc.em->bm, eed, false); - } - } - } - else if (eve) { - if (extend) { - /* Work-around: deselect first, so we can guarantee it will */ - /* be active even if it was already selected */ - BM_select_history_remove(vc.em->bm, eve); - BM_vert_select_set(vc.em->bm, eve, false); - BM_select_history_store(vc.em->bm, eve); - BM_vert_select_set(vc.em->bm, eve, true); - } - else if (deselect) { - BM_select_history_remove(vc.em->bm, eve); - BM_vert_select_set(vc.em->bm, eve, false); - } - else { - if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - BM_select_history_store(vc.em->bm, eve); - BM_vert_select_set(vc.em->bm, eve, true); - } - else if (toggle) { - BM_select_history_remove(vc.em->bm, eve); - BM_vert_select_set(vc.em->bm, eve, false); - } - } - } - - EDBM_selectmode_flush(vc.em); - - if (efa) { - /* Change active material on object. */ - if (efa->mat_nr != vc.obedit->actcol - 1) { - vc.obedit->actcol = efa->mat_nr + 1; - vc.em->mat_nr = efa->mat_nr; - WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); - } - - /* Change active face-map on object. */ - if (!BLI_listbase_is_empty(&vc.obedit->fmaps)) { - const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP); - if (cd_fmap_offset != -1) { - int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset)); - if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) { - map = -1; - } - map += 1; - if (map != vc.obedit->actfmap) { - /* We may want to add notifiers later, - * currently select update handles redraw. */ - vc.obedit->actfmap = map; - } - } - } - - } - - /* Changing active object is handy since it allows us to - * switch UV layers, vgroups for eg. */ - if (vc.view_layer->basact != basact) { - ED_object_base_activate(C, basact); - } - - DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); - - ok = true; - } - - MEM_freeN(bases); - - return ok; + ViewContext vc; + + int base_index_active = -1; + BMVert *eve = NULL; + BMEdge *eed = NULL; + BMFace *efa = NULL; + + /* setup view context for argument to callbacks */ + em_setup_viewcontext(C, &vc); + vc.mval[0] = mval[0]; + vc.mval[1] = mval[1]; + + uint bases_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); + + bool ok = false; + + if (unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa)) { + Base *basact = bases[base_index_active]; + ED_view3d_viewcontext_init_object(&vc, basact->object); + + /* Deselect everything */ + if (extend == false && deselect == false && toggle == false) { + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *ob_iter = base_iter->object; + EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT); + if (basact->object != ob_iter) { + DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); + } + } + } + + if (efa) { + if (extend) { + /* set the last selected face */ + BM_mesh_active_face_set(vc.em->bm, efa); + + /* Work-around: deselect first, so we can guarantee it will */ + /* be active even if it was already selected */ + BM_select_history_remove(vc.em->bm, efa); + BM_face_select_set(vc.em->bm, efa, false); + BM_select_history_store(vc.em->bm, efa); + BM_face_select_set(vc.em->bm, efa, true); + } + else if (deselect) { + BM_select_history_remove(vc.em->bm, efa); + BM_face_select_set(vc.em->bm, efa, false); + } + else { + /* set the last selected face */ + BM_mesh_active_face_set(vc.em->bm, efa); + + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_select_history_store(vc.em->bm, efa); + BM_face_select_set(vc.em->bm, efa, true); + } + else if (toggle) { + BM_select_history_remove(vc.em->bm, efa); + BM_face_select_set(vc.em->bm, efa, false); + } + } + } + else if (eed) { + if (extend) { + /* Work-around: deselect first, so we can guarantee it will */ + /* be active even if it was already selected */ + BM_select_history_remove(vc.em->bm, eed); + BM_edge_select_set(vc.em->bm, eed, false); + BM_select_history_store(vc.em->bm, eed); + BM_edge_select_set(vc.em->bm, eed, true); + } + else if (deselect) { + BM_select_history_remove(vc.em->bm, eed); + BM_edge_select_set(vc.em->bm, eed, false); + } + else { + if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + BM_select_history_store(vc.em->bm, eed); + BM_edge_select_set(vc.em->bm, eed, true); + } + else if (toggle) { + BM_select_history_remove(vc.em->bm, eed); + BM_edge_select_set(vc.em->bm, eed, false); + } + } + } + else if (eve) { + if (extend) { + /* Work-around: deselect first, so we can guarantee it will */ + /* be active even if it was already selected */ + BM_select_history_remove(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, false); + BM_select_history_store(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, true); + } + else if (deselect) { + BM_select_history_remove(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, false); + } + else { + if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + BM_select_history_store(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, true); + } + else if (toggle) { + BM_select_history_remove(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, false); + } + } + } + + EDBM_selectmode_flush(vc.em); + + if (efa) { + /* Change active material on object. */ + if (efa->mat_nr != vc.obedit->actcol - 1) { + vc.obedit->actcol = efa->mat_nr + 1; + vc.em->mat_nr = efa->mat_nr; + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); + } + + /* Change active face-map on object. */ + if (!BLI_listbase_is_empty(&vc.obedit->fmaps)) { + const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP); + if (cd_fmap_offset != -1) { + int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset)); + if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) { + map = -1; + } + map += 1; + if (map != vc.obedit->actfmap) { + /* We may want to add notifiers later, + * currently select update handles redraw. */ + vc.obedit->actfmap = map; + } + } + } + } + + /* Changing active object is handy since it allows us to + * switch UV layers, vgroups for eg. */ + if (vc.view_layer->basact != basact) { + ED_object_base_activate(C, basact); + } + + DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); + + ok = true; + } + + MEM_freeN(bases); + + return ok; } /** \} */ @@ -2176,91 +2199,91 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect static void edbm_strip_selections(BMEditMesh *em) { - BMEditSelection *ese, *nextese; - - if (!(em->selectmode & SCE_SELECT_VERTEX)) { - ese = em->bm->selected.first; - while (ese) { - nextese = ese->next; - if (ese->htype == BM_VERT) BLI_freelinkN(&(em->bm->selected), ese); - ese = nextese; - } - } - if (!(em->selectmode & SCE_SELECT_EDGE)) { - ese = em->bm->selected.first; - while (ese) { - nextese = ese->next; - if (ese->htype == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese); - ese = nextese; - } - } - if (!(em->selectmode & SCE_SELECT_FACE)) { - ese = em->bm->selected.first; - while (ese) { - nextese = ese->next; - if (ese->htype == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese); - ese = nextese; - } - } + BMEditSelection *ese, *nextese; + + if (!(em->selectmode & SCE_SELECT_VERTEX)) { + ese = em->bm->selected.first; + while (ese) { + nextese = ese->next; + if (ese->htype == BM_VERT) + BLI_freelinkN(&(em->bm->selected), ese); + ese = nextese; + } + } + if (!(em->selectmode & SCE_SELECT_EDGE)) { + ese = em->bm->selected.first; + while (ese) { + nextese = ese->next; + if (ese->htype == BM_EDGE) + BLI_freelinkN(&(em->bm->selected), ese); + ese = nextese; + } + } + if (!(em->selectmode & SCE_SELECT_FACE)) { + ese = em->bm->selected.first; + while (ese) { + nextese = ese->next; + if (ese->htype == BM_FACE) + BLI_freelinkN(&(em->bm->selected), ese); + ese = nextese; + } + } } /* when switching select mode, makes sure selection is consistent for editing */ /* also for paranoia checks to make sure edge or face mode works */ void EDBM_selectmode_set(BMEditMesh *em) { - BMVert *eve; - BMEdge *eed; - BMFace *efa; - BMIter iter; - - em->bm->selectmode = em->selectmode; - - /* strip BMEditSelections from em->selected that are not relevant to new mode */ - edbm_strip_selections(em); - - if (em->bm->totvertsel == 0 && - em->bm->totedgesel == 0 && - em->bm->totfacesel == 0) - { - return; - } - - if (em->selectmode & SCE_SELECT_VERTEX) { - if (em->bm->totvertsel) { - EDBM_select_flush(em); - } - } - else if (em->selectmode & SCE_SELECT_EDGE) { - /* deselect vertices, and select again based on edge select */ - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - BM_vert_select_set(em->bm, eve, false); - } - - if (em->bm->totedgesel) { - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - BM_edge_select_set(em->bm, eed, true); - } - } - - /* selects faces based on edge status */ - EDBM_selectmode_flush(em); - } - } - else if (em->selectmode & SCE_SELECT_FACE) { - /* deselect eges, and select again based on face select */ - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_edge_select_set(em->bm, eed, false); - } - - if (em->bm->totfacesel) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_face_select_set(em->bm, efa, true); - } - } - } - } + BMVert *eve; + BMEdge *eed; + BMFace *efa; + BMIter iter; + + em->bm->selectmode = em->selectmode; + + /* strip BMEditSelections from em->selected that are not relevant to new mode */ + edbm_strip_selections(em); + + if (em->bm->totvertsel == 0 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) { + return; + } + + if (em->selectmode & SCE_SELECT_VERTEX) { + if (em->bm->totvertsel) { + EDBM_select_flush(em); + } + } + else if (em->selectmode & SCE_SELECT_EDGE) { + /* deselect vertices, and select again based on edge select */ + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + BM_vert_select_set(em->bm, eve, false); + } + + if (em->bm->totedgesel) { + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + BM_edge_select_set(em->bm, eed, true); + } + } + + /* selects faces based on edge status */ + EDBM_selectmode_flush(em); + } + } + else if (em->selectmode & SCE_SELECT_FACE) { + /* deselect eges, and select again based on face select */ + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_edge_select_set(em->bm, eed, false); + } + + if (em->bm->totfacesel) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_face_select_set(em->bm, efa, true); + } + } + } + } } /** @@ -2277,230 +2300,235 @@ void EDBM_selectmode_set(BMEditMesh *em) * - face -> vert * - edge -> vert */ -void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const short selectmode_new) +void EDBM_selectmode_convert(BMEditMesh *em, + const short selectmode_old, + const short selectmode_new) { - BMesh *bm = em->bm; - - BMVert *eve; - BMEdge *eed; - BMFace *efa; - BMIter iter; - - /* first tag-to-select, then select --- this avoids a feedback loop */ - - /* have to find out what the selectionmode was previously */ - if (selectmode_old == SCE_SELECT_VERTEX) { - if (bm->totvertsel == 0) { - /* pass */ - } - else if (selectmode_new == SCE_SELECT_EDGE) { - /* flush up (vert -> edge) */ - - /* select all edges associated with every selected vert */ - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(eed, BM_ELEM_TAG, BM_edge_is_any_vert_flag_test(eed, BM_ELEM_SELECT)); - } - - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { - BM_edge_select_set(bm, eed, true); - } - } - } - else if (selectmode_new == SCE_SELECT_FACE) { - /* flush up (vert -> face) */ - - /* select all faces associated with every selected vert */ - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_vert_flag_test(efa, BM_ELEM_SELECT)); - } - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - BM_face_select_set(bm, efa, true); - } - } - } - } - else if (selectmode_old == SCE_SELECT_EDGE) { - if (bm->totedgesel == 0) { - /* pass */ - } - else if (selectmode_new == SCE_SELECT_FACE) { - /* flush up (edge -> face) */ - - /* select all faces associated with every selected edge */ - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_edge_flag_test(efa, BM_ELEM_SELECT)); - } - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - BM_face_select_set(bm, efa, true); - } - } - } - else if (selectmode_new == SCE_SELECT_VERTEX) { - /* flush down (edge -> vert) */ - - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_vert_is_all_edge_flag_test(eve, BM_ELEM_SELECT, true)) { - BM_vert_select_set(bm, eve, false); - } - } - /* deselect edges without both verts selected */ - BM_mesh_deselect_flush(bm); - } - } - else if (selectmode_old == SCE_SELECT_FACE) { - if (bm->totfacesel == 0) { - /* pass */ - } - else if (selectmode_new == SCE_SELECT_EDGE) { - /* flush down (face -> edge) */ - - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - if (!BM_edge_is_all_face_flag_test(eed, BM_ELEM_SELECT, true)) { - BM_edge_select_set(bm, eed, false); - } - } - } - else if (selectmode_new == SCE_SELECT_VERTEX) { - /* flush down (face -> vert) */ - - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_vert_is_all_face_flag_test(eve, BM_ELEM_SELECT, true)) { - BM_vert_select_set(bm, eve, false); - } - } - /* deselect faces without verts selected */ - BM_mesh_deselect_flush(bm); - } - } + BMesh *bm = em->bm; + + BMVert *eve; + BMEdge *eed; + BMFace *efa; + BMIter iter; + + /* first tag-to-select, then select --- this avoids a feedback loop */ + + /* have to find out what the selectionmode was previously */ + if (selectmode_old == SCE_SELECT_VERTEX) { + if (bm->totvertsel == 0) { + /* pass */ + } + else if (selectmode_new == SCE_SELECT_EDGE) { + /* flush up (vert -> edge) */ + + /* select all edges associated with every selected vert */ + BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(eed, BM_ELEM_TAG, BM_edge_is_any_vert_flag_test(eed, BM_ELEM_SELECT)); + } + + BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { + BM_edge_select_set(bm, eed, true); + } + } + } + else if (selectmode_new == SCE_SELECT_FACE) { + /* flush up (vert -> face) */ + + /* select all faces associated with every selected vert */ + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_vert_flag_test(efa, BM_ELEM_SELECT)); + } + + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + BM_face_select_set(bm, efa, true); + } + } + } + } + else if (selectmode_old == SCE_SELECT_EDGE) { + if (bm->totedgesel == 0) { + /* pass */ + } + else if (selectmode_new == SCE_SELECT_FACE) { + /* flush up (edge -> face) */ + + /* select all faces associated with every selected edge */ + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_edge_flag_test(efa, BM_ELEM_SELECT)); + } + + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + BM_face_select_set(bm, efa, true); + } + } + } + else if (selectmode_new == SCE_SELECT_VERTEX) { + /* flush down (edge -> vert) */ + + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_vert_is_all_edge_flag_test(eve, BM_ELEM_SELECT, true)) { + BM_vert_select_set(bm, eve, false); + } + } + /* deselect edges without both verts selected */ + BM_mesh_deselect_flush(bm); + } + } + else if (selectmode_old == SCE_SELECT_FACE) { + if (bm->totfacesel == 0) { + /* pass */ + } + else if (selectmode_new == SCE_SELECT_EDGE) { + /* flush down (face -> edge) */ + + BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { + if (!BM_edge_is_all_face_flag_test(eed, BM_ELEM_SELECT, true)) { + BM_edge_select_set(bm, eed, false); + } + } + } + else if (selectmode_new == SCE_SELECT_VERTEX) { + /* flush down (face -> vert) */ + + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_vert_is_all_face_flag_test(eve, BM_ELEM_SELECT, true)) { + BM_vert_select_set(bm, eve, false); + } + } + /* deselect faces without verts selected */ + BM_mesh_deselect_flush(bm); + } + } } /* user facing function, does notification */ -bool EDBM_selectmode_toggle( - bContext *C, const short selectmode_new, - const int action, const bool use_extend, const bool use_expand) +bool EDBM_selectmode_toggle(bContext *C, + const short selectmode_new, + const int action, + const bool use_extend, + const bool use_expand) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - ToolSettings *ts = CTX_data_tool_settings(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = NULL; - bool ret = false; - - if (obedit && obedit->type == OB_MESH) { - em = BKE_editmesh_from_object(obedit); - } - - if (em == NULL) { - return ret; - } - - bool only_update = false; - switch (action) { - case -1: - /* already set */ - break; - case 0: /* disable */ - /* check we have something to do */ - if ((em->selectmode & selectmode_new) == 0) { - only_update = true; - break; - } - em->selectmode &= ~selectmode_new; - break; - case 1: /* enable */ - /* check we have something to do */ - if ((em->selectmode & selectmode_new) != 0) { - only_update = true; - break; - } - em->selectmode |= selectmode_new; - break; - case 2: /* toggle */ - /* can't disable this flag if its the only one set */ - if (em->selectmode == selectmode_new) { - only_update = true; - break; - } - em->selectmode ^= selectmode_new; - break; - default: - BLI_assert(0); - break; - } - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; - BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); - if (em_iter != em) { - em_iter->selectmode = em->selectmode; - } - } - - if (only_update) { - MEM_freeN(objects); - return false; - } - - if (use_extend == 0 || em->selectmode == 0) { - if (use_expand) { - const short selmode_max = highest_order_bit_s(ts->selectmode); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; - BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); - EDBM_selectmode_convert(em_iter, selmode_max, selectmode_new); - } - } - } - - switch (selectmode_new) { - case SCE_SELECT_VERTEX: - if (use_extend == 0 || em->selectmode == 0) { - em->selectmode = SCE_SELECT_VERTEX; - } - ret = true; - break; - case SCE_SELECT_EDGE: - if (use_extend == 0 || em->selectmode == 0) { - em->selectmode = SCE_SELECT_EDGE; - } - ret = true; - break; - case SCE_SELECT_FACE: - if (use_extend == 0 || em->selectmode == 0) { - em->selectmode = SCE_SELECT_FACE; - } - ret = true; - break; - default: - BLI_assert(0); - break; - } - - if (ret == true) { - ts->selectmode = em->selectmode; - em = NULL; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; - BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); - em_iter->selectmode = ts->selectmode; - EDBM_selectmode_set(em_iter); - DEG_id_tag_update(ob_iter->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); - } - WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - } - - MEM_freeN(objects); - return ret; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = NULL; + bool ret = false; + + if (obedit && obedit->type == OB_MESH) { + em = BKE_editmesh_from_object(obedit); + } + + if (em == NULL) { + return ret; + } + + bool only_update = false; + switch (action) { + case -1: + /* already set */ + break; + case 0: /* disable */ + /* check we have something to do */ + if ((em->selectmode & selectmode_new) == 0) { + only_update = true; + break; + } + em->selectmode &= ~selectmode_new; + break; + case 1: /* enable */ + /* check we have something to do */ + if ((em->selectmode & selectmode_new) != 0) { + only_update = true; + break; + } + em->selectmode |= selectmode_new; + break; + case 2: /* toggle */ + /* can't disable this flag if its the only one set */ + if (em->selectmode == selectmode_new) { + only_update = true; + break; + } + em->selectmode ^= selectmode_new; + break; + default: + BLI_assert(0); + break; + } + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); + if (em_iter != em) { + em_iter->selectmode = em->selectmode; + } + } + + if (only_update) { + MEM_freeN(objects); + return false; + } + + if (use_extend == 0 || em->selectmode == 0) { + if (use_expand) { + const short selmode_max = highest_order_bit_s(ts->selectmode); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); + EDBM_selectmode_convert(em_iter, selmode_max, selectmode_new); + } + } + } + + switch (selectmode_new) { + case SCE_SELECT_VERTEX: + if (use_extend == 0 || em->selectmode == 0) { + em->selectmode = SCE_SELECT_VERTEX; + } + ret = true; + break; + case SCE_SELECT_EDGE: + if (use_extend == 0 || em->selectmode == 0) { + em->selectmode = SCE_SELECT_EDGE; + } + ret = true; + break; + case SCE_SELECT_FACE: + if (use_extend == 0 || em->selectmode == 0) { + em->selectmode = SCE_SELECT_FACE; + } + ret = true; + break; + default: + BLI_assert(0); + break; + } + + if (ret == true) { + ts->selectmode = em->selectmode; + em = NULL; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); + em_iter->selectmode = ts->selectmode; + EDBM_selectmode_set(em_iter); + DEG_id_tag_update(ob_iter->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); + } + WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + } + + MEM_freeN(objects); + return ret; } /** @@ -2509,30 +2537,30 @@ bool EDBM_selectmode_toggle( * * \return true if the mode is changed. */ -bool EDBM_selectmode_disable( - Scene *scene, BMEditMesh *em, - const short selectmode_disable, - const short selectmode_fallback) +bool EDBM_selectmode_disable(Scene *scene, + BMEditMesh *em, + const short selectmode_disable, + const short selectmode_fallback) { - /* note essential, but switch out of vertex mode since the - * selected regions wont be nicely isolated after flushing */ - if (em->selectmode & selectmode_disable) { - if (em->selectmode == selectmode_disable) { - em->selectmode = selectmode_fallback; - } - else { - em->selectmode &= ~selectmode_disable; - } - scene->toolsettings->selectmode = em->selectmode; - EDBM_selectmode_set(em); - - WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene); - - return true; - } - else { - return false; - } + /* note essential, but switch out of vertex mode since the + * selected regions wont be nicely isolated after flushing */ + if (em->selectmode & selectmode_disable) { + if (em->selectmode == selectmode_disable) { + em->selectmode = selectmode_fallback; + } + else { + em->selectmode &= ~selectmode_disable; + } + scene->toolsettings->selectmode = em->selectmode; + EDBM_selectmode_set(em); + + WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene); + + return true; + } + else { + return false; + } } /** \} */ @@ -2543,88 +2571,88 @@ bool EDBM_selectmode_disable( bool EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select) { - BMIter iter; - BMFace *efa; - bool changed = false; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) - continue; - if (efa->mat_nr == index) { - changed = true; - BM_face_select_set(em->bm, efa, select); - } - } - return changed; + BMIter iter; + BMFace *efa; + bool changed = false; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) + continue; + if (efa->mat_nr == index) { + changed = true; + BM_face_select_set(em->bm, efa, select); + } + } + return changed; } void EDBM_select_toggle_all(BMEditMesh *em) /* exported for UV */ { - if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - else - EDBM_flag_enable_all(em, BM_ELEM_SELECT); + if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + else + EDBM_flag_enable_all(em, BM_ELEM_SELECT); } void EDBM_select_swap(BMEditMesh *em) /* exported for UV */ { - BMIter iter; - BMVert *eve; - BMEdge *eed; - BMFace *efa; - - if (em->bm->selectmode & SCE_SELECT_VERTEX) { - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) - continue; - BM_vert_select_set(em->bm, eve, !BM_elem_flag_test(eve, BM_ELEM_SELECT)); - } - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) - continue; - BM_edge_select_set(em->bm, eed, !BM_elem_flag_test(eed, BM_ELEM_SELECT)); - } - } - else { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) - continue; - BM_face_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT)); - } - - } + BMIter iter; + BMVert *eve; + BMEdge *eed; + BMFace *efa; + + if (em->bm->selectmode & SCE_SELECT_VERTEX) { + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) + continue; + BM_vert_select_set(em->bm, eve, !BM_elem_flag_test(eve, BM_ELEM_SELECT)); + } + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) + continue; + BM_edge_select_set(em->bm, eed, !BM_elem_flag_test(eed, BM_ELEM_SELECT)); + } + } + else { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) + continue; + BM_face_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT)); + } + } } bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len) { - bool changed_multi = false; - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *ob_iter = base_iter->object; - BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); - - if (em_iter->bm->totvertsel == 0) { - continue; - } - - EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); - changed_multi = true; - } - return changed_multi; + bool changed_multi = false; + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *ob_iter = base_iter->object; + BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); + + if (em_iter->bm->totvertsel == 0) { + continue; + } + + EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); + DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + changed_multi = true; + } + return changed_multi; } bool EDBM_mesh_deselect_all_multi(struct bContext *C) { - ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); - uint bases_len = 0; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &bases_len); - bool changed_multi = EDBM_mesh_deselect_all_multi_ex(bases, bases_len); - MEM_freeN(bases); - return changed_multi; + ViewContext vc; + ED_view3d_viewcontext_init(C, &vc); + uint bases_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + vc.view_layer, vc.v3d, &bases_len); + bool changed_multi = EDBM_mesh_deselect_all_multi_ex(bases, bases_len); + MEM_freeN(bases); + return changed_multi; } /** \} */ @@ -2638,34 +2666,33 @@ bool EDBM_mesh_deselect_all_multi(struct bContext *C) bool EDBM_select_interior_faces(BMEditMesh *em) { - BMesh *bm = em->bm; - BMIter iter; - BMIter eiter; - BMFace *efa; - BMEdge *eed; - bool ok; - bool changed = false; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) - continue; - - - ok = true; - BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) { - if (!BM_edge_face_count_is_over(eed, 2)) { - ok = false; - break; - } - } - - if (ok) { - BM_face_select_set(bm, efa, true); - changed = true; - } - } - - return changed; + BMesh *bm = em->bm; + BMIter iter; + BMIter eiter; + BMFace *efa; + BMEdge *eed; + bool ok; + bool changed = false; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) + continue; + + ok = true; + BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) { + if (!BM_edge_face_count_is_over(eed, 2)) { + ok = false; + break; + } + } + + if (ok) { + BM_face_select_set(bm, efa, true); + changed = true; + } + } + + return changed; } /** \} */ @@ -2680,53 +2707,54 @@ bool EDBM_select_interior_faces(BMEditMesh *em) #define USE_LINKED_SELECT_DEFAULT_HACK struct DelimitData { - int cd_loop_type; - int cd_loop_offset; + int cd_loop_type; + int cd_loop_offset; }; -static bool select_linked_delimit_test( - BMEdge *e, int delimit, - const struct DelimitData *delimit_data) +static bool select_linked_delimit_test(BMEdge *e, + int delimit, + const struct DelimitData *delimit_data) { - BLI_assert(delimit); - - if (delimit & BMO_DELIM_SEAM) { - if (BM_elem_flag_test(e, BM_ELEM_SEAM)) { - return true; - } - } - - if (delimit & BMO_DELIM_SHARP) { - if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) { - return true; - } - } - - if (delimit & BMO_DELIM_NORMAL) { - if (!BM_edge_is_contiguous(e)) { - return true; - } - } - - if (delimit & BMO_DELIM_MATERIAL) { - if (e->l && e->l->radial_next != e->l) { - const short mat_nr = e->l->f->mat_nr; - BMLoop *l_iter = e->l->radial_next; - do { - if (l_iter->f->mat_nr != mat_nr) { - return true; - } - } while ((l_iter = l_iter->radial_next) != e->l); - } - } - - if (delimit & BMO_DELIM_UV) { - if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, delimit_data->cd_loop_offset) == 0) { - return true; - } - } - - return false; + BLI_assert(delimit); + + if (delimit & BMO_DELIM_SEAM) { + if (BM_elem_flag_test(e, BM_ELEM_SEAM)) { + return true; + } + } + + if (delimit & BMO_DELIM_SHARP) { + if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) { + return true; + } + } + + if (delimit & BMO_DELIM_NORMAL) { + if (!BM_edge_is_contiguous(e)) { + return true; + } + } + + if (delimit & BMO_DELIM_MATERIAL) { + if (e->l && e->l->radial_next != e->l) { + const short mat_nr = e->l->f->mat_nr; + BMLoop *l_iter = e->l->radial_next; + do { + if (l_iter->f->mat_nr != mat_nr) { + return true; + } + } while ((l_iter = l_iter->radial_next) != e->l); + } + } + + if (delimit & BMO_DELIM_UV) { + if (BM_edge_is_contiguous_loop_cd( + e, delimit_data->cd_loop_type, delimit_data->cd_loop_offset) == 0) { + return true; + } + } + + return false; } #ifdef USE_LINKED_SELECT_DEFAULT_HACK @@ -2736,277 +2764,294 @@ static bool select_linked_delimit_test( */ static int select_linked_delimit_default_from_op(wmOperator *op, const int select_mode) { - static char delimit_last_store[2] = {0, BMO_DELIM_SEAM}; - int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0; - char *delimit_last = &delimit_last_store[delimit_last_index]; - PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit"); - int delimit; - - if (RNA_property_is_set(op->ptr, prop_delimit)) { - delimit = RNA_property_enum_get(op->ptr, prop_delimit); - *delimit_last = delimit; - } - else { - delimit = *delimit_last; - RNA_property_enum_set(op->ptr, prop_delimit, delimit); - } - return delimit; + static char delimit_last_store[2] = {0, BMO_DELIM_SEAM}; + int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0; + char *delimit_last = &delimit_last_store[delimit_last_index]; + PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit"); + int delimit; + + if (RNA_property_is_set(op->ptr, prop_delimit)) { + delimit = RNA_property_enum_get(op->ptr, prop_delimit); + *delimit_last = delimit; + } + else { + delimit = *delimit_last; + RNA_property_enum_set(op->ptr, prop_delimit, delimit); + } + return delimit; } #endif static void select_linked_delimit_validate(BMesh *bm, int *delimit) { - if ((*delimit) & BMO_DELIM_UV) { - if (!CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) { - (*delimit) &= ~BMO_DELIM_UV; - } - } + if ((*delimit) & BMO_DELIM_UV) { + if (!CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) { + (*delimit) &= ~BMO_DELIM_UV; + } + } } static void select_linked_delimit_begin(BMesh *bm, int delimit) { - struct DelimitData delimit_data = {0}; - - if (delimit & BMO_DELIM_UV) { - delimit_data.cd_loop_type = CD_MLOOPUV; - delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type); - if (delimit_data.cd_loop_offset == -1) { - delimit &= ~BMO_DELIM_UV; - } - } - - /* grr, shouldn't need to alloc BMO flags here */ - BM_mesh_elem_toolflags_ensure(bm); - - { - BMIter iter; - BMEdge *e; - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - const bool is_walk_ok = ( - (select_linked_delimit_test(e, delimit, &delimit_data) == false)); - - BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok); - } - } + struct DelimitData delimit_data = {0}; + + if (delimit & BMO_DELIM_UV) { + delimit_data.cd_loop_type = CD_MLOOPUV; + delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type); + if (delimit_data.cd_loop_offset == -1) { + delimit &= ~BMO_DELIM_UV; + } + } + + /* grr, shouldn't need to alloc BMO flags here */ + BM_mesh_elem_toolflags_ensure(bm); + + { + BMIter iter; + BMEdge *e; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + const bool is_walk_ok = ((select_linked_delimit_test(e, delimit, &delimit_data) == false)); + + BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok); + } + } } static void select_linked_delimit_end(BMEditMesh *em) { - BMesh *bm = em->bm; + BMesh *bm = em->bm; - BM_mesh_elem_toolflags_clear(bm); + BM_mesh_elem_toolflags_clear(bm); } static int edbm_select_linked_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); #ifdef USE_LINKED_SELECT_DEFAULT_HACK - const int delimit_init = select_linked_delimit_default_from_op(op, scene->toolsettings->selectmode); + const int delimit_init = select_linked_delimit_default_from_op(op, + scene->toolsettings->selectmode); #else - const int delimit_init = RNA_enum_get(op->ptr, "delimit"); + const int delimit_init = RNA_enum_get(op->ptr, "delimit"); #endif - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter; - BMWalker walker; - - int delimit = delimit_init; - - select_linked_delimit_validate(bm, &delimit); - - if (delimit) { - select_linked_delimit_begin(em->bm, delimit); - } - - if (em->selectmode & SCE_SELECT_VERTEX) { - BMVert *v; - - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT)); - } - - /* exclude all delimited verts */ - if (delimit) { - BMEdge *e; - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) { - BM_elem_flag_disable(e->v1, BM_ELEM_TAG); - BM_elem_flag_disable(e->v2, BM_ELEM_TAG); - } - } - } - - BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, - BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - if (delimit) { - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - BMElem *ele_walk; - BMW_ITER (ele_walk, &walker, v) { - if (ele_walk->head.htype == BM_LOOP) { - BMVert *v_step = ((BMLoop *)ele_walk)->v; - BM_vert_select_set(em->bm, v_step, true); - BM_elem_flag_disable(v_step, BM_ELEM_TAG); - } - else { - BMEdge *e_step = (BMEdge *)ele_walk; - BLI_assert(ele_walk->head.htype == BM_EDGE); - BM_edge_select_set(em->bm, e_step, true); - BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG); - BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG); - } - } - } - } - } - else { - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - BMEdge *e_walk; - BMW_ITER (e_walk, &walker, v) { - BM_edge_select_set(em->bm, e_walk, true); - BM_elem_flag_disable(e_walk, BM_ELEM_TAG); - } - } - } - } - - BMW_end(&walker); - - EDBM_selectmode_flush(em); - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *e; - - if (delimit) { - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set( - e, BM_ELEM_TAG, - (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG))); - } - } - else { - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); - } - } - - BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, - BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - if (delimit) { - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BMElem *ele_walk; - BMW_ITER (ele_walk, &walker, e) { - if (ele_walk->head.htype == BM_LOOP) { - BMLoop *l_step = (BMLoop *)ele_walk; - BM_edge_select_set(em->bm, l_step->e, true); - BM_edge_select_set(em->bm, l_step->prev->e, true); - BM_elem_flag_disable(l_step->e, BM_ELEM_TAG); - } - else { - BMEdge *e_step = (BMEdge *)ele_walk; - BLI_assert(ele_walk->head.htype == BM_EDGE); - BM_edge_select_set(em->bm, e_step, true); - BM_elem_flag_disable(e_step, BM_ELEM_TAG); - } - } - } - } - } - else { - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BMEdge *e_walk; - BMW_ITER (e_walk, &walker, e) { - BM_edge_select_set(em->bm, e_walk, true); - BM_elem_flag_disable(e_walk, BM_ELEM_TAG); - } - } - } - } - - BMW_end(&walker); - - EDBM_selectmode_flush(em); - } - else { - BMFace *f; - - BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT)); - } - - BMW_init(&walker, bm, BMW_ISLAND, - BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_TAG)) { - BMFace *f_walk; - BMW_ITER (f_walk, &walker, f) { - BM_face_select_set(bm, f_walk, true); - BM_elem_flag_disable(f_walk, BM_ELEM_TAG); - } - } - } - - BMW_end(&walker); - } - - if (delimit) { - select_linked_delimit_end(em); - } - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter iter; + BMWalker walker; + + int delimit = delimit_init; + + select_linked_delimit_validate(bm, &delimit); + + if (delimit) { + select_linked_delimit_begin(em->bm, delimit); + } + + if (em->selectmode & SCE_SELECT_VERTEX) { + BMVert *v; + + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT)); + } + + /* exclude all delimited verts */ + if (delimit) { + BMEdge *e; + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) { + BM_elem_flag_disable(e->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e->v2, BM_ELEM_TAG); + } + } + } + + BMW_init(&walker, + em->bm, + delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, + BMW_MASK_NOP, + delimit ? BMO_ELE_TAG : BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + if (delimit) { + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + BMElem *ele_walk; + BMW_ITER (ele_walk, &walker, v) { + if (ele_walk->head.htype == BM_LOOP) { + BMVert *v_step = ((BMLoop *)ele_walk)->v; + BM_vert_select_set(em->bm, v_step, true); + BM_elem_flag_disable(v_step, BM_ELEM_TAG); + } + else { + BMEdge *e_step = (BMEdge *)ele_walk; + BLI_assert(ele_walk->head.htype == BM_EDGE); + BM_edge_select_set(em->bm, e_step, true); + BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG); + } + } + } + } + } + else { + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + BMEdge *e_walk; + BMW_ITER (e_walk, &walker, v) { + BM_edge_select_set(em->bm, e_walk, true); + BM_elem_flag_disable(e_walk, BM_ELEM_TAG); + } + } + } + } + + BMW_end(&walker); + + EDBM_selectmode_flush(em); + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BMEdge *e; + + if (delimit) { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set( + e, + BM_ELEM_TAG, + (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG))); + } + } + else { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + } + } + + BMW_init(&walker, + em->bm, + delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, + BMW_MASK_NOP, + delimit ? BMO_ELE_TAG : BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + if (delimit) { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BMElem *ele_walk; + BMW_ITER (ele_walk, &walker, e) { + if (ele_walk->head.htype == BM_LOOP) { + BMLoop *l_step = (BMLoop *)ele_walk; + BM_edge_select_set(em->bm, l_step->e, true); + BM_edge_select_set(em->bm, l_step->prev->e, true); + BM_elem_flag_disable(l_step->e, BM_ELEM_TAG); + } + else { + BMEdge *e_step = (BMEdge *)ele_walk; + BLI_assert(ele_walk->head.htype == BM_EDGE); + BM_edge_select_set(em->bm, e_step, true); + BM_elem_flag_disable(e_step, BM_ELEM_TAG); + } + } + } + } + } + else { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BMEdge *e_walk; + BMW_ITER (e_walk, &walker, e) { + BM_edge_select_set(em->bm, e_walk, true); + BM_elem_flag_disable(e_walk, BM_ELEM_TAG); + } + } + } + } + + BMW_end(&walker); + + EDBM_selectmode_flush(em); + } + else { + BMFace *f; + + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT)); + } + + BMW_init(&walker, + bm, + BMW_ISLAND, + BMW_MASK_NOP, + delimit ? BMO_ELE_TAG : BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG)) { + BMFace *f_walk; + BMW_ITER (f_walk, &walker, f) { + BM_face_select_set(bm, f_walk, true); + BM_elem_flag_disable(f_walk, BM_ELEM_TAG); + } + } + } + + BMW_end(&walker); + } + + if (delimit) { + select_linked_delimit_end(em); + } + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_select_linked(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Select Linked All"; - ot->idname = "MESH_OT_select_linked"; - ot->description = "Select all vertices connected to the current selection"; - - /* api callbacks */ - ot->exec = edbm_select_linked_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit", - "Delimit selected region"); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Select Linked All"; + ot->idname = "MESH_OT_select_linked"; + ot->description = "Select all vertices connected to the current selection"; + + /* api callbacks */ + ot->exec = edbm_select_linked_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_enum_flag(ot->srna, + "delimit", + rna_enum_mesh_delimit_mode_items, + BMO_DELIM_SEAM, + "Delimit", + "Delimit selected region"); #ifdef USE_LINKED_SELECT_DEFAULT_HACK - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); #else - UNUSED_VARS(prop); + UNUSED_VARS(prop); #endif } @@ -3020,245 +3065,260 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op); static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit) { - BMesh *bm = em->bm; - BMWalker walker; - - select_linked_delimit_validate(bm, &delimit); - - if (delimit) { - select_linked_delimit_begin(bm, delimit); - } - - /* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */ - - if (ele->head.htype == BM_VERT) { - BMVert *eve = (BMVert *)ele; - - BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, - BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - if (delimit) { - BMElem *ele_walk; - BMW_ITER (ele_walk, &walker, eve) { - if (ele_walk->head.htype == BM_LOOP) { - BMVert *v_step = ((BMLoop *)ele_walk)->v; - BM_vert_select_set(bm, v_step, sel); - } - else { - BMEdge *e_step = (BMEdge *)ele_walk; - BLI_assert(ele_walk->head.htype == BM_EDGE); - BM_edge_select_set(bm, e_step, sel); - } - } - } - else { - BMEdge *e_walk; - BMW_ITER (e_walk, &walker, eve) { - BM_edge_select_set(bm, e_walk, sel); - } - } - - BMW_end(&walker); - - EDBM_selectmode_flush(em); - } - else if (ele->head.htype == BM_EDGE) { - BMEdge *eed = (BMEdge *)ele; - - BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, - BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - if (delimit) { - BMElem *ele_walk; - BMW_ITER (ele_walk, &walker, eed) { - if (ele_walk->head.htype == BM_LOOP) { - BMEdge *e_step = ((BMLoop *)ele_walk)->e; - BM_edge_select_set(bm, e_step, sel); - } - else { - BMEdge *e_step = (BMEdge *)ele_walk; - BLI_assert(ele_walk->head.htype == BM_EDGE); - BM_edge_select_set(bm, e_step, sel); - } - } - } - else { - BMEdge *e_walk; - BMW_ITER (e_walk, &walker, eed) { - BM_edge_select_set(bm, e_walk, sel); - } - } - - BMW_end(&walker); - - EDBM_selectmode_flush(em); - } - else if (ele->head.htype == BM_FACE) { - BMFace *efa = (BMFace *)ele; - - BMW_init(&walker, bm, BMW_ISLAND, - BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - - { - BMFace *f_walk; - BMW_ITER (f_walk, &walker, efa) { - BM_face_select_set(bm, f_walk, sel); - BM_elem_flag_disable(f_walk, BM_ELEM_TAG); - } - } - - BMW_end(&walker); - } - - if (delimit) { - select_linked_delimit_end(em); - } + BMesh *bm = em->bm; + BMWalker walker; + + select_linked_delimit_validate(bm, &delimit); + + if (delimit) { + select_linked_delimit_begin(bm, delimit); + } + + /* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */ + + if (ele->head.htype == BM_VERT) { + BMVert *eve = (BMVert *)ele; + + BMW_init(&walker, + bm, + delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, + BMW_MASK_NOP, + delimit ? BMO_ELE_TAG : BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + if (delimit) { + BMElem *ele_walk; + BMW_ITER (ele_walk, &walker, eve) { + if (ele_walk->head.htype == BM_LOOP) { + BMVert *v_step = ((BMLoop *)ele_walk)->v; + BM_vert_select_set(bm, v_step, sel); + } + else { + BMEdge *e_step = (BMEdge *)ele_walk; + BLI_assert(ele_walk->head.htype == BM_EDGE); + BM_edge_select_set(bm, e_step, sel); + } + } + } + else { + BMEdge *e_walk; + BMW_ITER (e_walk, &walker, eve) { + BM_edge_select_set(bm, e_walk, sel); + } + } + + BMW_end(&walker); + + EDBM_selectmode_flush(em); + } + else if (ele->head.htype == BM_EDGE) { + BMEdge *eed = (BMEdge *)ele; + + BMW_init(&walker, + bm, + delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, + BMW_MASK_NOP, + delimit ? BMO_ELE_TAG : BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + if (delimit) { + BMElem *ele_walk; + BMW_ITER (ele_walk, &walker, eed) { + if (ele_walk->head.htype == BM_LOOP) { + BMEdge *e_step = ((BMLoop *)ele_walk)->e; + BM_edge_select_set(bm, e_step, sel); + } + else { + BMEdge *e_step = (BMEdge *)ele_walk; + BLI_assert(ele_walk->head.htype == BM_EDGE); + BM_edge_select_set(bm, e_step, sel); + } + } + } + else { + BMEdge *e_walk; + BMW_ITER (e_walk, &walker, eed) { + BM_edge_select_set(bm, e_walk, sel); + } + } + + BMW_end(&walker); + + EDBM_selectmode_flush(em); + } + else if (ele->head.htype == BM_FACE) { + BMFace *efa = (BMFace *)ele; + + BMW_init(&walker, + bm, + BMW_ISLAND, + BMW_MASK_NOP, + delimit ? BMO_ELE_TAG : BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + { + BMFace *f_walk; + BMW_ITER (f_walk, &walker, efa) { + BM_face_select_set(bm, f_walk, sel); + BM_elem_flag_disable(f_walk, BM_ELEM_TAG); + } + } + + BMW_end(&walker); + } + + if (delimit) { + select_linked_delimit_end(em); + } } static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ViewContext vc; - Base *basact = NULL; - BMVert *eve; - BMEdge *eed; - BMFace *efa; - const bool sel = !RNA_boolean_get(op->ptr, "deselect"); - int index; - - if (RNA_struct_property_is_set(op->ptr, "index")) { - return edbm_select_linked_pick_exec(C, op); - } - - /* unified_finednearest needs ogl */ - view3d_operator_needs_opengl(C); - - /* setup view context for argument to callbacks */ - em_setup_viewcontext(C, &vc); - - uint bases_len; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); - - { - bool has_edges = false; - for (uint base_index = 0; base_index < bases_len; base_index++) { - Object *ob_iter = bases[base_index]->object; - ED_view3d_viewcontext_init_object(&vc, ob_iter); - if (vc.em->bm->totedge) { - has_edges = true; - } - } - if (has_edges == false) { - MEM_freeN(bases); - return OPERATOR_CANCELLED; - } - } - - vc.mval[0] = event->mval[0]; - vc.mval[1] = event->mval[1]; - - /* return warning! */ - { - int base_index = -1; - const bool ok = unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa); - if (!ok) { - MEM_freeN(bases); - return OPERATOR_CANCELLED; - } - basact = bases[base_index]; - } - - ED_view3d_viewcontext_init_object(&vc, basact->object); - BMEditMesh *em = vc.em; - BMesh *bm = em->bm; + ViewContext vc; + Base *basact = NULL; + BMVert *eve; + BMEdge *eed; + BMFace *efa; + const bool sel = !RNA_boolean_get(op->ptr, "deselect"); + int index; + + if (RNA_struct_property_is_set(op->ptr, "index")) { + return edbm_select_linked_pick_exec(C, op); + } + + /* unified_finednearest needs ogl */ + view3d_operator_needs_opengl(C); + + /* setup view context for argument to callbacks */ + em_setup_viewcontext(C, &vc); + + uint bases_len; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); + + { + bool has_edges = false; + for (uint base_index = 0; base_index < bases_len; base_index++) { + Object *ob_iter = bases[base_index]->object; + ED_view3d_viewcontext_init_object(&vc, ob_iter); + if (vc.em->bm->totedge) { + has_edges = true; + } + } + if (has_edges == false) { + MEM_freeN(bases); + return OPERATOR_CANCELLED; + } + } + + vc.mval[0] = event->mval[0]; + vc.mval[1] = event->mval[1]; + + /* return warning! */ + { + int base_index = -1; + const bool ok = unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa); + if (!ok) { + MEM_freeN(bases); + return OPERATOR_CANCELLED; + } + basact = bases[base_index]; + } + + ED_view3d_viewcontext_init_object(&vc, basact->object); + BMEditMesh *em = vc.em; + BMesh *bm = em->bm; #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, vc.scene->toolsettings->selectmode); + int delimit = select_linked_delimit_default_from_op(op, vc.scene->toolsettings->selectmode); #else - int delimit = RNA_enum_get(op->ptr, "delimit"); + int delimit = RNA_enum_get(op->ptr, "delimit"); #endif - BMElem *ele = EDBM_elem_from_selectmode(em, eve, eed, efa); + BMElem *ele = EDBM_elem_from_selectmode(em, eve, eed, efa); - edbm_select_linked_pick_ex(em, ele, sel, delimit); + edbm_select_linked_pick_ex(em, ele, sel, delimit); - /* to support redo */ - BM_mesh_elem_index_ensure(bm, ele->head.htype); - index = EDBM_elem_to_index_any(em, ele); + /* to support redo */ + BM_mesh_elem_index_ensure(bm, ele->head.htype); + index = EDBM_elem_to_index_any(em, ele); - /* TODO(MULTI_EDIT), index doesn't know which object, - * index selections isn't very common. */ - RNA_int_set(op->ptr, "index", index); + /* TODO(MULTI_EDIT), index doesn't know which object, + * index selections isn't very common. */ + RNA_int_set(op->ptr, "index", index); - DEG_id_tag_update(basact->object->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data); + DEG_id_tag_update(basact->object->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data); - MEM_freeN(bases); - return OPERATOR_FINISHED; + MEM_freeN(bases); + return OPERATOR_FINISHED; } - static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - int index; - const bool sel = !RNA_boolean_get(op->ptr, "deselect"); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + int index; + const bool sel = !RNA_boolean_get(op->ptr, "deselect"); - index = RNA_int_get(op->ptr, "index"); - if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) { - return OPERATOR_CANCELLED; - } + index = RNA_int_get(op->ptr, "index"); + if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) { + return OPERATOR_CANCELLED; + } - BMElem *ele = EDBM_elem_from_index_any(em, index); + BMElem *ele = EDBM_elem_from_index_any(em, index); #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em->selectmode); + int delimit = select_linked_delimit_default_from_op(op, em->selectmode); #else - int delimit = RNA_enum_get(op->ptr, "delimit"); + int delimit = RNA_enum_get(op->ptr, "delimit"); #endif - edbm_select_linked_pick_ex(em, ele, sel, delimit); + edbm_select_linked_pick_ex(em, ele, sel, delimit); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_select_linked_pick(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Select Linked"; - ot->idname = "MESH_OT_select_linked_pick"; - ot->description = "(De)select all vertices linked to the edge under the mouse cursor"; - - /* api callbacks */ - ot->invoke = edbm_select_linked_pick_invoke; - ot->exec = edbm_select_linked_pick_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); - prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit", - "Delimit selected region"); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Select Linked"; + ot->idname = "MESH_OT_select_linked_pick"; + ot->description = "(De)select all vertices linked to the edge under the mouse cursor"; + + /* api callbacks */ + ot->invoke = edbm_select_linked_pick_invoke; + ot->exec = edbm_select_linked_pick_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); + prop = RNA_def_enum_flag(ot->srna, + "delimit", + rna_enum_mesh_delimit_mode_items, + BMO_DELIM_SEAM, + "Delimit", + "Delimit selected region"); #ifdef USE_LINKED_SELECT_DEFAULT_HACK - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); #endif - /* use for redo */ - prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* use for redo */ + prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /** \} */ @@ -3269,86 +3329,87 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot) static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - const bool extend = RNA_boolean_get(op->ptr, "extend"); - const int numverts = RNA_int_get(op->ptr, "number"); - const int type = RNA_enum_get(op->ptr, "type"); - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMIter iter; - - if (!extend) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - } - - BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) { - bool select; - - switch (type) { - case 0: - select = (efa->len < numverts); - break; - case 1: - select = (efa->len == numverts); - break; - case 2: - select = (efa->len > numverts); - break; - case 3: - select = (efa->len != numverts); - break; - default: - BLI_assert(0); - select = false; - break; - } - - if (select) { - BM_face_select_set(em->bm, efa, true); - } - } - - EDBM_selectmode_flush(em); - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - MEM_freeN(objects); - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const int numverts = RNA_int_get(op->ptr, "number"); + const int type = RNA_enum_get(op->ptr, "type"); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMIter iter; + + if (!extend) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + bool select; + + switch (type) { + case 0: + select = (efa->len < numverts); + break; + case 1: + select = (efa->len == numverts); + break; + case 2: + select = (efa->len > numverts); + break; + case 3: + select = (efa->len != numverts); + break; + default: + BLI_assert(0); + select = false; + break; + } + + if (select) { + BM_face_select_set(em->bm, efa, true); + } + } + + EDBM_selectmode_flush(em); + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_select_face_by_sides(wmOperatorType *ot) { - static const EnumPropertyItem type_items[] = { - {0, "LESS", 0, "Less Than", ""}, - {1, "EQUAL", 0, "Equal To", ""}, - {2, "GREATER", 0, "Greater Than", ""}, - {3, "NOTEQUAL", 0, "Not Equal To", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Select Faces by Sides"; - ot->description = "Select vertices or faces by the number of polygon sides"; - ot->idname = "MESH_OT_select_face_by_sides"; - - /* api callbacks */ - ot->exec = edbm_select_face_by_sides_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_int(ot->srna, "number", 4, 3, INT_MAX, "Number of Vertices", "", 3, INT_MAX); - RNA_def_enum(ot->srna, "type", type_items, 1, "Type", "Type of comparison to make"); - RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection"); + static const EnumPropertyItem type_items[] = { + {0, "LESS", 0, "Less Than", ""}, + {1, "EQUAL", 0, "Equal To", ""}, + {2, "GREATER", 0, "Greater Than", ""}, + {3, "NOTEQUAL", 0, "Not Equal To", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Select Faces by Sides"; + ot->description = "Select vertices or faces by the number of polygon sides"; + ot->idname = "MESH_OT_select_face_by_sides"; + + /* api callbacks */ + ot->exec = edbm_select_face_by_sides_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_int(ot->srna, "number", 4, 3, INT_MAX, "Number of Vertices", "", 3, INT_MAX); + RNA_def_enum(ot->srna, "type", type_items, 1, "Type", "Type of comparison to make"); + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection"); } /** \} */ @@ -3359,85 +3420,86 @@ void MESH_OT_select_face_by_sides(wmOperatorType *ot) static int edbm_select_loose_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter; - - if (!extend) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - } - - if (em->selectmode & SCE_SELECT_VERTEX) { - BMVert *eve; - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (!eve->e) { - BM_vert_select_set(bm, eve, true); - } - } - } - - if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *eed; - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_edge_is_wire(eed)) { - BM_edge_select_set(bm, eed, true); - } - } - } - - if (em->selectmode & SCE_SELECT_FACE) { - BMFace *efa; - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BMIter liter; - BMLoop *l; - bool is_loose = true; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (!BM_edge_is_boundary(l->e)) { - is_loose = false; - break; - } - } - if (is_loose) { - BM_face_select_set(bm, efa, true); - } - } - } - - EDBM_selectmode_flush(em); - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter iter; + + if (!extend) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } + + if (em->selectmode & SCE_SELECT_VERTEX) { + BMVert *eve; + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + if (!eve->e) { + BM_vert_select_set(bm, eve, true); + } + } + } + + if (em->selectmode & SCE_SELECT_EDGE) { + BMEdge *eed; + BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_edge_is_wire(eed)) { + BM_edge_select_set(bm, eed, true); + } + } + } + + if (em->selectmode & SCE_SELECT_FACE) { + BMFace *efa; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BMIter liter; + BMLoop *l; + bool is_loose = true; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (!BM_edge_is_boundary(l->e)) { + is_loose = false; + break; + } + } + if (is_loose) { + BM_face_select_set(bm, efa, true); + } + } + } + + EDBM_selectmode_flush(em); + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_select_loose(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Loose Geometry"; - ot->description = "Select loose geometry based on the selection mode"; - ot->idname = "MESH_OT_select_loose"; + /* identifiers */ + ot->name = "Select Loose Geometry"; + ot->description = "Select loose geometry based on the selection mode"; + ot->idname = "MESH_OT_select_loose"; - /* api callbacks */ - ot->exec = edbm_select_loose_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_select_loose_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); + /* props */ + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } /** \} */ @@ -3448,69 +3510,70 @@ void MESH_OT_select_loose(wmOperatorType *ot) static int edbm_select_mirror_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const int axis_flag = RNA_enum_get(op->ptr, "axis"); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - Object *obedit_active = CTX_data_edit_object(C); - BMEditMesh *em_active = BKE_editmesh_from_object(obedit_active); - const int select_mode = em_active->bm->selectmode; - int tot_mirr = 0, tot_fail = 0; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totvertsel == 0) { - continue; - } - - int tot_mirr_iter = 0, tot_fail_iter = 0; - - for (int axis = 0; axis < 3; axis++) { - if ((1 << axis) & axis_flag) { - EDBM_select_mirrored(em, axis, extend, &tot_mirr_iter, &tot_fail_iter); - } - } - - if (tot_mirr_iter) { - EDBM_selectmode_flush(em); - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - tot_fail += tot_fail_iter; - tot_mirr += tot_mirr_iter; - } - MEM_freeN(objects); - - if (tot_mirr || tot_fail) { - ED_mesh_report_mirror_ex(op, tot_mirr, tot_fail, select_mode); - } - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + const int axis_flag = RNA_enum_get(op->ptr, "axis"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + Object *obedit_active = CTX_data_edit_object(C); + BMEditMesh *em_active = BKE_editmesh_from_object(obedit_active); + const int select_mode = em_active->bm->selectmode; + int tot_mirr = 0, tot_fail = 0; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totvertsel == 0) { + continue; + } + + int tot_mirr_iter = 0, tot_fail_iter = 0; + + for (int axis = 0; axis < 3; axis++) { + if ((1 << axis) & axis_flag) { + EDBM_select_mirrored(em, axis, extend, &tot_mirr_iter, &tot_fail_iter); + } + } + + if (tot_mirr_iter) { + EDBM_selectmode_flush(em); + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + tot_fail += tot_fail_iter; + tot_mirr += tot_mirr_iter; + } + MEM_freeN(objects); + + if (tot_mirr || tot_fail) { + ED_mesh_report_mirror_ex(op, tot_mirr, tot_fail, select_mode); + } + return OPERATOR_FINISHED; } void MESH_OT_select_mirror(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Mirror"; - ot->description = "Select mesh items at mirrored locations"; - ot->idname = "MESH_OT_select_mirror"; + /* identifiers */ + ot->name = "Select Mirror"; + ot->description = "Select mesh items at mirrored locations"; + ot->idname = "MESH_OT_select_mirror"; - /* api callbacks */ - ot->exec = edbm_select_mirror_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_select_mirror_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_enum_flag(ot->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 0), "Axis", ""); + /* props */ + RNA_def_enum_flag(ot->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 0), "Axis", ""); - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection"); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection"); } /** \} */ @@ -3521,47 +3584,46 @@ void MESH_OT_select_mirror(wmOperatorType *ot) static int edbm_select_more_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if ((bm->totvertsel == 0) && - (bm->totedgesel == 0) && - (bm->totfacesel == 0)) - { - continue; - } - - EDBM_select_more(em, use_face_step); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - MEM_freeN(objects); - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) { + continue; + } + + EDBM_select_more(em, use_face_step); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_select_more(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select More"; - ot->idname = "MESH_OT_select_more"; - ot->description = "Select more vertices, edges or faces connected to initial selection"; + /* identifiers */ + ot->name = "Select More"; + ot->idname = "MESH_OT_select_more"; + ot->description = "Select more vertices, edges or faces connected to initial selection"; - /* api callbacks */ - ot->exec = edbm_select_more_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_select_more_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)"); + RNA_def_boolean( + ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)"); } /** \} */ @@ -3572,47 +3634,46 @@ void MESH_OT_select_more(wmOperatorType *ot) static int edbm_select_less_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if ((bm->totvertsel == 0) && - (bm->totedgesel == 0) && - (bm->totfacesel == 0)) - { - continue; - } - - EDBM_select_less(em, use_face_step); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - MEM_freeN(objects); - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) { + continue; + } + + EDBM_select_less(em, use_face_step); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_select_less(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Less"; - ot->idname = "MESH_OT_select_less"; - ot->description = "Deselect vertices, edges or faces at the boundary of each selection region"; + /* identifiers */ + ot->name = "Select Less"; + ot->idname = "MESH_OT_select_less"; + ot->description = "Deselect vertices, edges or faces at the boundary of each selection region"; - /* api callbacks */ - ot->exec = edbm_select_less_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_select_less_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)"); + RNA_def_boolean( + ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)"); } /** \} */ @@ -3626,249 +3687,250 @@ void MESH_OT_select_less(wmOperatorType *ot) */ static bool bm_edge_is_select_isolated(BMEdge *e) { - BMIter viter; - BMVert *v; - - BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { - BMIter eiter; - BMEdge *e_other; - - BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) { - if ((e_other != e) && BM_elem_flag_test(e_other, BM_ELEM_SELECT)) { - return false; - } - } - } - return true; + BMIter viter; + BMVert *v; + + BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { + BMIter eiter; + BMEdge *e_other; + + BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) { + if ((e_other != e) && BM_elem_flag_test(e_other, BM_ELEM_SELECT)) { + return false; + } + } + } + return true; } /* Walk all reachable elements of the same type as h_act in breadth-first * order, starting from h_act. Deselects elements if the depth when they * are reached is not a multiple of "nth". */ -static void walker_deselect_nth( - BMEditMesh *em, const struct CheckerIntervalParams *op_params, - BMHeader *h_act) +static void walker_deselect_nth(BMEditMesh *em, + const struct CheckerIntervalParams *op_params, + BMHeader *h_act) { - BMElem *ele; - BMesh *bm = em->bm; - BMWalker walker; - BMIter iter; - int walktype = 0, itertype = 0, flushtype = 0; - short mask_vert = 0, mask_edge = 0, mask_face = 0; - - /* No active element from which to start - nothing to do */ - if (h_act == NULL) { - return; - } - - /* Determine which type of iter, walker, and select flush to use - * based on type of the elements being deselected */ - switch (h_act->htype) { - case BM_VERT: - itertype = BM_VERTS_OF_MESH; - walktype = BMW_CONNECTED_VERTEX; - flushtype = SCE_SELECT_VERTEX; - mask_vert = BMO_ELE_TAG; - break; - case BM_EDGE: - /* When an edge has no connected-selected edges, - * use face-stepping (supports edge-rings) */ - itertype = BM_EDGES_OF_MESH; - walktype = bm_edge_is_select_isolated((BMEdge *)h_act) ? BMW_FACE_SHELL : BMW_VERT_SHELL; - flushtype = SCE_SELECT_EDGE; - mask_edge = BMO_ELE_TAG; - break; - case BM_FACE: - itertype = BM_FACES_OF_MESH; - walktype = BMW_ISLAND; - flushtype = SCE_SELECT_FACE; - mask_face = BMO_ELE_TAG; - break; - } - - /* grr, shouldn't need to alloc BMO flags here */ - BM_mesh_elem_toolflags_ensure(bm); - - /* Walker restrictions uses BMO flags, not header flags, - * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */ - BMO_push(bm, NULL); - BM_ITER_MESH (ele, &iter, bm, itertype) { - if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { - BMO_elem_flag_enable(bm, (BMElemF *)ele, BMO_ELE_TAG); - } - } - - /* Walk over selected elements starting at active */ - BMW_init(&walker, bm, walktype, - mask_vert, mask_edge, mask_face, - BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */ - BMW_NIL_LAY); - - /* use tag to avoid touching the same verts twice */ - BM_ITER_MESH (ele, &iter, bm, itertype) { - BM_elem_flag_disable(ele, BM_ELEM_TAG); - } - - BLI_assert(walker.order == BMW_BREADTH_FIRST); - for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) { - if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) { - /* Deselect elements that aren't at "nth" depth from active */ - const int depth = BMW_current_depth(&walker) - 1; - if (WM_operator_properties_checker_interval_test(op_params, depth)) { - BM_elem_select_set(bm, ele, false); - } - BM_elem_flag_enable(ele, BM_ELEM_TAG); - } - } - BMW_end(&walker); - - BMO_pop(bm); - - /* Flush selection up */ - EDBM_selectmode_flush_ex(em, flushtype); + BMElem *ele; + BMesh *bm = em->bm; + BMWalker walker; + BMIter iter; + int walktype = 0, itertype = 0, flushtype = 0; + short mask_vert = 0, mask_edge = 0, mask_face = 0; + + /* No active element from which to start - nothing to do */ + if (h_act == NULL) { + return; + } + + /* Determine which type of iter, walker, and select flush to use + * based on type of the elements being deselected */ + switch (h_act->htype) { + case BM_VERT: + itertype = BM_VERTS_OF_MESH; + walktype = BMW_CONNECTED_VERTEX; + flushtype = SCE_SELECT_VERTEX; + mask_vert = BMO_ELE_TAG; + break; + case BM_EDGE: + /* When an edge has no connected-selected edges, + * use face-stepping (supports edge-rings) */ + itertype = BM_EDGES_OF_MESH; + walktype = bm_edge_is_select_isolated((BMEdge *)h_act) ? BMW_FACE_SHELL : BMW_VERT_SHELL; + flushtype = SCE_SELECT_EDGE; + mask_edge = BMO_ELE_TAG; + break; + case BM_FACE: + itertype = BM_FACES_OF_MESH; + walktype = BMW_ISLAND; + flushtype = SCE_SELECT_FACE; + mask_face = BMO_ELE_TAG; + break; + } + + /* grr, shouldn't need to alloc BMO flags here */ + BM_mesh_elem_toolflags_ensure(bm); + + /* Walker restrictions uses BMO flags, not header flags, + * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */ + BMO_push(bm, NULL); + BM_ITER_MESH (ele, &iter, bm, itertype) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { + BMO_elem_flag_enable(bm, (BMElemF *)ele, BMO_ELE_TAG); + } + } + + /* Walk over selected elements starting at active */ + BMW_init(&walker, + bm, + walktype, + mask_vert, + mask_edge, + mask_face, + BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */ + BMW_NIL_LAY); + + /* use tag to avoid touching the same verts twice */ + BM_ITER_MESH (ele, &iter, bm, itertype) { + BM_elem_flag_disable(ele, BM_ELEM_TAG); + } + + BLI_assert(walker.order == BMW_BREADTH_FIRST); + for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) { + if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) { + /* Deselect elements that aren't at "nth" depth from active */ + const int depth = BMW_current_depth(&walker) - 1; + if (WM_operator_properties_checker_interval_test(op_params, depth)) { + BM_elem_select_set(bm, ele, false); + } + BM_elem_flag_enable(ele, BM_ELEM_TAG); + } + } + BMW_end(&walker); + + BMO_pop(bm); + + /* Flush selection up */ + EDBM_selectmode_flush_ex(em, flushtype); } static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) { - BMIter iter; - BMElem *ele; - - *r_eve = NULL; - *r_eed = NULL; - *r_efa = NULL; - - EDBM_selectmode_flush(em); - ele = BM_mesh_active_elem_get(em->bm); - - if (ele && BM_elem_flag_test(ele, BM_ELEM_SELECT)) { - switch (ele->head.htype) { - case BM_VERT: - *r_eve = (BMVert *)ele; - return; - case BM_EDGE: - *r_eed = (BMEdge *)ele; - return; - case BM_FACE: - *r_efa = (BMFace *)ele; - return; - } - } - - if (em->selectmode & SCE_SELECT_VERTEX) { - BMVert *v; - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - *r_eve = v; - return; - } - } - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *e; - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - *r_eed = e; - return; - } - } - } - else if (em->selectmode & SCE_SELECT_FACE) { - BMFace *f = BM_mesh_active_face_get(em->bm, true, false); - if (f && BM_elem_flag_test(f, BM_ELEM_SELECT)) { - *r_efa = f; - return; - } - } + BMIter iter; + BMElem *ele; + + *r_eve = NULL; + *r_eed = NULL; + *r_efa = NULL; + + EDBM_selectmode_flush(em); + ele = BM_mesh_active_elem_get(em->bm); + + if (ele && BM_elem_flag_test(ele, BM_ELEM_SELECT)) { + switch (ele->head.htype) { + case BM_VERT: + *r_eve = (BMVert *)ele; + return; + case BM_EDGE: + *r_eed = (BMEdge *)ele; + return; + case BM_FACE: + *r_efa = (BMFace *)ele; + return; + } + } + + if (em->selectmode & SCE_SELECT_VERTEX) { + BMVert *v; + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + *r_eve = v; + return; + } + } + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BMEdge *e; + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + *r_eed = e; + return; + } + } + } + else if (em->selectmode & SCE_SELECT_FACE) { + BMFace *f = BM_mesh_active_face_get(em->bm, true, false); + if (f && BM_elem_flag_test(f, BM_ELEM_SELECT)) { + *r_efa = f; + return; + } + } } static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams *op_params) { - BMVert *v; - BMEdge *e; - BMFace *f; - - deselect_nth_active(em, &v, &e, &f); - - if (v) { - walker_deselect_nth(em, op_params, &v->head); - return true; - } - else if (e) { - walker_deselect_nth(em, op_params, &e->head); - return true; - } - else if (f) { - walker_deselect_nth(em, op_params, &f->head); - return true; - } - - return false; + BMVert *v; + BMEdge *e; + BMFace *f; + + deselect_nth_active(em, &v, &e, &f); + + if (v) { + walker_deselect_nth(em, op_params, &v->head); + return true; + } + else if (e) { + walker_deselect_nth(em, op_params, &e->head); + return true; + } + else if (f) { + walker_deselect_nth(em, op_params, &f->head); + return true; + } + + return false; } static int edbm_select_nth_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - struct CheckerIntervalParams op_params; - WM_operator_properties_checker_interval_from_op(op, &op_params); - bool found_active_elt = false; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if ((em->bm->totvertsel == 0) && - (em->bm->totedgesel == 0) && - (em->bm->totfacesel == 0)) - { - continue; - } - - if (edbm_deselect_nth(em, &op_params) == true) { - found_active_elt = true; - EDBM_update_generic(em, false, false); - } - } - MEM_freeN(objects); - - if (!found_active_elt) { - BKE_report(op->reports, RPT_ERROR, - (objects_len == 1 ? - "Mesh has no active vert/edge/face" : - "Meshes have no active vert/edge/face")); - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + struct CheckerIntervalParams op_params; + WM_operator_properties_checker_interval_from_op(op, &op_params); + bool found_active_elt = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) { + continue; + } + + if (edbm_deselect_nth(em, &op_params) == true) { + found_active_elt = true; + EDBM_update_generic(em, false, false); + } + } + MEM_freeN(objects); + + if (!found_active_elt) { + BKE_report(op->reports, + RPT_ERROR, + (objects_len == 1 ? "Mesh has no active vert/edge/face" : + "Meshes have no active vert/edge/face")); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } - void MESH_OT_select_nth(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Checker Deselect"; - ot->idname = "MESH_OT_select_nth"; - ot->description = "Deselect every Nth element starting from the active vertex, edge or face"; + /* identifiers */ + ot->name = "Checker Deselect"; + ot->idname = "MESH_OT_select_nth"; + ot->description = "Deselect every Nth element starting from the active vertex, edge or face"; - /* api callbacks */ - ot->exec = edbm_select_nth_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_select_nth_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_checker_interval(ot, false); + WM_operator_properties_checker_interval(ot, false); } void em_setup_viewcontext(bContext *C, ViewContext *vc) { - ED_view3d_viewcontext_init(C, vc); + ED_view3d_viewcontext_init(C, vc); - if (vc->obedit) { - vc->em = BKE_editmesh_from_object(vc->obedit); - } + if (vc->obedit) { + vc->em = BKE_editmesh_from_object(vc->obedit); + } } /** \} */ @@ -3879,71 +3941,78 @@ void em_setup_viewcontext(bContext *C, ViewContext *vc) static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op) { - /* Find edges that have exactly two neighboring faces, - * check the angle between those faces, and if angle is - * small enough, select the edge - */ - const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness")); - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - BMEdge *e; - BMLoop *l1, *l2; - - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false && - BM_edge_loop_pair(e, &l1, &l2)) - { - /* edge has exactly two neighboring faces, check angle */ - const float angle_cos = dot_v3v3(l1->f->no, l2->f->no); - - if (angle_cos < angle_limit_cos) { - BM_edge_select_set(em->bm, e, true); - } - } - } - - if ((em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) { - /* Since we can't select individual edges, select faces connected to them. */ - EDBM_selectmode_convert(em, SCE_SELECT_EDGE, SCE_SELECT_FACE); - } - else { - EDBM_selectmode_flush(em); - } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + /* Find edges that have exactly two neighboring faces, + * check the angle between those faces, and if angle is + * small enough, select the edge + */ + const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness")); + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMIter iter; + BMEdge *e; + BMLoop *l1, *l2; + + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false && BM_edge_loop_pair(e, &l1, &l2)) { + /* edge has exactly two neighboring faces, check angle */ + const float angle_cos = dot_v3v3(l1->f->no, l2->f->no); + + if (angle_cos < angle_limit_cos) { + BM_edge_select_set(em->bm, e, true); + } + } + } + + if ((em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) { + /* Since we can't select individual edges, select faces connected to them. */ + EDBM_selectmode_convert(em, SCE_SELECT_EDGE, SCE_SELECT_FACE); + } + else { + EDBM_selectmode_flush(em); + } + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_edges_select_sharp(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Select Sharp Edges"; - ot->description = "Select all sharp-enough edges"; - ot->idname = "MESH_OT_edges_select_sharp"; - - /* api callbacks */ - ot->exec = edbm_select_sharp_edges_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f), - "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f)); - RNA_def_property_float_default(prop, DEG2RADF(30.0f)); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Select Sharp Edges"; + ot->description = "Select all sharp-enough edges"; + ot->idname = "MESH_OT_edges_select_sharp"; + + /* api callbacks */ + ot->exec = edbm_select_sharp_edges_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + prop = RNA_def_float_rotation(ot->srna, + "sharpness", + 0, + NULL, + DEG2RADF(0.01f), + DEG2RADF(180.0f), + "Sharpness", + "", + DEG2RADF(1.0f), + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(30.0f)); } /** \} */ @@ -3954,95 +4023,102 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot) static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness")); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness")); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; - if (bm->totfacesel == 0) { - continue; - } + if (bm->totfacesel == 0) { + continue; + } - BLI_LINKSTACK_DECLARE(stack, BMFace *); + BLI_LINKSTACK_DECLARE(stack, BMFace *); - BMIter iter, liter, liter2; - BMFace *f; - BMLoop *l, *l2; + BMIter iter, liter, liter2; + BMFace *f; + BMLoop *l, *l2; - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BLI_LINKSTACK_INIT(stack); + BLI_LINKSTACK_INIT(stack); - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || - (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) || - (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) - { - continue; - } + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || + (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) || + (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) { + continue; + } - BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); + BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); - do { - BM_face_select_set(bm, f, true); + do { + BM_face_select_set(bm, f, true); - BM_elem_flag_enable(f, BM_ELEM_TAG); + BM_elem_flag_enable(f, BM_ELEM_TAG); - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { - float angle_cos; + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { + float angle_cos; - if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || - BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) - { - continue; - } + if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || + BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) { + continue; + } - angle_cos = dot_v3v3(f->no, l2->f->no); + angle_cos = dot_v3v3(f->no, l2->f->no); - if (angle_cos > angle_limit_cos) { - BLI_LINKSTACK_PUSH(stack, l2->f); - } - } - } - } while ((f = BLI_LINKSTACK_POP(stack))); - } + if (angle_cos > angle_limit_cos) { + BLI_LINKSTACK_PUSH(stack, l2->f); + } + } + } + } while ((f = BLI_LINKSTACK_POP(stack))); + } - BLI_LINKSTACK_FREE(stack); + BLI_LINKSTACK_FREE(stack); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - MEM_freeN(objects); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Select Linked Flat Faces"; - ot->description = "Select linked faces by angle"; - ot->idname = "MESH_OT_faces_select_linked_flat"; - - /* api callbacks */ - ot->exec = edbm_select_linked_flat_faces_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f), - "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f)); - RNA_def_property_float_default(prop, DEG2RADF(1.0f)); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Select Linked Flat Faces"; + ot->description = "Select linked faces by angle"; + ot->idname = "MESH_OT_faces_select_linked_flat"; + + /* api callbacks */ + ot->exec = edbm_select_linked_flat_faces_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + prop = RNA_def_float_rotation(ot->srna, + "sharpness", + 0, + NULL, + DEG2RADF(0.01f), + DEG2RADF(180.0f), + "Sharpness", + "", + DEG2RADF(1.0f), + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(1.0f)); } /** \} */ @@ -4053,103 +4129,102 @@ void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) { - const bool use_extend = RNA_boolean_get(op->ptr, "extend"); - const bool use_wire = RNA_boolean_get(op->ptr, "use_wire"); - const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); - const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face"); - const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous"); - const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMVert *v; - BMEdge *e; - BMIter iter; - - if (!use_extend) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - } - - /* Selects isolated verts, and edges that do not have 2 neighboring - * faces - */ - - if (em->selectmode == SCE_SELECT_FACE) { - BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode"); - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - - if (use_verts) { - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { - if (!BM_vert_is_manifold(v)) { - BM_vert_select_set(em->bm, v, true); - } - } - } - } - - if (use_wire || use_boundary || use_multi_face || use_non_contiguous) { - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - if ((use_wire && BM_edge_is_wire(e)) || - (use_boundary && BM_edge_is_boundary(e)) || - (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) || - (use_multi_face && (BM_edge_face_count_is_over(e, 2)))) - { - /* check we never select perfect edge (in test above) */ - BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e))); - - BM_edge_select_set(em->bm, e, true); - } - } - } - } - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - - EDBM_selectmode_flush(em); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const bool use_extend = RNA_boolean_get(op->ptr, "extend"); + const bool use_wire = RNA_boolean_get(op->ptr, "use_wire"); + const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); + const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face"); + const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous"); + const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMVert *v; + BMEdge *e; + BMIter iter; + + if (!use_extend) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } + + /* Selects isolated verts, and edges that do not have 2 neighboring + * faces + */ + + if (em->selectmode == SCE_SELECT_FACE) { + BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode"); + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + + if (use_verts) { + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + if (!BM_vert_is_manifold(v)) { + BM_vert_select_set(em->bm, v, true); + } + } + } + } + + if (use_wire || use_boundary || use_multi_face || use_non_contiguous) { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if ((use_wire && BM_edge_is_wire(e)) || (use_boundary && BM_edge_is_boundary(e)) || + (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) || + (use_multi_face && (BM_edge_face_count_is_over(e, 2)))) { + /* check we never select perfect edge (in test above) */ + BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e))); + + BM_edge_select_set(em->bm, e, true); + } + } + } + } + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + EDBM_selectmode_flush(em); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_select_non_manifold(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Non Manifold"; - ot->description = "Select all non-manifold vertices or edges"; - ot->idname = "MESH_OT_select_non_manifold"; - - /* api callbacks */ - ot->exec = edbm_select_non_manifold_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection"); - /* edges */ - RNA_def_boolean(ot->srna, "use_wire", true, "Wire", - "Wire edges"); - RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries", - "Boundary edges"); - RNA_def_boolean(ot->srna, "use_multi_face", true, - "Multiple Faces", "Edges shared by 3+ faces"); - RNA_def_boolean(ot->srna, "use_non_contiguous", true, "Non Contiguous", - "Edges between faces pointing in alternate directions"); - /* verts */ - RNA_def_boolean(ot->srna, "use_verts", true, "Vertices", - "Vertices connecting multiple face regions"); + /* identifiers */ + ot->name = "Select Non Manifold"; + ot->description = "Select all non-manifold vertices or edges"; + ot->idname = "MESH_OT_select_non_manifold"; + + /* api callbacks */ + ot->exec = edbm_select_non_manifold_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection"); + /* edges */ + RNA_def_boolean(ot->srna, "use_wire", true, "Wire", "Wire edges"); + RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries", "Boundary edges"); + RNA_def_boolean(ot->srna, "use_multi_face", true, "Multiple Faces", "Edges shared by 3+ faces"); + RNA_def_boolean(ot->srna, + "use_non_contiguous", + true, + "Non Contiguous", + "Edges between faces pointing in alternate directions"); + /* verts */ + RNA_def_boolean( + ot->srna, "use_verts", true, "Vertices", "Vertices connecting multiple face regions"); } /** \} */ @@ -4160,86 +4235,87 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) static int edbm_select_random_exec(bContext *C, wmOperator *op) { - const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); - const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; - const int seed = WM_operator_properties_select_random_seed_increment_get(op); - - ViewLayer *view_layer = CTX_data_view_layer(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - int seed_iter = seed; - - /* This gives a consistent result regardless of object order. */ - if (ob_index) { - seed_iter += BLI_ghashutil_strhash_p(obedit->id.name); - } - - RNG *rng = BLI_rng_new_srandom(seed_iter); - - if (em->selectmode & SCE_SELECT_VERTEX) { - BMVert *eve; - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { - BM_vert_select_set(em->bm, eve, select); - } - } - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *eed; - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { - BM_edge_select_set(em->bm, eed, select); - } - } - } - else { - BMFace *efa; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { - BM_face_select_set(em->bm, efa, select); - } - } - } - - BLI_rng_free(rng); - - if (select) { - /* was EDBM_select_flush, but it over select in edge/face mode */ - EDBM_selectmode_flush(em); - } - else { - EDBM_deselect_flush(em); - } - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - MEM_freeN(objects); - return OPERATOR_FINISHED; + const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); + const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; + const int seed = WM_operator_properties_select_random_seed_increment_get(op); + + ViewLayer *view_layer = CTX_data_view_layer(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMIter iter; + int seed_iter = seed; + + /* This gives a consistent result regardless of object order. */ + if (ob_index) { + seed_iter += BLI_ghashutil_strhash_p(obedit->id.name); + } + + RNG *rng = BLI_rng_new_srandom(seed_iter); + + if (em->selectmode & SCE_SELECT_VERTEX) { + BMVert *eve; + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { + BM_vert_select_set(em->bm, eve, select); + } + } + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BMEdge *eed; + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { + BM_edge_select_set(em->bm, eed, select); + } + } + } + else { + BMFace *efa; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { + BM_face_select_set(em->bm, efa, select); + } + } + } + + BLI_rng_free(rng); + + if (select) { + /* was EDBM_select_flush, but it over select in edge/face mode */ + EDBM_selectmode_flush(em); + } + else { + EDBM_deselect_flush(em); + } + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_select_random(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Random"; - ot->description = "Randomly select vertices"; - ot->idname = "MESH_OT_select_random"; + /* identifiers */ + ot->name = "Select Random"; + ot->description = "Randomly select vertices"; + ot->idname = "MESH_OT_select_random"; - /* api callbacks */ - ot->exec = edbm_select_random_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_select_random_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - WM_operator_properties_select_random(ot); + /* props */ + WM_operator_properties_select_random(ot); } /** \} */ @@ -4250,90 +4326,91 @@ void MESH_OT_select_random(wmOperatorType *ot) static bool edbm_select_ungrouped_poll(bContext *C) { - if (ED_operator_editmesh(C)) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - - if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { - CTX_wm_operator_poll_msg_set(C, "Must be in vertex selection mode"); - } - else if (BLI_listbase_is_empty(&obedit->defbase) || cd_dvert_offset == -1) { - CTX_wm_operator_poll_msg_set(C, "No weights/vertex groups on object"); - } - else { - return true; - } - } - return false; + if (ED_operator_editmesh(C)) { + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + + if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { + CTX_wm_operator_poll_msg_set(C, "Must be in vertex selection mode"); + } + else if (BLI_listbase_is_empty(&obedit->defbase) || cd_dvert_offset == -1) { + CTX_wm_operator_poll_msg_set(C, "No weights/vertex groups on object"); + } + else { + return true; + } + } + return false; } static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op) { - const bool extend = RNA_boolean_get(op->ptr, "extend"); - ViewLayer *view_layer = CTX_data_view_layer(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - - if (cd_dvert_offset == -1) { - continue; - } - - BMVert *eve; - BMIter iter; - - bool changed = false; - - if (!extend) { - if (em->bm->totvertsel) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - changed = true; - } - } - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - /* no dv or dv set with no weight */ - if (ELEM(NULL, dv, dv->dw)) { - BM_vert_select_set(em->bm, eve, true); - changed = true; - } - } - } - - if (changed) { - EDBM_selectmode_flush(em); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - } - MEM_freeN(objects); - return OPERATOR_FINISHED; + const bool extend = RNA_boolean_get(op->ptr, "extend"); + ViewLayer *view_layer = CTX_data_view_layer(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + + if (cd_dvert_offset == -1) { + continue; + } + + BMVert *eve; + BMIter iter; + + bool changed = false; + + if (!extend) { + if (em->bm->totvertsel) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + changed = true; + } + } + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + /* no dv or dv set with no weight */ + if (ELEM(NULL, dv, dv->dw)) { + BM_vert_select_set(em->bm, eve, true); + changed = true; + } + } + } + + if (changed) { + EDBM_selectmode_flush(em); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_select_ungrouped(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Ungrouped"; - ot->idname = "MESH_OT_select_ungrouped"; - ot->description = "Select vertices without a group"; + /* identifiers */ + ot->name = "Select Ungrouped"; + ot->idname = "MESH_OT_select_ungrouped"; + ot->description = "Select vertices without a group"; - /* api callbacks */ - ot->exec = edbm_select_ungrouped_exec; - ot->poll = edbm_select_ungrouped_poll; + /* api callbacks */ + ot->exec = edbm_select_ungrouped_exec; + ot->poll = edbm_select_ungrouped_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } /** \} */ @@ -4343,131 +4420,149 @@ void MESH_OT_select_ungrouped(wmOperatorType *ot) * \{ */ enum { - SELECT_AXIS_POS = 0, - SELECT_AXIS_NEG = 1, - SELECT_AXIS_ALIGN = 2, + SELECT_AXIS_POS = 0, + SELECT_AXIS_NEG = 1, + SELECT_AXIS_ALIGN = 2, }; static int edbm_select_axis_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMVert *v_act = BM_mesh_active_vert_get(em->bm); - const int orientation = RNA_enum_get(op->ptr, "orientation"); - const int axis = RNA_enum_get(op->ptr, "axis"); - const int sign = RNA_enum_get(op->ptr, "sign"); - - if (v_act == NULL) { - BKE_report(op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)"); - return OPERATOR_CANCELLED; - } - - const float limit = RNA_float_get(op->ptr, "threshold"); - - float value; - float axis_mat[3][3]; - - /* 3D view variables may be NULL, (no need to check in poll function). */ - ED_transform_calc_orientation_from_type_ex( - C, axis_mat, - scene, CTX_wm_region_view3d(C), obedit, obedit, - orientation, 0, V3D_AROUND_ACTIVE); - - const float *axis_vector = axis_mat[axis]; - - { - float vertex_world[3]; - mul_v3_m4v3(vertex_world, obedit->obmat, v_act->co); - value = dot_v3v3(axis_vector, vertex_world); - } - - if (sign == SELECT_AXIS_NEG) { - value += limit; - } - else if (sign == SELECT_AXIS_POS) { - value -= limit; - } - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit_iter = objects[ob_index]; - BMEditMesh *em_iter = BKE_editmesh_from_object(obedit_iter); - BMesh *bm = em_iter->bm; - - if (bm->totvert == bm->totvertsel) { - continue; - } - - BMIter iter; - BMVert *v; - bool changed = false; - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN | BM_ELEM_SELECT)) { - float v_iter_world[3]; - mul_v3_m4v3(v_iter_world, obedit_iter->obmat, v->co); - const float value_iter = dot_v3v3(axis_vector, v_iter_world); - switch (sign) { - case SELECT_AXIS_ALIGN: - if (fabsf(value_iter - value) < limit) { - BM_vert_select_set(bm, v, true); - changed = true; - } - break; - case SELECT_AXIS_NEG: - if (value_iter < value) { - BM_vert_select_set(bm, v, true); - changed = true; - } - break; - case SELECT_AXIS_POS: - if (value_iter > value) { - BM_vert_select_set(bm, v, true); - changed = true; - } - break; - } - } - } - if (changed) { - EDBM_selectmode_flush(em_iter); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit_iter->data); - DEG_id_tag_update(obedit_iter->data, ID_RECALC_SELECT); - } - } - MEM_freeN(objects); - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMVert *v_act = BM_mesh_active_vert_get(em->bm); + const int orientation = RNA_enum_get(op->ptr, "orientation"); + const int axis = RNA_enum_get(op->ptr, "axis"); + const int sign = RNA_enum_get(op->ptr, "sign"); + + if (v_act == NULL) { + BKE_report( + op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)"); + return OPERATOR_CANCELLED; + } + + const float limit = RNA_float_get(op->ptr, "threshold"); + + float value; + float axis_mat[3][3]; + + /* 3D view variables may be NULL, (no need to check in poll function). */ + ED_transform_calc_orientation_from_type_ex(C, + axis_mat, + scene, + CTX_wm_region_view3d(C), + obedit, + obedit, + orientation, + 0, + V3D_AROUND_ACTIVE); + + const float *axis_vector = axis_mat[axis]; + + { + float vertex_world[3]; + mul_v3_m4v3(vertex_world, obedit->obmat, v_act->co); + value = dot_v3v3(axis_vector, vertex_world); + } + + if (sign == SELECT_AXIS_NEG) { + value += limit; + } + else if (sign == SELECT_AXIS_POS) { + value -= limit; + } + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit_iter = objects[ob_index]; + BMEditMesh *em_iter = BKE_editmesh_from_object(obedit_iter); + BMesh *bm = em_iter->bm; + + if (bm->totvert == bm->totvertsel) { + continue; + } + + BMIter iter; + BMVert *v; + bool changed = false; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN | BM_ELEM_SELECT)) { + float v_iter_world[3]; + mul_v3_m4v3(v_iter_world, obedit_iter->obmat, v->co); + const float value_iter = dot_v3v3(axis_vector, v_iter_world); + switch (sign) { + case SELECT_AXIS_ALIGN: + if (fabsf(value_iter - value) < limit) { + BM_vert_select_set(bm, v, true); + changed = true; + } + break; + case SELECT_AXIS_NEG: + if (value_iter < value) { + BM_vert_select_set(bm, v, true); + changed = true; + } + break; + case SELECT_AXIS_POS: + if (value_iter > value) { + BM_vert_select_set(bm, v, true); + changed = true; + } + break; + } + } + } + if (changed) { + EDBM_selectmode_flush(em_iter); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit_iter->data); + DEG_id_tag_update(obedit_iter->data, ID_RECALC_SELECT); + } + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_select_axis(wmOperatorType *ot) { - static const EnumPropertyItem axis_sign_items[] = { - {SELECT_AXIS_POS, "POS", 0, "Positive Axis", ""}, - {SELECT_AXIS_NEG, "NEG", 0, "Negative Axis", ""}, - {SELECT_AXIS_ALIGN, "ALIGN", 0, "Aligned Axis", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Select Axis"; - ot->description = "Select all data in the mesh on a single axis"; - ot->idname = "MESH_OT_select_axis"; - - /* api callbacks */ - ot->exec = edbm_select_axis_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_enum(ot->srna, "orientation", rna_enum_transform_orientation_items, V3D_ORIENT_LOCAL, "Axis Mode", "Axis orientation"); - RNA_def_enum(ot->srna, "sign", axis_sign_items, SELECT_AXIS_POS, "Axis Sign", "Side to select"); - RNA_def_enum(ot->srna, "axis", rna_enum_axis_xyz_items, 0, "Axis", "Select the axis to compare each vertex on"); - RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f); + static const EnumPropertyItem axis_sign_items[] = { + {SELECT_AXIS_POS, "POS", 0, "Positive Axis", ""}, + {SELECT_AXIS_NEG, "NEG", 0, "Negative Axis", ""}, + {SELECT_AXIS_ALIGN, "ALIGN", 0, "Aligned Axis", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Select Axis"; + ot->description = "Select all data in the mesh on a single axis"; + ot->idname = "MESH_OT_select_axis"; + + /* api callbacks */ + ot->exec = edbm_select_axis_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, + "orientation", + rna_enum_transform_orientation_items, + V3D_ORIENT_LOCAL, + "Axis Mode", + "Axis orientation"); + RNA_def_enum(ot->srna, "sign", axis_sign_items, SELECT_AXIS_POS, "Axis Sign", "Side to select"); + RNA_def_enum(ot->srna, + "axis", + rna_enum_axis_xyz_items, + 0, + "Axis", + "Select the axis to compare each vertex on"); + RNA_def_float( + ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f); } /** \} */ @@ -4478,76 +4573,77 @@ void MESH_OT_select_axis(wmOperatorType *ot) static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op)) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totfacesel == 0) { - continue; - } - BMFace *f; - BMEdge *e; - BMIter iter; - - BM_mesh_elem_hflag_disable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false); - - BM_ITER_MESH(f, &iter, em->bm, BM_FACES_OF_MESH) { - BMLoop *l1, *l2; - BMIter liter1, liter2; - - BM_ITER_ELEM(l1, &liter1, f, BM_LOOPS_OF_FACE) { - int tot = 0, totsel = 0; - - BM_ITER_ELEM(l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { - tot++; - totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0; - } - - if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1)) - BM_elem_flag_enable(l1->e, BM_ELEM_TAG); - } - } - - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - - BM_ITER_MESH(e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BM_edge_select_set(em->bm, e, true); - } - } - - /* If in face-only select mode, switch to edge select mode so that - * an edge-only selection is not inconsistent state */ - if (em->selectmode == SCE_SELECT_FACE) { - em->selectmode = SCE_SELECT_EDGE; - EDBM_selectmode_set(em); - EDBM_selectmode_to_scene(C); - } - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totfacesel == 0) { + continue; + } + BMFace *f; + BMEdge *e; + BMIter iter; + + BM_mesh_elem_hflag_disable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false); + + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + BMLoop *l1, *l2; + BMIter liter1, liter2; + + BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { + int tot = 0, totsel = 0; + + BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { + tot++; + totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0; + } + + if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1)) + BM_elem_flag_enable(l1->e, BM_ELEM_TAG); + } + } + + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BM_edge_select_set(em->bm, e, true); + } + } + + /* If in face-only select mode, switch to edge select mode so that + * an edge-only selection is not inconsistent state */ + if (em->selectmode == SCE_SELECT_FACE) { + em->selectmode = SCE_SELECT_EDGE; + EDBM_selectmode_set(em); + EDBM_selectmode_to_scene(C); + } + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_region_to_loop(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Boundary Loop"; - ot->idname = "MESH_OT_region_to_loop"; - ot->description = "Select boundary edges around the selected faces"; + /* identifiers */ + ot->name = "Select Boundary Loop"; + ot->idname = "MESH_OT_region_to_loop"; + ot->description = "Select boundary edges around the selected faces"; - /* api callbacks */ - ot->exec = edbm_region_to_loop_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_region_to_loop_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -4556,61 +4652,61 @@ void MESH_OT_region_to_loop(wmOperatorType *ot) /** \name Select Loop to Region Operator * \{ */ -static int loop_find_region( - BMLoop *l, int flag, - GSet *visit_face_set, BMFace ***region_out) +static int loop_find_region(BMLoop *l, int flag, GSet *visit_face_set, BMFace ***region_out) { - BMFace **region = NULL; - BMFace **stack = NULL; - BLI_array_declare(region); - BLI_array_declare(stack); - BMFace *f; - - BLI_array_append(stack, l->f); - BLI_gset_insert(visit_face_set, l->f); - - while (BLI_array_len(stack) > 0) { - BMIter liter1, liter2; - BMLoop *l1, *l2; - - f = BLI_array_pop(stack); - BLI_array_append(region, f); - - BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l1->e, flag)) - continue; - - BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { - /* avoids finding same region twice - * (otherwise) the logic works fine without */ - if (BM_elem_flag_test(l2->f, BM_ELEM_TAG)) { - continue; - } - - if (BLI_gset_add(visit_face_set, l2->f)) { - BLI_array_append(stack, l2->f); - } - } - } - } - - BLI_array_free(stack); - - *region_out = region; - return BLI_array_len(region); + BMFace **region = NULL; + BMFace **stack = NULL; + BLI_array_declare(region); + BLI_array_declare(stack); + BMFace *f; + + BLI_array_append(stack, l->f); + BLI_gset_insert(visit_face_set, l->f); + + while (BLI_array_len(stack) > 0) { + BMIter liter1, liter2; + BMLoop *l1, *l2; + + f = BLI_array_pop(stack); + BLI_array_append(region, f); + + BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l1->e, flag)) + continue; + + BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { + /* avoids finding same region twice + * (otherwise) the logic works fine without */ + if (BM_elem_flag_test(l2->f, BM_ELEM_TAG)) { + continue; + } + + if (BLI_gset_add(visit_face_set, l2->f)) { + BLI_array_append(stack, l2->f); + } + } + } + } + + BLI_array_free(stack); + + *region_out = region; + return BLI_array_len(region); } static int verg_radial(const void *va, const void *vb) { - const BMEdge *e_a = *((const BMEdge **)va); - const BMEdge *e_b = *((const BMEdge **)vb); + const BMEdge *e_a = *((const BMEdge **)va); + const BMEdge *e_b = *((const BMEdge **)vb); - const int a = BM_edge_face_count(e_a); - const int b = BM_edge_face_count(e_b); + const int a = BM_edge_face_count(e_a); + const int b = BM_edge_face_count(e_b); - if (a > b) return -1; - if (a < b) return 1; - return 0; + if (a > b) + return -1; + if (a < b) + return 1; + return 0; } /** @@ -4621,143 +4717,148 @@ static int verg_radial(const void *va, const void *vb) */ static int loop_find_regions(BMEditMesh *em, const bool selbigger) { - GSet *visit_face_set; - BMIter iter; - const int edges_len = em->bm->totedgesel; - BMEdge *e, **edges; - int count = 0, i; - - visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len); - edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__); - - i = 0; - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - edges[i++] = e; - BM_elem_flag_enable(e, BM_ELEM_TAG); - } - else { - BM_elem_flag_disable(e, BM_ELEM_TAG); - } - } - - /* sort edges by radial cycle length */ - qsort(edges, edges_len, sizeof(*edges), verg_radial); - - for (i = 0; i < edges_len; i++) { - BMIter liter; - BMLoop *l; - BMFace **region = NULL, **region_out; - int c, tot = 0; - - e = edges[i]; - - if (!BM_elem_flag_test(e, BM_ELEM_TAG)) - continue; - - BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { - if (BLI_gset_haskey(visit_face_set, l->f)) - continue; - - c = loop_find_region(l, BM_ELEM_SELECT, visit_face_set, ®ion_out); - - if (!region || (selbigger ? c >= tot : c < tot)) { - /* this region is the best seen so far */ - tot = c; - if (region) { - /* free the previous best */ - MEM_freeN(region); - } - /* track the current region as the new best */ - region = region_out; - } - else { - /* this region is not as good as best so far, just free it */ - MEM_freeN(region_out); - } - } - - if (region) { - int j; - - for (j = 0; j < tot; j++) { - BM_elem_flag_enable(region[j], BM_ELEM_TAG); - BM_ITER_ELEM (l, &liter, region[j], BM_LOOPS_OF_FACE) { - BM_elem_flag_disable(l->e, BM_ELEM_TAG); - } - } - - count += tot; - - MEM_freeN(region); - } - } - - MEM_freeN(edges); - BLI_gset_free(visit_face_set, NULL); - - return count; + GSet *visit_face_set; + BMIter iter; + const int edges_len = em->bm->totedgesel; + BMEdge *e, **edges; + int count = 0, i; + + visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len); + edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__); + + i = 0; + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + edges[i++] = e; + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(e, BM_ELEM_TAG); + } + } + + /* sort edges by radial cycle length */ + qsort(edges, edges_len, sizeof(*edges), verg_radial); + + for (i = 0; i < edges_len; i++) { + BMIter liter; + BMLoop *l; + BMFace **region = NULL, **region_out; + int c, tot = 0; + + e = edges[i]; + + if (!BM_elem_flag_test(e, BM_ELEM_TAG)) + continue; + + BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { + if (BLI_gset_haskey(visit_face_set, l->f)) + continue; + + c = loop_find_region(l, BM_ELEM_SELECT, visit_face_set, ®ion_out); + + if (!region || (selbigger ? c >= tot : c < tot)) { + /* this region is the best seen so far */ + tot = c; + if (region) { + /* free the previous best */ + MEM_freeN(region); + } + /* track the current region as the new best */ + region = region_out; + } + else { + /* this region is not as good as best so far, just free it */ + MEM_freeN(region_out); + } + } + + if (region) { + int j; + + for (j = 0; j < tot; j++) { + BM_elem_flag_enable(region[j], BM_ELEM_TAG); + BM_ITER_ELEM (l, &liter, region[j], BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l->e, BM_ELEM_TAG); + } + } + + count += tot; + + MEM_freeN(region); + } + } + + MEM_freeN(edges); + BLI_gset_free(visit_face_set, NULL); + + return count; } static int edbm_loop_to_region_exec(bContext *C, wmOperator *op) { - const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger"); + const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totedgesel == 0) { - continue; - } + if (em->bm->totedgesel == 0) { + continue; + } - BMIter iter; - BMFace *f; + BMIter iter; + BMFace *f; - /* find the set of regions with smallest number of total faces */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - const int a = loop_find_regions(em, select_bigger); - const int b = loop_find_regions(em, !select_bigger); + /* find the set of regions with smallest number of total faces */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + const int a = loop_find_regions(em, select_bigger); + const int b = loop_find_regions(em, !select_bigger); - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger); + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BM_ITER_MESH(f, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - BM_face_select_set(em->bm, f, true); - } - } + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + BM_face_select_set(em->bm, f, true); + } + } - EDBM_selectmode_flush(em); + EDBM_selectmode_flush(em); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - MEM_freeN(objects); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_loop_to_region(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Loop Inner-Region"; - ot->idname = "MESH_OT_loop_to_region"; - ot->description = "Select region of faces inside of a selected loop of edges"; - - /* api callbacks */ - ot->exec = edbm_loop_to_region_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones"); + /* identifiers */ + ot->name = "Select Loop Inner-Region"; + ot->idname = "MESH_OT_loop_to_region"; + ot->description = "Select region of faces inside of a selected loop of edges"; + + /* api callbacks */ + ot->exec = edbm_loop_to_region_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, + "select_bigger", + 0, + "Select Bigger", + "Select bigger regions instead of smaller ones"); } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index 67e455375df..3006e2ed73d 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -45,66 +45,66 @@ #include "ED_screen.h" #include "ED_select_utils.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /* -------------------------------------------------------------------- */ /** \name Select Similar (Vert/Edge/Face) Operator - common * \{ */ static const EnumPropertyItem prop_similar_compare_types[] = { - {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""}, - {SIM_CMP_GT, "GREATER", 0, "Greater", ""}, - {SIM_CMP_LT, "LESS", 0, "Less", ""}, + {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""}, + {SIM_CMP_GT, "GREATER", 0, "Greater", ""}, + {SIM_CMP_LT, "LESS", 0, "Less", ""}, - {0, NULL, 0, NULL, NULL}, + {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_similar_types[] = { - {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""}, - {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""}, - {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""}, - {SIMVERT_EDGE, "EDGE", 0, "Amount of connecting edges", ""}, - - {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""}, - {SIMEDGE_DIR, "DIR", 0, "Direction", ""}, - {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""}, - {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""}, - {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""}, - {SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""}, - {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""}, - {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""}, + {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""}, + {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""}, + {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""}, + {SIMVERT_EDGE, "EDGE", 0, "Amount of connecting edges", ""}, + + {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""}, + {SIMEDGE_DIR, "DIR", 0, "Direction", ""}, + {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""}, + {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""}, + {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""}, + {SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""}, + {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""}, + {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""}, #ifdef WITH_FREESTYLE - {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""}, + {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""}, #endif - {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""}, - {SIMFACE_AREA, "AREA", 0, "Area", ""}, - {SIMFACE_SIDES, "SIDES", 0, "Polygon Sides", ""}, - {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""}, - {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""}, - {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""}, - {SIMFACE_SMOOTH, "SMOOTH", 0, "Flat/Smooth", ""}, - {SIMFACE_FACEMAP, "FACE_MAP", 0, "Face-Map", ""}, + {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""}, + {SIMFACE_AREA, "AREA", 0, "Area", ""}, + {SIMFACE_SIDES, "SIDES", 0, "Polygon Sides", ""}, + {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""}, + {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""}, + {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""}, + {SIMFACE_SMOOTH, "SMOOTH", 0, "Flat/Smooth", ""}, + {SIMFACE_FACEMAP, "FACE_MAP", 0, "Face-Map", ""}, #ifdef WITH_FREESTYLE - {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""}, + {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""}, #endif - {0, NULL, 0, NULL, NULL}, + {0, NULL, 0, NULL, NULL}, }; static int mesh_select_similar_compare_int(const int delta, const int compare) { - switch (compare) { - case SIM_CMP_EQ: - return (delta == 0); - case SIM_CMP_GT: - return (delta > 0); - case SIM_CMP_LT: - return (delta < 0); - default: - BLI_assert(0); - return 0; - } + switch (compare) { + case SIM_CMP_EQ: + return (delta == 0); + case SIM_CMP_GT: + return (delta > 0); + case SIM_CMP_LT: + return (delta < 0); + default: + BLI_assert(0); + return 0; + } } /** \} */ @@ -114,10 +114,10 @@ static int mesh_select_similar_compare_int(const int delta, const int compare) * \{ */ enum { - SIMFACE_DATA_NONE = 0, - SIMFACE_DATA_TRUE = (1 << 0), - SIMFACE_DATA_FALSE = (1 << 1), - SIMFACE_DATA_ALL = (SIMFACE_DATA_TRUE | SIMFACE_DATA_FALSE), + SIMFACE_DATA_NONE = 0, + SIMFACE_DATA_TRUE = (1 << 0), + SIMFACE_DATA_FALSE = (1 << 1), + SIMFACE_DATA_ALL = (SIMFACE_DATA_TRUE | SIMFACE_DATA_FALSE), }; /** @@ -127,14 +127,14 @@ enum { */ static bool face_data_value_set(BMFace *face, const int hflag, int *r_value) { - if (BM_elem_flag_test(face, hflag)) { - *r_value |= SIMFACE_DATA_TRUE; - } - else { - *r_value |= SIMFACE_DATA_FALSE; - } - - return *r_value != SIMFACE_DATA_ALL; + if (BM_elem_flag_test(face, hflag)) { + *r_value |= SIMFACE_DATA_TRUE; + } + else { + *r_value |= SIMFACE_DATA_FALSE; + } + + return *r_value != SIMFACE_DATA_ALL; } /** @@ -142,12 +142,12 @@ static bool face_data_value_set(BMFace *face, const int hflag, int *r_value) */ static void face_to_plane(const Object *ob, BMFace *face, float r_plane[4]) { - float normal[3], co[3]; - copy_v3_v3(normal, face->no); - mul_transposed_mat3_m4_v3(ob->imat, normal); - normalize_v3(normal); - mul_v3_m4v3(co, ob->obmat, BM_FACE_FIRST_LOOP(face)->v->co); - plane_from_point_normal_v3(r_plane, co, normal); + float normal[3], co[3]; + copy_v3_v3(normal, face->no); + mul_transposed_mat3_m4_v3(ob->imat, normal); + normalize_v3(normal); + mul_v3_m4v3(co, ob->obmat, BM_FACE_FIRST_LOOP(face)->v->co); + plane_from_point_normal_v3(r_plane, co, normal); } /* TODO(dfelinto): `types` that should technically be compared in world space but are not: @@ -156,418 +156,390 @@ static void face_to_plane(const Object *ob, BMFace *face, float r_plane[4]) */ static int similar_face_select_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - - const int type = RNA_enum_get(op->ptr, "type"); - const float thresh = RNA_float_get(op->ptr, "threshold"); - const float thresh_radians = thresh * (float)M_PI; - const int compare = RNA_enum_get(op->ptr, "compare"); - - int tot_faces_selected_all = 0; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - tot_faces_selected_all += em->bm->totfacesel; - } - - if (tot_faces_selected_all == 0) { - BKE_report(op->reports, RPT_ERROR, "No face selected"); - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - - KDTree_1d *tree_1d = NULL; - KDTree_3d *tree_3d = NULL; - KDTree_4d *tree_4d = NULL; - GSet *gset = NULL; - GSet **gset_array = NULL; - int face_data_value = SIMFACE_DATA_NONE; - - switch (type) { - case SIMFACE_AREA: - case SIMFACE_PERIMETER: - tree_1d = BLI_kdtree_1d_new(tot_faces_selected_all); - break; - case SIMFACE_NORMAL: - tree_3d = BLI_kdtree_3d_new(tot_faces_selected_all); - break; - case SIMFACE_COPLANAR: - tree_4d = BLI_kdtree_4d_new(tot_faces_selected_all); - break; - case SIMFACE_SIDES: - case SIMFACE_MATERIAL: - gset = BLI_gset_ptr_new("Select similar face"); - break; - case SIMFACE_FACEMAP: - gset_array = MEM_callocN(sizeof(GSet *) * objects_len, "Select similar face: facemap gset array"); - break; - } - - int tree_index = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - Material ***material_array = NULL; - invert_m4_m4(ob->imat, ob->obmat); - int custom_data_offset = 0; - - if (bm->totfacesel == 0) { - continue; - } - - float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); - - switch (type) { - case SIMFACE_MATERIAL: - { - if (ob->totcol == 0) { - continue; - } - material_array = give_matarar(ob); - break; - } - case SIMFACE_FREESTYLE: - { - if (!CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) { - face_data_value |= SIMFACE_DATA_FALSE; - continue; - } - break; - } - case SIMFACE_FACEMAP: - { - custom_data_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP); - if (custom_data_offset == -1) { - continue; - } - else { - gset_array[ob_index] = BLI_gset_ptr_new("Select similar face: facemap gset"); - } - } - } - - BMFace *face; /* Mesh face. */ - BMIter iter; /* Selected faces iterator. */ - - BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(face, BM_ELEM_SELECT)) { - switch (type) { - case SIMFACE_SIDES: - BLI_gset_add(gset, POINTER_FROM_INT(face->len)); - break; - case SIMFACE_MATERIAL: - { - Material *material = (*material_array)[face->mat_nr]; - if (material != NULL) { - BLI_gset_add(gset, material); - } - break; - } - case SIMFACE_AREA: - { - float area = BM_face_calc_area_with_mat3(face, ob_m3); - BLI_kdtree_1d_insert(tree_1d, tree_index++, &area); - break; - } - case SIMFACE_PERIMETER: - { - float perimeter = BM_face_calc_perimeter_with_mat3(face, ob_m3); - BLI_kdtree_1d_insert(tree_1d, tree_index++, &perimeter); - break; - } - case SIMFACE_NORMAL: - { - float normal[3]; - copy_v3_v3(normal, face->no); - mul_transposed_mat3_m4_v3(ob->imat, normal); - normalize_v3(normal); - BLI_kdtree_3d_insert(tree_3d, tree_index++, normal); - break; - } - case SIMFACE_COPLANAR: - { - float plane[4]; - face_to_plane(ob, face, plane); - BLI_kdtree_4d_insert(tree_4d, tree_index++, plane); - break; - } - case SIMFACE_SMOOTH: - { - if (!face_data_value_set(face, BM_ELEM_SMOOTH, &face_data_value)) { - goto face_select_all; - } - break; - } - case SIMFACE_FREESTYLE: - { - FreestyleFace *fface; - fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_FREESTYLE_FACE); - if ((fface == NULL) || ((fface->flag & FREESTYLE_FACE_MARK) == 0)) { - face_data_value |= SIMFACE_DATA_FALSE; - } - else { - face_data_value |= SIMFACE_DATA_TRUE; - } - if (face_data_value == SIMFACE_DATA_ALL) { - goto face_select_all; - } - break; - } - case SIMFACE_FACEMAP: - { - BLI_assert(custom_data_offset != -1); - int *face_map = BM_ELEM_CD_GET_VOID_P(face, custom_data_offset); - BLI_gset_add(gset_array[ob_index], face_map); - break; - } - } - } - } - } - - BLI_assert((type != SIMFACE_FREESTYLE) || (face_data_value != SIMFACE_DATA_NONE)); - - if (tree_1d != NULL) { - BLI_kdtree_1d_deduplicate(tree_1d); - BLI_kdtree_1d_balance(tree_1d); - } - if (tree_3d != NULL) { - BLI_kdtree_3d_deduplicate(tree_3d); - BLI_kdtree_3d_balance(tree_3d); - } - if (tree_4d != NULL) { - BLI_kdtree_4d_deduplicate(tree_4d); - BLI_kdtree_4d_balance(tree_4d); - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - bool changed = false; - Material ***material_array = NULL; - int custom_data_offset; - - float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); - - bool has_custom_data_layer = false; - switch (type) { - case SIMFACE_MATERIAL: - { - if (ob->totcol == 0) { - continue; - } - material_array = give_matarar(ob); - break; - } - case SIMFACE_FREESTYLE: - { - has_custom_data_layer = CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE); - if ((face_data_value == SIMFACE_DATA_TRUE) && !has_custom_data_layer) { - continue; - } - break; - } - case SIMFACE_FACEMAP: - { - custom_data_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP); - if (custom_data_offset == -1) { - continue; - } - } - } - - BMFace *face; /* Mesh face. */ - BMIter iter; /* Selected faces iterator. */ - - BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(face, BM_ELEM_SELECT) && - !BM_elem_flag_test(face, BM_ELEM_HIDDEN)) - { - bool select = false; - switch (type) { - case SIMFACE_SIDES: - { - const int num_sides = face->len; - GSetIterator gs_iter; - GSET_ITER(gs_iter, gset) { - const int num_sides_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); - const int delta_i = num_sides - num_sides_iter; - if (mesh_select_similar_compare_int(delta_i, compare)) { - select = true; - break; - } - } - break; - } - case SIMFACE_MATERIAL: - { - const Material *material = (*material_array)[face->mat_nr]; - if (material == NULL) { - continue; - } - - GSetIterator gs_iter; - GSET_ITER(gs_iter, gset) { - const Material *material_iter = BLI_gsetIterator_getKey(&gs_iter); - if (material == material_iter) { - select = true; - break; - } - } - break; - } - case SIMFACE_AREA: - { - float area = BM_face_calc_area_with_mat3(face, ob_m3); - if (ED_select_similar_compare_float_tree(tree_1d, area, thresh, compare)) { - select = true; - } - break; - } - case SIMFACE_PERIMETER: - { - float perimeter = BM_face_calc_perimeter_with_mat3(face, ob_m3); - if (ED_select_similar_compare_float_tree(tree_1d, perimeter, thresh, compare)) { - select = true; - } - break; - } - case SIMFACE_NORMAL: - { - float normal[3]; - copy_v3_v3(normal, face->no); - mul_transposed_mat3_m4_v3(ob->imat, normal); - normalize_v3(normal); - - /* We are treating the normals as coordinates, the "nearest" one will - * also be the one closest to the angle. */ - KDTreeNearest_3d nearest; - if (BLI_kdtree_3d_find_nearest(tree_3d, normal, &nearest) != -1) { - if (angle_normalized_v3v3(normal, nearest.co) <= thresh_radians) { - select = true; - } - } - break; - } - case SIMFACE_COPLANAR: - { - float plane[4]; - face_to_plane(ob, face, plane); - - KDTreeNearest_4d nearest; - if (BLI_kdtree_4d_find_nearest(tree_4d, plane, &nearest) != -1) { - if (nearest.dist <= thresh) { - if ((fabsf(plane[3] - nearest.co[3]) <= thresh) && - (angle_v3v3(plane, nearest.co) <= thresh_radians)) - { - select = true; - } - } - } - break; - } - case SIMFACE_SMOOTH: - if ((BM_elem_flag_test(face, BM_ELEM_SMOOTH) != 0) == - ((face_data_value & SIMFACE_DATA_TRUE) != 0)) - { - select = true; - } - break; - case SIMFACE_FREESTYLE: - { - FreestyleFace *fface; - - if (!has_custom_data_layer) { - BLI_assert(face_data_value == SIMFACE_DATA_FALSE); - select = true; - break; - } - - fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_FREESTYLE_FACE); - if (((fface != NULL) && (fface->flag & FREESTYLE_FACE_MARK)) == - ((face_data_value & SIMFACE_DATA_TRUE) != 0)) - { - select = true; - } - break; - } - case SIMFACE_FACEMAP: - { - const int *face_map = BM_ELEM_CD_GET_VOID_P(face, custom_data_offset); - GSetIterator gs_iter; - GSET_ITER(gs_iter, gset_array[ob_index]) { - const int *face_map_iter = BLI_gsetIterator_getKey(&gs_iter); - if (*face_map == *face_map_iter) { - select = true; - break; - } - } - break; - } - } - - if (select) { - BM_face_select_set(bm, face, true); - changed = true; - } - } - } - - if (changed) { - EDBM_selectmode_flush(em); - EDBM_update_generic(em, false, false); - } - } - - if (false) { -face_select_all: - BLI_assert(ELEM(type, - SIMFACE_SMOOTH, - SIMFACE_FREESTYLE - )); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - - BMFace *face; /* Mesh face. */ - BMIter iter; /* Selected faces iterator. */ - - BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(face, BM_ELEM_SELECT)) { - BM_face_select_set(bm, face, true); - } - } - EDBM_selectmode_flush(em); - EDBM_update_generic(em, false, false); - } - } - - MEM_freeN(objects); - BLI_kdtree_1d_free(tree_1d); - BLI_kdtree_3d_free(tree_3d); - BLI_kdtree_4d_free(tree_4d); - if (gset != NULL) { - BLI_gset_free(gset, NULL); - } - if (gset_array != NULL) { - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - if (gset_array[ob_index] != NULL) { - BLI_gset_free(gset_array[ob_index], NULL); - } - } - MEM_freeN(gset_array); - } - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + + const int type = RNA_enum_get(op->ptr, "type"); + const float thresh = RNA_float_get(op->ptr, "threshold"); + const float thresh_radians = thresh * (float)M_PI; + const int compare = RNA_enum_get(op->ptr, "compare"); + + int tot_faces_selected_all = 0; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + tot_faces_selected_all += em->bm->totfacesel; + } + + if (tot_faces_selected_all == 0) { + BKE_report(op->reports, RPT_ERROR, "No face selected"); + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + + KDTree_1d *tree_1d = NULL; + KDTree_3d *tree_3d = NULL; + KDTree_4d *tree_4d = NULL; + GSet *gset = NULL; + GSet **gset_array = NULL; + int face_data_value = SIMFACE_DATA_NONE; + + switch (type) { + case SIMFACE_AREA: + case SIMFACE_PERIMETER: + tree_1d = BLI_kdtree_1d_new(tot_faces_selected_all); + break; + case SIMFACE_NORMAL: + tree_3d = BLI_kdtree_3d_new(tot_faces_selected_all); + break; + case SIMFACE_COPLANAR: + tree_4d = BLI_kdtree_4d_new(tot_faces_selected_all); + break; + case SIMFACE_SIDES: + case SIMFACE_MATERIAL: + gset = BLI_gset_ptr_new("Select similar face"); + break; + case SIMFACE_FACEMAP: + gset_array = MEM_callocN(sizeof(GSet *) * objects_len, + "Select similar face: facemap gset array"); + break; + } + + int tree_index = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + Material ***material_array = NULL; + invert_m4_m4(ob->imat, ob->obmat); + int custom_data_offset = 0; + + if (bm->totfacesel == 0) { + continue; + } + + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + switch (type) { + case SIMFACE_MATERIAL: { + if (ob->totcol == 0) { + continue; + } + material_array = give_matarar(ob); + break; + } + case SIMFACE_FREESTYLE: { + if (!CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) { + face_data_value |= SIMFACE_DATA_FALSE; + continue; + } + break; + } + case SIMFACE_FACEMAP: { + custom_data_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP); + if (custom_data_offset == -1) { + continue; + } + else { + gset_array[ob_index] = BLI_gset_ptr_new("Select similar face: facemap gset"); + } + } + } + + BMFace *face; /* Mesh face. */ + BMIter iter; /* Selected faces iterator. */ + + BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(face, BM_ELEM_SELECT)) { + switch (type) { + case SIMFACE_SIDES: + BLI_gset_add(gset, POINTER_FROM_INT(face->len)); + break; + case SIMFACE_MATERIAL: { + Material *material = (*material_array)[face->mat_nr]; + if (material != NULL) { + BLI_gset_add(gset, material); + } + break; + } + case SIMFACE_AREA: { + float area = BM_face_calc_area_with_mat3(face, ob_m3); + BLI_kdtree_1d_insert(tree_1d, tree_index++, &area); + break; + } + case SIMFACE_PERIMETER: { + float perimeter = BM_face_calc_perimeter_with_mat3(face, ob_m3); + BLI_kdtree_1d_insert(tree_1d, tree_index++, &perimeter); + break; + } + case SIMFACE_NORMAL: { + float normal[3]; + copy_v3_v3(normal, face->no); + mul_transposed_mat3_m4_v3(ob->imat, normal); + normalize_v3(normal); + BLI_kdtree_3d_insert(tree_3d, tree_index++, normal); + break; + } + case SIMFACE_COPLANAR: { + float plane[4]; + face_to_plane(ob, face, plane); + BLI_kdtree_4d_insert(tree_4d, tree_index++, plane); + break; + } + case SIMFACE_SMOOTH: { + if (!face_data_value_set(face, BM_ELEM_SMOOTH, &face_data_value)) { + goto face_select_all; + } + break; + } + case SIMFACE_FREESTYLE: { + FreestyleFace *fface; + fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_FREESTYLE_FACE); + if ((fface == NULL) || ((fface->flag & FREESTYLE_FACE_MARK) == 0)) { + face_data_value |= SIMFACE_DATA_FALSE; + } + else { + face_data_value |= SIMFACE_DATA_TRUE; + } + if (face_data_value == SIMFACE_DATA_ALL) { + goto face_select_all; + } + break; + } + case SIMFACE_FACEMAP: { + BLI_assert(custom_data_offset != -1); + int *face_map = BM_ELEM_CD_GET_VOID_P(face, custom_data_offset); + BLI_gset_add(gset_array[ob_index], face_map); + break; + } + } + } + } + } + + BLI_assert((type != SIMFACE_FREESTYLE) || (face_data_value != SIMFACE_DATA_NONE)); + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + if (tree_3d != NULL) { + BLI_kdtree_3d_deduplicate(tree_3d); + BLI_kdtree_3d_balance(tree_3d); + } + if (tree_4d != NULL) { + BLI_kdtree_4d_deduplicate(tree_4d); + BLI_kdtree_4d_balance(tree_4d); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + bool changed = false; + Material ***material_array = NULL; + int custom_data_offset; + + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + bool has_custom_data_layer = false; + switch (type) { + case SIMFACE_MATERIAL: { + if (ob->totcol == 0) { + continue; + } + material_array = give_matarar(ob); + break; + } + case SIMFACE_FREESTYLE: { + has_custom_data_layer = CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE); + if ((face_data_value == SIMFACE_DATA_TRUE) && !has_custom_data_layer) { + continue; + } + break; + } + case SIMFACE_FACEMAP: { + custom_data_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP); + if (custom_data_offset == -1) { + continue; + } + } + } + + BMFace *face; /* Mesh face. */ + BMIter iter; /* Selected faces iterator. */ + + BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(face, BM_ELEM_SELECT) && !BM_elem_flag_test(face, BM_ELEM_HIDDEN)) { + bool select = false; + switch (type) { + case SIMFACE_SIDES: { + const int num_sides = face->len; + GSetIterator gs_iter; + GSET_ITER (gs_iter, gset) { + const int num_sides_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); + const int delta_i = num_sides - num_sides_iter; + if (mesh_select_similar_compare_int(delta_i, compare)) { + select = true; + break; + } + } + break; + } + case SIMFACE_MATERIAL: { + const Material *material = (*material_array)[face->mat_nr]; + if (material == NULL) { + continue; + } + + GSetIterator gs_iter; + GSET_ITER (gs_iter, gset) { + const Material *material_iter = BLI_gsetIterator_getKey(&gs_iter); + if (material == material_iter) { + select = true; + break; + } + } + break; + } + case SIMFACE_AREA: { + float area = BM_face_calc_area_with_mat3(face, ob_m3); + if (ED_select_similar_compare_float_tree(tree_1d, area, thresh, compare)) { + select = true; + } + break; + } + case SIMFACE_PERIMETER: { + float perimeter = BM_face_calc_perimeter_with_mat3(face, ob_m3); + if (ED_select_similar_compare_float_tree(tree_1d, perimeter, thresh, compare)) { + select = true; + } + break; + } + case SIMFACE_NORMAL: { + float normal[3]; + copy_v3_v3(normal, face->no); + mul_transposed_mat3_m4_v3(ob->imat, normal); + normalize_v3(normal); + + /* We are treating the normals as coordinates, the "nearest" one will + * also be the one closest to the angle. */ + KDTreeNearest_3d nearest; + if (BLI_kdtree_3d_find_nearest(tree_3d, normal, &nearest) != -1) { + if (angle_normalized_v3v3(normal, nearest.co) <= thresh_radians) { + select = true; + } + } + break; + } + case SIMFACE_COPLANAR: { + float plane[4]; + face_to_plane(ob, face, plane); + + KDTreeNearest_4d nearest; + if (BLI_kdtree_4d_find_nearest(tree_4d, plane, &nearest) != -1) { + if (nearest.dist <= thresh) { + if ((fabsf(plane[3] - nearest.co[3]) <= thresh) && + (angle_v3v3(plane, nearest.co) <= thresh_radians)) { + select = true; + } + } + } + break; + } + case SIMFACE_SMOOTH: + if ((BM_elem_flag_test(face, BM_ELEM_SMOOTH) != 0) == + ((face_data_value & SIMFACE_DATA_TRUE) != 0)) { + select = true; + } + break; + case SIMFACE_FREESTYLE: { + FreestyleFace *fface; + + if (!has_custom_data_layer) { + BLI_assert(face_data_value == SIMFACE_DATA_FALSE); + select = true; + break; + } + + fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_FREESTYLE_FACE); + if (((fface != NULL) && (fface->flag & FREESTYLE_FACE_MARK)) == + ((face_data_value & SIMFACE_DATA_TRUE) != 0)) { + select = true; + } + break; + } + case SIMFACE_FACEMAP: { + const int *face_map = BM_ELEM_CD_GET_VOID_P(face, custom_data_offset); + GSetIterator gs_iter; + GSET_ITER (gs_iter, gset_array[ob_index]) { + const int *face_map_iter = BLI_gsetIterator_getKey(&gs_iter); + if (*face_map == *face_map_iter) { + select = true; + break; + } + } + break; + } + } + + if (select) { + BM_face_select_set(bm, face, true); + changed = true; + } + } + } + + if (changed) { + EDBM_selectmode_flush(em); + EDBM_update_generic(em, false, false); + } + } + + if (false) { + face_select_all: + BLI_assert(ELEM(type, SIMFACE_SMOOTH, SIMFACE_FREESTYLE)); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + + BMFace *face; /* Mesh face. */ + BMIter iter; /* Selected faces iterator. */ + + BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(face, BM_ELEM_SELECT)) { + BM_face_select_set(bm, face, true); + } + } + EDBM_selectmode_flush(em); + EDBM_update_generic(em, false, false); + } + } + + MEM_freeN(objects); + BLI_kdtree_1d_free(tree_1d); + BLI_kdtree_3d_free(tree_3d); + BLI_kdtree_4d_free(tree_4d); + if (gset != NULL) { + BLI_gset_free(gset, NULL); + } + if (gset_array != NULL) { + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + if (gset_array[ob_index] != NULL) { + BLI_gset_free(gset_array[ob_index], NULL); + } + } + MEM_freeN(gset_array); + } + + return OPERATOR_FINISHED; } /** \} */ @@ -576,7 +548,6 @@ face_select_all: /** \name Select Similar Edge * \{ */ - /** * Note: This is not normal, but the edge direction itself and always in * a positive quadrant (tries z, y then x). @@ -584,48 +555,48 @@ face_select_all: */ static void edge_pos_direction_worldspace_get(Object *ob, BMEdge *edge, float *r_dir) { - float v1[3], v2[3]; - copy_v3_v3(v1, edge->v1->co); - copy_v3_v3(v2, edge->v2->co); - - mul_m4_v3(ob->obmat, v1); - mul_m4_v3(ob->obmat, v2); - - sub_v3_v3v3(r_dir, v1, v2); - normalize_v3(r_dir); - - /* Make sure we have a consistent direction that can be checked regardless of - * the verts order of the edges. This spares us from storing dir and -dir in the tree_3d. */ - if (fabs(r_dir[2]) < FLT_EPSILON) { - if (fabs(r_dir[1]) < FLT_EPSILON) { - if (r_dir[0] < 0.0f) { - mul_v3_fl(r_dir, -1.0f); - } - } - else if (r_dir[1] < 0.0f) { - mul_v3_fl(r_dir, -1.0f); - } - } - else if (r_dir[2] < 0.0f) { - mul_v3_fl(r_dir, -1.0f); - } + float v1[3], v2[3]; + copy_v3_v3(v1, edge->v1->co); + copy_v3_v3(v2, edge->v2->co); + + mul_m4_v3(ob->obmat, v1); + mul_m4_v3(ob->obmat, v2); + + sub_v3_v3v3(r_dir, v1, v2); + normalize_v3(r_dir); + + /* Make sure we have a consistent direction that can be checked regardless of + * the verts order of the edges. This spares us from storing dir and -dir in the tree_3d. */ + if (fabs(r_dir[2]) < FLT_EPSILON) { + if (fabs(r_dir[1]) < FLT_EPSILON) { + if (r_dir[0] < 0.0f) { + mul_v3_fl(r_dir, -1.0f); + } + } + else if (r_dir[1] < 0.0f) { + mul_v3_fl(r_dir, -1.0f); + } + } + else if (r_dir[2] < 0.0f) { + mul_v3_fl(r_dir, -1.0f); + } } static float edge_length_squared_worldspace_get(Object *ob, BMEdge *edge) { - float v1[3], v2[3]; + float v1[3], v2[3]; - mul_v3_mat3_m4v3(v1, ob->obmat, edge->v1->co); - mul_v3_mat3_m4v3(v2, ob->obmat, edge->v2->co); + mul_v3_mat3_m4v3(v1, ob->obmat, edge->v1->co); + mul_v3_mat3_m4v3(v2, ob->obmat, edge->v2->co); - return len_squared_v3v3(v1, v2); + return len_squared_v3v3(v1, v2); } enum { - SIMEDGE_DATA_NONE = 0, - SIMEDGE_DATA_TRUE = (1 << 0), - SIMEDGE_DATA_FALSE = (1 << 1), - SIMEDGE_DATA_ALL = (SIMEDGE_DATA_TRUE | SIMEDGE_DATA_FALSE), + SIMEDGE_DATA_NONE = 0, + SIMEDGE_DATA_TRUE = (1 << 0), + SIMEDGE_DATA_FALSE = (1 << 1), + SIMEDGE_DATA_ALL = (SIMEDGE_DATA_TRUE | SIMEDGE_DATA_FALSE), }; /** @@ -635,14 +606,14 @@ enum { */ static bool edge_data_value_set(BMEdge *edge, const int hflag, int *r_value) { - if (BM_elem_flag_test(edge, hflag)) { - *r_value |= SIMEDGE_DATA_TRUE; - } - else { - *r_value |= SIMEDGE_DATA_FALSE; - } - - return *r_value != SIMEDGE_DATA_ALL; + if (BM_elem_flag_test(edge, hflag)) { + *r_value |= SIMEDGE_DATA_TRUE; + } + else { + *r_value |= SIMEDGE_DATA_FALSE; + } + + return *r_value != SIMEDGE_DATA_ALL; } /* TODO(dfelinto): `types` that should technically be compared in world space but are not: @@ -650,357 +621,336 @@ static bool edge_data_value_set(BMEdge *edge, const int hflag, int *r_value) */ static int similar_edge_select_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - - const int type = RNA_enum_get(op->ptr, "type"); - const float thresh = RNA_float_get(op->ptr, "threshold"); - const float thresh_radians = thresh * (float)M_PI + FLT_EPSILON; - const int compare = RNA_enum_get(op->ptr, "compare"); - int custom_data_type = -1; - - int tot_edges_selected_all = 0; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - tot_edges_selected_all += em->bm->totedgesel; - } - - if (tot_edges_selected_all == 0) { - BKE_report(op->reports, RPT_ERROR, "No edge selected"); - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - - KDTree_1d *tree_1d = NULL; - KDTree_3d *tree_3d = NULL; - GSet *gset = NULL; - int edge_data_value = SIMEDGE_DATA_NONE; - - switch (type) { - case SIMEDGE_CREASE: - case SIMEDGE_BEVEL: - case SIMEDGE_FACE_ANGLE: - case SIMEDGE_LENGTH: - tree_1d = BLI_kdtree_1d_new(tot_edges_selected_all); - break; - case SIMEDGE_DIR: - tree_3d = BLI_kdtree_3d_new(tot_edges_selected_all); - break; - case SIMEDGE_FACE: - gset = BLI_gset_ptr_new("Select similar edge: face"); - break; - } - - switch (type) { - case SIMEDGE_CREASE: - custom_data_type = CD_CREASE; - break; - case SIMEDGE_BEVEL: - custom_data_type = CD_BWEIGHT; - break; - } - - int tree_index = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - - if (bm->totedgesel == 0) { - continue; - } - - switch (type) { - case SIMEDGE_FREESTYLE: - { - if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) { - edge_data_value |= SIMEDGE_DATA_FALSE; - continue; - } - break; - } - case SIMEDGE_CREASE: - case SIMEDGE_BEVEL: - { - if (!CustomData_has_layer(&bm->edata, custom_data_type)) { - BLI_kdtree_1d_insert(tree_1d, tree_index++, (float[1]){0.0f}); - continue; - } - break; - } - } - - float ob_m3[3][3], ob_m3_inv[3][3]; - copy_m3_m4(ob_m3, ob->obmat); - invert_m3_m3(ob_m3_inv, ob_m3); - - BMEdge *edge; /* Mesh edge. */ - BMIter iter; /* Selected edges iterator. */ - - BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(edge, BM_ELEM_SELECT)) { - switch (type) { - case SIMEDGE_FACE: - BLI_gset_add(gset, POINTER_FROM_INT(BM_edge_face_count(edge))); - break; - case SIMEDGE_DIR: - { - float dir[3]; - edge_pos_direction_worldspace_get(ob, edge, dir); - BLI_kdtree_3d_insert(tree_3d, tree_index++, dir); - break; - } - case SIMEDGE_LENGTH: - { - float length = edge_length_squared_worldspace_get(ob, edge); - BLI_kdtree_1d_insert(tree_1d, tree_index++, &length); - break; - } - case SIMEDGE_FACE_ANGLE: - { - if (BM_edge_face_count_at_most(edge, 2) == 2) { - float angle = BM_edge_calc_face_angle_with_imat3(edge, ob_m3_inv); - BLI_kdtree_1d_insert(tree_1d, tree_index++, &angle); - } - break; - } - case SIMEDGE_SEAM: - if (!edge_data_value_set(edge, BM_ELEM_SEAM, &edge_data_value)) { - goto edge_select_all; - } - break; - case SIMEDGE_SHARP: - if (!edge_data_value_set(edge, BM_ELEM_SMOOTH, &edge_data_value)) { - goto edge_select_all; - } - break; - case SIMEDGE_FREESTYLE: - { - FreestyleEdge *fedge; - fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE); - if ((fedge == NULL) || ((fedge->flag & FREESTYLE_EDGE_MARK) == 0)) { - edge_data_value |= SIMEDGE_DATA_FALSE; - } - else { - edge_data_value |= SIMEDGE_DATA_TRUE; - } - if (edge_data_value == SIMEDGE_DATA_ALL) { - goto edge_select_all; - } - break; - } - case SIMEDGE_CREASE: - case SIMEDGE_BEVEL: - { - const float *value = CustomData_bmesh_get(&bm->edata, edge->head.data, custom_data_type); - BLI_kdtree_1d_insert(tree_1d, tree_index++, value); - break; - } - } - } - } - } - - BLI_assert((type != SIMEDGE_FREESTYLE) || (edge_data_value != SIMEDGE_DATA_NONE)); - - if (tree_1d != NULL) { - BLI_kdtree_1d_deduplicate(tree_1d); - BLI_kdtree_1d_balance(tree_1d); - } - if (tree_3d != NULL) { - BLI_kdtree_3d_deduplicate(tree_3d); - BLI_kdtree_3d_balance(tree_3d); - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - bool changed = false; - - bool has_custom_data_layer = false; - switch (type) { - case SIMEDGE_FREESTYLE: - { - has_custom_data_layer = CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE); - if ((edge_data_value == SIMEDGE_DATA_TRUE) && !has_custom_data_layer) { - continue; - } - break; - } - case SIMEDGE_CREASE: - case SIMEDGE_BEVEL: - { - has_custom_data_layer = CustomData_has_layer(&bm->edata, custom_data_type); - if (!has_custom_data_layer) { - /* Proceed only if we have to select all the edges that have custom data value of 0.0f. - * In this case we will just select all the edges. - * Otherwise continue the for loop. */ - if (!ED_select_similar_compare_float_tree(tree_1d, 0.0f, thresh, compare)) { - continue; - } - } - } - } - - float ob_m3[3][3], ob_m3_inv[3][3]; - copy_m3_m4(ob_m3, ob->obmat); - invert_m3_m3(ob_m3_inv, ob_m3); - - BMEdge *edge; /* Mesh edge. */ - BMIter iter; /* Selected edges iterator. */ - - BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(edge, BM_ELEM_SELECT) && - !BM_elem_flag_test(edge, BM_ELEM_HIDDEN)) - { - bool select = false; - switch (type) { - case SIMEDGE_FACE: - { - const int num_faces = BM_edge_face_count(edge); - GSetIterator gs_iter; - GSET_ITER(gs_iter, gset) { - const int num_faces_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); - const int delta_i = num_faces - num_faces_iter; - if (mesh_select_similar_compare_int(delta_i, compare)) { - select = true; - break; - } - } - break; - } - case SIMEDGE_DIR: - { - float dir[3]; - edge_pos_direction_worldspace_get(ob, edge, dir); - - /* We are treating the direction as coordinates, the "nearest" one will - * also be the one closest to the intended direction. */ - KDTreeNearest_3d nearest; - if (BLI_kdtree_3d_find_nearest(tree_3d, dir, &nearest) != -1) { - if (angle_normalized_v3v3(dir, nearest.co) <= thresh_radians) { - select = true; - } - } - break; - } - case SIMEDGE_LENGTH: - { - float length = edge_length_squared_worldspace_get(ob, edge); - if (ED_select_similar_compare_float_tree(tree_1d, length, thresh, compare)) { - select = true; - } - break; - } - case SIMEDGE_FACE_ANGLE: - { - if (BM_edge_face_count_at_most(edge, 2) == 2) { - float angle = BM_edge_calc_face_angle_with_imat3(edge, ob_m3_inv); - if (ED_select_similar_compare_float_tree(tree_1d, angle, thresh, SIM_CMP_EQ)) { - select = true; - } - } - break; - } - case SIMEDGE_SEAM: - if ((BM_elem_flag_test(edge, BM_ELEM_SEAM) != 0) == - ((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) - { - select = true; - } - break; - case SIMEDGE_SHARP: - if ((BM_elem_flag_test(edge, BM_ELEM_SMOOTH) != 0) == - ((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) - { - select = true; - } - break; - case SIMEDGE_FREESTYLE: - { - FreestyleEdge *fedge; - - if (!has_custom_data_layer) { - BLI_assert(edge_data_value == SIMEDGE_DATA_FALSE); - select = true; - break; - } - - fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE); - if (((fedge != NULL) && (fedge->flag & FREESTYLE_EDGE_MARK)) == - ((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) - { - select = true; - } - break; - } - case SIMEDGE_CREASE: - case SIMEDGE_BEVEL: - { - if (!has_custom_data_layer) { - select = true; - break; - } - - const float *value = CustomData_bmesh_get(&bm->edata, edge->head.data, custom_data_type); - if (ED_select_similar_compare_float_tree(tree_1d, *value, thresh, compare)) { - select = true; - } - break; - } - } - - if (select) { - BM_edge_select_set(bm, edge, true); - changed = true; - } - } - } - - if (changed) { - EDBM_selectmode_flush(em); - EDBM_update_generic(em, false, false); - } - } - - if (false) { -edge_select_all: - BLI_assert(ELEM(type, - SIMEDGE_SEAM, - SIMEDGE_SHARP, - SIMEDGE_FREESTYLE - )); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - - BMEdge *edge; /* Mesh edge. */ - BMIter iter; /* Selected edges iterator. */ - - BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(edge, BM_ELEM_SELECT)) { - BM_edge_select_set(bm, edge, true); - } - } - EDBM_selectmode_flush(em); - EDBM_update_generic(em, false, false); - } - } - - MEM_freeN(objects); - BLI_kdtree_1d_free(tree_1d); - BLI_kdtree_3d_free(tree_3d); - if (gset != NULL) { - BLI_gset_free(gset, NULL); - } - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + + const int type = RNA_enum_get(op->ptr, "type"); + const float thresh = RNA_float_get(op->ptr, "threshold"); + const float thresh_radians = thresh * (float)M_PI + FLT_EPSILON; + const int compare = RNA_enum_get(op->ptr, "compare"); + int custom_data_type = -1; + + int tot_edges_selected_all = 0; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + tot_edges_selected_all += em->bm->totedgesel; + } + + if (tot_edges_selected_all == 0) { + BKE_report(op->reports, RPT_ERROR, "No edge selected"); + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + + KDTree_1d *tree_1d = NULL; + KDTree_3d *tree_3d = NULL; + GSet *gset = NULL; + int edge_data_value = SIMEDGE_DATA_NONE; + + switch (type) { + case SIMEDGE_CREASE: + case SIMEDGE_BEVEL: + case SIMEDGE_FACE_ANGLE: + case SIMEDGE_LENGTH: + tree_1d = BLI_kdtree_1d_new(tot_edges_selected_all); + break; + case SIMEDGE_DIR: + tree_3d = BLI_kdtree_3d_new(tot_edges_selected_all); + break; + case SIMEDGE_FACE: + gset = BLI_gset_ptr_new("Select similar edge: face"); + break; + } + + switch (type) { + case SIMEDGE_CREASE: + custom_data_type = CD_CREASE; + break; + case SIMEDGE_BEVEL: + custom_data_type = CD_BWEIGHT; + break; + } + + int tree_index = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + + if (bm->totedgesel == 0) { + continue; + } + + switch (type) { + case SIMEDGE_FREESTYLE: { + if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) { + edge_data_value |= SIMEDGE_DATA_FALSE; + continue; + } + break; + } + case SIMEDGE_CREASE: + case SIMEDGE_BEVEL: { + if (!CustomData_has_layer(&bm->edata, custom_data_type)) { + BLI_kdtree_1d_insert(tree_1d, tree_index++, (float[1]){0.0f}); + continue; + } + break; + } + } + + float ob_m3[3][3], ob_m3_inv[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + invert_m3_m3(ob_m3_inv, ob_m3); + + BMEdge *edge; /* Mesh edge. */ + BMIter iter; /* Selected edges iterator. */ + + BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(edge, BM_ELEM_SELECT)) { + switch (type) { + case SIMEDGE_FACE: + BLI_gset_add(gset, POINTER_FROM_INT(BM_edge_face_count(edge))); + break; + case SIMEDGE_DIR: { + float dir[3]; + edge_pos_direction_worldspace_get(ob, edge, dir); + BLI_kdtree_3d_insert(tree_3d, tree_index++, dir); + break; + } + case SIMEDGE_LENGTH: { + float length = edge_length_squared_worldspace_get(ob, edge); + BLI_kdtree_1d_insert(tree_1d, tree_index++, &length); + break; + } + case SIMEDGE_FACE_ANGLE: { + if (BM_edge_face_count_at_most(edge, 2) == 2) { + float angle = BM_edge_calc_face_angle_with_imat3(edge, ob_m3_inv); + BLI_kdtree_1d_insert(tree_1d, tree_index++, &angle); + } + break; + } + case SIMEDGE_SEAM: + if (!edge_data_value_set(edge, BM_ELEM_SEAM, &edge_data_value)) { + goto edge_select_all; + } + break; + case SIMEDGE_SHARP: + if (!edge_data_value_set(edge, BM_ELEM_SMOOTH, &edge_data_value)) { + goto edge_select_all; + } + break; + case SIMEDGE_FREESTYLE: { + FreestyleEdge *fedge; + fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE); + if ((fedge == NULL) || ((fedge->flag & FREESTYLE_EDGE_MARK) == 0)) { + edge_data_value |= SIMEDGE_DATA_FALSE; + } + else { + edge_data_value |= SIMEDGE_DATA_TRUE; + } + if (edge_data_value == SIMEDGE_DATA_ALL) { + goto edge_select_all; + } + break; + } + case SIMEDGE_CREASE: + case SIMEDGE_BEVEL: { + const float *value = CustomData_bmesh_get( + &bm->edata, edge->head.data, custom_data_type); + BLI_kdtree_1d_insert(tree_1d, tree_index++, value); + break; + } + } + } + } + } + + BLI_assert((type != SIMEDGE_FREESTYLE) || (edge_data_value != SIMEDGE_DATA_NONE)); + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + if (tree_3d != NULL) { + BLI_kdtree_3d_deduplicate(tree_3d); + BLI_kdtree_3d_balance(tree_3d); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + bool changed = false; + + bool has_custom_data_layer = false; + switch (type) { + case SIMEDGE_FREESTYLE: { + has_custom_data_layer = CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE); + if ((edge_data_value == SIMEDGE_DATA_TRUE) && !has_custom_data_layer) { + continue; + } + break; + } + case SIMEDGE_CREASE: + case SIMEDGE_BEVEL: { + has_custom_data_layer = CustomData_has_layer(&bm->edata, custom_data_type); + if (!has_custom_data_layer) { + /* Proceed only if we have to select all the edges that have custom data value of 0.0f. + * In this case we will just select all the edges. + * Otherwise continue the for loop. */ + if (!ED_select_similar_compare_float_tree(tree_1d, 0.0f, thresh, compare)) { + continue; + } + } + } + } + + float ob_m3[3][3], ob_m3_inv[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + invert_m3_m3(ob_m3_inv, ob_m3); + + BMEdge *edge; /* Mesh edge. */ + BMIter iter; /* Selected edges iterator. */ + + BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(edge, BM_ELEM_SELECT) && !BM_elem_flag_test(edge, BM_ELEM_HIDDEN)) { + bool select = false; + switch (type) { + case SIMEDGE_FACE: { + const int num_faces = BM_edge_face_count(edge); + GSetIterator gs_iter; + GSET_ITER (gs_iter, gset) { + const int num_faces_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); + const int delta_i = num_faces - num_faces_iter; + if (mesh_select_similar_compare_int(delta_i, compare)) { + select = true; + break; + } + } + break; + } + case SIMEDGE_DIR: { + float dir[3]; + edge_pos_direction_worldspace_get(ob, edge, dir); + + /* We are treating the direction as coordinates, the "nearest" one will + * also be the one closest to the intended direction. */ + KDTreeNearest_3d nearest; + if (BLI_kdtree_3d_find_nearest(tree_3d, dir, &nearest) != -1) { + if (angle_normalized_v3v3(dir, nearest.co) <= thresh_radians) { + select = true; + } + } + break; + } + case SIMEDGE_LENGTH: { + float length = edge_length_squared_worldspace_get(ob, edge); + if (ED_select_similar_compare_float_tree(tree_1d, length, thresh, compare)) { + select = true; + } + break; + } + case SIMEDGE_FACE_ANGLE: { + if (BM_edge_face_count_at_most(edge, 2) == 2) { + float angle = BM_edge_calc_face_angle_with_imat3(edge, ob_m3_inv); + if (ED_select_similar_compare_float_tree(tree_1d, angle, thresh, SIM_CMP_EQ)) { + select = true; + } + } + break; + } + case SIMEDGE_SEAM: + if ((BM_elem_flag_test(edge, BM_ELEM_SEAM) != 0) == + ((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) { + select = true; + } + break; + case SIMEDGE_SHARP: + if ((BM_elem_flag_test(edge, BM_ELEM_SMOOTH) != 0) == + ((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) { + select = true; + } + break; + case SIMEDGE_FREESTYLE: { + FreestyleEdge *fedge; + + if (!has_custom_data_layer) { + BLI_assert(edge_data_value == SIMEDGE_DATA_FALSE); + select = true; + break; + } + + fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE); + if (((fedge != NULL) && (fedge->flag & FREESTYLE_EDGE_MARK)) == + ((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) { + select = true; + } + break; + } + case SIMEDGE_CREASE: + case SIMEDGE_BEVEL: { + if (!has_custom_data_layer) { + select = true; + break; + } + + const float *value = CustomData_bmesh_get( + &bm->edata, edge->head.data, custom_data_type); + if (ED_select_similar_compare_float_tree(tree_1d, *value, thresh, compare)) { + select = true; + } + break; + } + } + + if (select) { + BM_edge_select_set(bm, edge, true); + changed = true; + } + } + } + + if (changed) { + EDBM_selectmode_flush(em); + EDBM_update_generic(em, false, false); + } + } + + if (false) { + edge_select_all: + BLI_assert(ELEM(type, SIMEDGE_SEAM, SIMEDGE_SHARP, SIMEDGE_FREESTYLE)); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + + BMEdge *edge; /* Mesh edge. */ + BMIter iter; /* Selected edges iterator. */ + + BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(edge, BM_ELEM_SELECT)) { + BM_edge_select_set(bm, edge, true); + } + } + EDBM_selectmode_flush(em); + EDBM_update_generic(em, false, false); + } + } + + MEM_freeN(objects); + BLI_kdtree_1d_free(tree_1d); + BLI_kdtree_3d_free(tree_3d); + if (gset != NULL) { + BLI_gset_free(gset, NULL); + } + + return OPERATOR_FINISHED; } /** \} */ @@ -1010,254 +960,243 @@ edge_select_all: static int similar_vert_select_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - - /* get the type from RNA */ - const int type = RNA_enum_get(op->ptr, "type"); - const float thresh = RNA_float_get(op->ptr, "threshold"); - const float thresh_radians = thresh * (float)M_PI + FLT_EPSILON; - const int compare = RNA_enum_get(op->ptr, "compare"); - - int tot_verts_selected_all = 0; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - tot_verts_selected_all += em->bm->totvertsel; - } - - if (tot_verts_selected_all == 0) { - BKE_report(op->reports, RPT_ERROR, "No vertex selected"); - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - - KDTree_3d *tree_3d = NULL; - GSet *gset = NULL; - - switch (type) { - case SIMVERT_NORMAL: - tree_3d = BLI_kdtree_3d_new(tot_verts_selected_all); - break; - case SIMVERT_EDGE: - case SIMVERT_FACE: - gset = BLI_gset_ptr_new("Select similar vertex: edge/face"); - break; - case SIMVERT_VGROUP: - gset = BLI_gset_str_new("Select similar vertex: vertex groups"); - break; - } - - int normal_tree_index = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - int cd_dvert_offset = -1; - int dvert_selected = 0; - invert_m4_m4(ob->imat, ob->obmat); - - if (bm->totvertsel == 0) { - continue; - } - - if (type == SIMVERT_VGROUP) { - cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - if (cd_dvert_offset == -1) { - continue; - } - } - - BMVert *vert; /* Mesh vertex. */ - BMIter iter; /* Selected verts iterator. */ - - BM_ITER_MESH (vert, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(vert, BM_ELEM_SELECT)) { - switch (type) { - case SIMVERT_FACE: - BLI_gset_add(gset, POINTER_FROM_INT(BM_vert_face_count(vert))); - break; - case SIMVERT_EDGE: - BLI_gset_add(gset, POINTER_FROM_INT(BM_vert_edge_count(vert))); - break; - case SIMVERT_NORMAL: - { - float normal[3]; - copy_v3_v3(normal, vert->no); - mul_transposed_mat3_m4_v3(ob->imat, normal); - normalize_v3(normal); - - BLI_kdtree_3d_insert(tree_3d, normal_tree_index++, normal); - break; - } - case SIMVERT_VGROUP: - { - MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, cd_dvert_offset); - MDeformWeight *dw = dvert->dw; - - for (int i = 0; i < dvert->totweight; i++, dw++) { - if (dw->weight > 0.0f) { - dvert_selected |= (1 << dw->def_nr); - } - } - break; - } - } - } - } - - if (type == SIMVERT_VGROUP) { - /* We store the names of the vertex groups, so we can select - * vertex groups with the same name in different objects. */ - const int dvert_tot = BLI_listbase_count(&ob->defbase); - for (int i = 0; i < dvert_tot; i++) { - if (dvert_selected & (1 << i)) { - bDeformGroup *dg = BLI_findlink(&ob->defbase, i); - BLI_gset_add(gset, dg->name); - } - } - } - } - - if (type == SIMVERT_VGROUP) { - if (BLI_gset_len(gset) == 0) { - BKE_report(op->reports, - RPT_INFO, - "No vertex group among the selected vertices"); - } - } - - /* Remove duplicated entries. */ - if (tree_3d != NULL) { - BLI_kdtree_3d_deduplicate(tree_3d); - BLI_kdtree_3d_balance(tree_3d); - } - - /* Run .the BM operators. */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - bool changed = false; - int cd_dvert_offset = -1; - int dvert_selected = 0; - - if (type == SIMVERT_VGROUP) { - cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - if (cd_dvert_offset == -1) { - continue; - } - - /* We map back the names of the vertex groups to their corresponding indices - * for this object. This is fast, and keep the logic for each vertex very simple. */ - GSetIterator gs_iter; - GSET_ITER(gs_iter, gset) { - const char *name = BLI_gsetIterator_getKey(&gs_iter); - int vgroup_id = BLI_findstringindex(&ob->defbase, - name, - offsetof(bDeformGroup, name)); - if (vgroup_id != -1) { - dvert_selected |= (1 << vgroup_id); - } - } - if (dvert_selected == 0) { - continue; - } - } - - BMVert *vert; /* Mesh vertex. */ - BMIter iter; /* Selected verts iterator. */ - - BM_ITER_MESH (vert, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(vert, BM_ELEM_SELECT) && - !BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) - { - bool select = false; - switch (type) { - case SIMVERT_EDGE: - { - const int num_edges = BM_vert_edge_count(vert); - GSetIterator gs_iter; - GSET_ITER(gs_iter, gset) { - const int num_edges_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); - const int delta_i = num_edges - num_edges_iter; - if (mesh_select_similar_compare_int(delta_i, compare)) { - select = true; - break; - } - } - break; - } - case SIMVERT_FACE: - { - const int num_faces = BM_vert_face_count(vert); - GSetIterator gs_iter; - GSET_ITER(gs_iter, gset) { - const int num_faces_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); - const int delta_i = num_faces - num_faces_iter; - if (mesh_select_similar_compare_int(delta_i, compare)) { - select = true; - break; - } - } - break; - } - case SIMVERT_NORMAL: - { - float normal[3]; - copy_v3_v3(normal, vert->no); - mul_transposed_mat3_m4_v3(ob->imat, normal); - normalize_v3(normal); - - /* We are treating the normals as coordinates, the "nearest" one will - * also be the one closest to the angle. */ - KDTreeNearest_3d nearest; - if (BLI_kdtree_3d_find_nearest(tree_3d, normal, &nearest) != -1) { - if (angle_normalized_v3v3(normal, nearest.co) <= thresh_radians) { - select = true; - } - } - break; - } - case SIMVERT_VGROUP: - { - MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, cd_dvert_offset); - MDeformWeight *dw = dvert->dw; - - for (int i = 0; i < dvert->totweight; i++, dw++) { - if (dw->weight > 0.0f) { - if (dvert_selected & (1 << dw->def_nr)) { - select = true; - break; - } - } - } - break; - } - } - - if (select) { - BM_vert_select_set(bm, vert, true); - changed = true; - } - } - } - - if (changed) { - EDBM_selectmode_flush(em); - EDBM_update_generic(em, false, false); - } - } - - MEM_freeN(objects); - BLI_kdtree_3d_free(tree_3d); - if (gset != NULL) { - BLI_gset_free(gset, NULL); - } - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + + /* get the type from RNA */ + const int type = RNA_enum_get(op->ptr, "type"); + const float thresh = RNA_float_get(op->ptr, "threshold"); + const float thresh_radians = thresh * (float)M_PI + FLT_EPSILON; + const int compare = RNA_enum_get(op->ptr, "compare"); + + int tot_verts_selected_all = 0; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + tot_verts_selected_all += em->bm->totvertsel; + } + + if (tot_verts_selected_all == 0) { + BKE_report(op->reports, RPT_ERROR, "No vertex selected"); + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + + KDTree_3d *tree_3d = NULL; + GSet *gset = NULL; + + switch (type) { + case SIMVERT_NORMAL: + tree_3d = BLI_kdtree_3d_new(tot_verts_selected_all); + break; + case SIMVERT_EDGE: + case SIMVERT_FACE: + gset = BLI_gset_ptr_new("Select similar vertex: edge/face"); + break; + case SIMVERT_VGROUP: + gset = BLI_gset_str_new("Select similar vertex: vertex groups"); + break; + } + + int normal_tree_index = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + int cd_dvert_offset = -1; + int dvert_selected = 0; + invert_m4_m4(ob->imat, ob->obmat); + + if (bm->totvertsel == 0) { + continue; + } + + if (type == SIMVERT_VGROUP) { + cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); + if (cd_dvert_offset == -1) { + continue; + } + } + + BMVert *vert; /* Mesh vertex. */ + BMIter iter; /* Selected verts iterator. */ + + BM_ITER_MESH (vert, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(vert, BM_ELEM_SELECT)) { + switch (type) { + case SIMVERT_FACE: + BLI_gset_add(gset, POINTER_FROM_INT(BM_vert_face_count(vert))); + break; + case SIMVERT_EDGE: + BLI_gset_add(gset, POINTER_FROM_INT(BM_vert_edge_count(vert))); + break; + case SIMVERT_NORMAL: { + float normal[3]; + copy_v3_v3(normal, vert->no); + mul_transposed_mat3_m4_v3(ob->imat, normal); + normalize_v3(normal); + + BLI_kdtree_3d_insert(tree_3d, normal_tree_index++, normal); + break; + } + case SIMVERT_VGROUP: { + MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, cd_dvert_offset); + MDeformWeight *dw = dvert->dw; + + for (int i = 0; i < dvert->totweight; i++, dw++) { + if (dw->weight > 0.0f) { + dvert_selected |= (1 << dw->def_nr); + } + } + break; + } + } + } + } + + if (type == SIMVERT_VGROUP) { + /* We store the names of the vertex groups, so we can select + * vertex groups with the same name in different objects. */ + const int dvert_tot = BLI_listbase_count(&ob->defbase); + for (int i = 0; i < dvert_tot; i++) { + if (dvert_selected & (1 << i)) { + bDeformGroup *dg = BLI_findlink(&ob->defbase, i); + BLI_gset_add(gset, dg->name); + } + } + } + } + + if (type == SIMVERT_VGROUP) { + if (BLI_gset_len(gset) == 0) { + BKE_report(op->reports, RPT_INFO, "No vertex group among the selected vertices"); + } + } + + /* Remove duplicated entries. */ + if (tree_3d != NULL) { + BLI_kdtree_3d_deduplicate(tree_3d); + BLI_kdtree_3d_balance(tree_3d); + } + + /* Run .the BM operators. */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + bool changed = false; + int cd_dvert_offset = -1; + int dvert_selected = 0; + + if (type == SIMVERT_VGROUP) { + cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); + if (cd_dvert_offset == -1) { + continue; + } + + /* We map back the names of the vertex groups to their corresponding indices + * for this object. This is fast, and keep the logic for each vertex very simple. */ + GSetIterator gs_iter; + GSET_ITER (gs_iter, gset) { + const char *name = BLI_gsetIterator_getKey(&gs_iter); + int vgroup_id = BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)); + if (vgroup_id != -1) { + dvert_selected |= (1 << vgroup_id); + } + } + if (dvert_selected == 0) { + continue; + } + } + + BMVert *vert; /* Mesh vertex. */ + BMIter iter; /* Selected verts iterator. */ + + BM_ITER_MESH (vert, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(vert, BM_ELEM_SELECT) && !BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) { + bool select = false; + switch (type) { + case SIMVERT_EDGE: { + const int num_edges = BM_vert_edge_count(vert); + GSetIterator gs_iter; + GSET_ITER (gs_iter, gset) { + const int num_edges_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); + const int delta_i = num_edges - num_edges_iter; + if (mesh_select_similar_compare_int(delta_i, compare)) { + select = true; + break; + } + } + break; + } + case SIMVERT_FACE: { + const int num_faces = BM_vert_face_count(vert); + GSetIterator gs_iter; + GSET_ITER (gs_iter, gset) { + const int num_faces_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); + const int delta_i = num_faces - num_faces_iter; + if (mesh_select_similar_compare_int(delta_i, compare)) { + select = true; + break; + } + } + break; + } + case SIMVERT_NORMAL: { + float normal[3]; + copy_v3_v3(normal, vert->no); + mul_transposed_mat3_m4_v3(ob->imat, normal); + normalize_v3(normal); + + /* We are treating the normals as coordinates, the "nearest" one will + * also be the one closest to the angle. */ + KDTreeNearest_3d nearest; + if (BLI_kdtree_3d_find_nearest(tree_3d, normal, &nearest) != -1) { + if (angle_normalized_v3v3(normal, nearest.co) <= thresh_radians) { + select = true; + } + } + break; + } + case SIMVERT_VGROUP: { + MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, cd_dvert_offset); + MDeformWeight *dw = dvert->dw; + + for (int i = 0; i < dvert->totweight; i++, dw++) { + if (dw->weight > 0.0f) { + if (dvert_selected & (1 << dw->def_nr)) { + select = true; + break; + } + } + } + break; + } + } + + if (select) { + BM_vert_select_set(bm, vert, true); + changed = true; + } + } + } + + if (changed) { + EDBM_selectmode_flush(em); + EDBM_update_generic(em, false, false); + } + } + + MEM_freeN(objects); + BLI_kdtree_3d_free(tree_3d); + if (gset != NULL) { + BLI_gset_free(gset, NULL); + } + + return OPERATOR_FINISHED; } /** \} */ @@ -1267,93 +1206,97 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) static int edbm_select_similar_exec(bContext *C, wmOperator *op) { - ToolSettings *ts = CTX_data_tool_settings(C); - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold"); - - const int type = RNA_enum_get(op->ptr, "type"); - - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_set(op->ptr, prop, ts->select_thresh); - } - else { - ts->select_thresh = RNA_property_float_get(op->ptr, prop); - } - - if (type < 100) return similar_vert_select_exec(C, op); - else if (type < 200) return similar_edge_select_exec(C, op); - else return similar_face_select_exec(C, op); + ToolSettings *ts = CTX_data_tool_settings(C); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold"); + + const int type = RNA_enum_get(op->ptr, "type"); + + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set(op->ptr, prop, ts->select_thresh); + } + else { + ts->select_thresh = RNA_property_float_get(op->ptr, prop); + } + + if (type < 100) + return similar_vert_select_exec(C, op); + else if (type < 200) + return similar_edge_select_exec(C, op); + else + return similar_face_select_exec(C, op); } -static const EnumPropertyItem *select_similar_type_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), - bool *r_free) +static const EnumPropertyItem *select_similar_type_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - Object *obedit; - - if (!C) /* needed for docs and i18n tools */ - return prop_similar_types; - - obedit = CTX_data_edit_object(C); - - if (obedit && obedit->type == OB_MESH) { - EnumPropertyItem *item = NULL; - int a, totitem = 0; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->selectmode & SCE_SELECT_VERTEX) { - for (a = SIMVERT_NORMAL; a < SIMEDGE_LENGTH; a++) { - RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); - } - } - else if (em->selectmode & SCE_SELECT_EDGE) { - for (a = SIMEDGE_LENGTH; a < SIMFACE_MATERIAL; a++) { - RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); - } - } - else if (em->selectmode & SCE_SELECT_FACE) { + Object *obedit; + + if (!C) /* needed for docs and i18n tools */ + return prop_similar_types; + + obedit = CTX_data_edit_object(C); + + if (obedit && obedit->type == OB_MESH) { + EnumPropertyItem *item = NULL; + int a, totitem = 0; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->selectmode & SCE_SELECT_VERTEX) { + for (a = SIMVERT_NORMAL; a < SIMEDGE_LENGTH; a++) { + RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); + } + } + else if (em->selectmode & SCE_SELECT_EDGE) { + for (a = SIMEDGE_LENGTH; a < SIMFACE_MATERIAL; a++) { + RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); + } + } + else if (em->selectmode & SCE_SELECT_FACE) { #ifdef WITH_FREESTYLE - const int a_end = SIMFACE_FREESTYLE; + const int a_end = SIMFACE_FREESTYLE; #else - const int a_end = SIMFACE_FACEMAP; + const int a_end = SIMFACE_FACEMAP; #endif - for (a = SIMFACE_MATERIAL; a <= a_end; a++) { - RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); - } - } - RNA_enum_item_end(&item, &totitem); + for (a = SIMFACE_MATERIAL; a <= a_end; a++) { + RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); + } + } + RNA_enum_item_end(&item, &totitem); - *r_free = true; + *r_free = true; - return item; - } + return item; + } - return prop_similar_types; + return prop_similar_types; } void MESH_OT_select_similar(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Select Similar"; - ot->idname = "MESH_OT_select_similar"; - ot->description = "Select similar vertices, edges or faces by property types"; + /* identifiers */ + ot->name = "Select Similar"; + ot->idname = "MESH_OT_select_similar"; + ot->description = "Select similar vertices, edges or faces by property types"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = edbm_select_similar_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = edbm_select_similar_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", ""); - RNA_def_enum_funcs(prop, select_similar_type_itemf); + /* properties */ + prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", ""); + RNA_def_enum_funcs(prop, select_similar_type_itemf); - RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", ""); + RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", ""); - RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); + RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 9fb200951ca..79bbf021829 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -80,7 +80,7 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ #include "bmesh_tools.h" @@ -92,92 +92,131 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op) { - const int cuts = RNA_int_get(op->ptr, "number_cuts"); - const float smooth = RNA_float_get(op->ptr, "smoothness"); - const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f; - const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal"); - - if (RNA_boolean_get(op->ptr, "ngon") && - RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT) - { - RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT); - } - const int quad_corner_type = RNA_enum_get(op->ptr, "quadcorner"); - const bool use_quad_tri = !RNA_boolean_get(op->ptr, "ngon"); - const int seed = RNA_int_get(op->ptr, "seed"); - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (!(em->bm->totedgesel || em->bm->totfacesel)) { - continue; - } - - BM_mesh_esubdivide( - em->bm, BM_ELEM_SELECT, - smooth, SUBD_FALLOFF_LIN, false, - fractal, along_normal, - cuts, - SUBDIV_SELECT_ORIG, quad_corner_type, - use_quad_tri, true, false, - seed); - - EDBM_update_generic(em, true, true); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const int cuts = RNA_int_get(op->ptr, "number_cuts"); + const float smooth = RNA_float_get(op->ptr, "smoothness"); + const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f; + const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal"); + + if (RNA_boolean_get(op->ptr, "ngon") && + RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT) { + RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT); + } + const int quad_corner_type = RNA_enum_get(op->ptr, "quadcorner"); + const bool use_quad_tri = !RNA_boolean_get(op->ptr, "ngon"); + const int seed = RNA_int_get(op->ptr, "seed"); + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (!(em->bm->totedgesel || em->bm->totfacesel)) { + continue; + } + + BM_mesh_esubdivide(em->bm, + BM_ELEM_SELECT, + smooth, + SUBD_FALLOFF_LIN, + false, + fractal, + along_normal, + cuts, + SUBDIV_SELECT_ORIG, + quad_corner_type, + use_quad_tri, + true, + false, + seed); + + EDBM_update_generic(em, true, true); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } /* Note, these values must match delete_mesh() event values */ static const EnumPropertyItem prop_mesh_cornervert_types[] = { - {SUBD_CORNER_INNERVERT, "INNERVERT", 0, "Inner Vert", ""}, - {SUBD_CORNER_PATH, "PATH", 0, "Path", ""}, - {SUBD_CORNER_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""}, - {SUBD_CORNER_FAN, "FAN", 0, "Fan", ""}, - {0, NULL, 0, NULL, NULL}, + {SUBD_CORNER_INNERVERT, "INNERVERT", 0, "Inner Vert", ""}, + {SUBD_CORNER_PATH, "PATH", 0, "Path", ""}, + {SUBD_CORNER_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""}, + {SUBD_CORNER_FAN, "FAN", 0, "Fan", ""}, + {0, NULL, 0, NULL, NULL}, }; void MESH_OT_subdivide(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Subdivide"; - ot->description = "Subdivide selected edges"; - ot->idname = "MESH_OT_subdivide"; - - /* api callbacks */ - ot->exec = edbm_subdivide_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 100, "Number of Cuts", "", 1, 10); - /* avoid re-using last var because it can cause - * _very_ high poly meshes and annoy users (or worse crash) */ - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f); - - WM_operatortype_props_advanced_begin(ot); - - RNA_def_boolean(ot->srna, "ngon", true, "Create N-Gons", "When disabled, newly created faces are limited to 3-4 sided faces"); - RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_CORNER_STRAIGHT_CUT, - "Quad Corner Type", "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)"); - - RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, 1e6f, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f); - RNA_def_float(ot->srna, "fractal_along_normal", 0.0f, 0.0f, 1.0f, - "Along Normal", "Apply fractal displacement along normal only", 0.0f, 1.0f); - RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Random Seed", "Seed for the random number generator", 0, 255); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Subdivide"; + ot->description = "Subdivide selected edges"; + ot->idname = "MESH_OT_subdivide"; + + /* api callbacks */ + ot->exec = edbm_subdivide_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 100, "Number of Cuts", "", 1, 10); + /* avoid re-using last var because it can cause + * _very_ high poly meshes and annoy users (or worse crash) */ + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + RNA_def_float( + ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f); + + WM_operatortype_props_advanced_begin(ot); + + RNA_def_boolean(ot->srna, + "ngon", + true, + "Create N-Gons", + "When disabled, newly created faces are limited to 3-4 sided faces"); + RNA_def_enum( + ot->srna, + "quadcorner", + prop_mesh_cornervert_types, + SUBD_CORNER_STRAIGHT_CUT, + "Quad Corner Type", + "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)"); + + RNA_def_float(ot->srna, + "fractal", + 0.0f, + 0.0f, + 1e6f, + "Fractal", + "Fractal randomness factor", + 0.0f, + 1000.0f); + RNA_def_float(ot->srna, + "fractal_along_normal", + 0.0f, + 0.0f, + 1.0f, + "Along Normal", + "Apply fractal displacement along normal only", + 0.0f, + 1.0f); + RNA_def_int(ot->srna, + "seed", + 0, + 0, + INT_MAX, + "Random Seed", + "Seed for the random number generator", + 0, + 255); } /** \} */ @@ -190,107 +229,124 @@ void MESH_OT_subdivide(wmOperatorType *ot) * \{ */ struct EdgeRingOpSubdProps { - int interp_mode; - int cuts; - float smooth; + int interp_mode; + int cuts; + float smooth; - int profile_shape; - float profile_shape_factor; + int profile_shape; + float profile_shape_factor; }; - -static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_min, const int cuts_default) -{ - /* Note, these values must match delete_mesh() event values */ - static const EnumPropertyItem prop_subd_edgering_types[] = { - {SUBD_RING_INTERP_LINEAR, "LINEAR", 0, "Linear", ""}, - {SUBD_RING_INTERP_PATH, "PATH", 0, "Blend Path", ""}, - {SUBD_RING_INTERP_SURF, "SURFACE", 0, "Blend Surface", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - PropertyRNA *prop; - - prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", cuts_min, 64); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH, - "Interpolation", "Interpolation method"); - - RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1e3f, - "Smoothness", "Smoothness factor", 0.0f, 2.0f); - - /* profile-shape */ - RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -1e3f, 1e3f, - "Profile Factor", "How much intermediary new edges are shrunk/expanded", -2.0f, 2.0f); - - prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items); - RNA_def_property_enum_default(prop, PROP_SMOOTH); - RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile"); - RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */ +static void mesh_operator_edgering_props(wmOperatorType *ot, + const int cuts_min, + const int cuts_default) +{ + /* Note, these values must match delete_mesh() event values */ + static const EnumPropertyItem prop_subd_edgering_types[] = { + {SUBD_RING_INTERP_LINEAR, "LINEAR", 0, "Linear", ""}, + {SUBD_RING_INTERP_PATH, "PATH", 0, "Blend Path", ""}, + {SUBD_RING_INTERP_SURF, "SURFACE", 0, "Blend Surface", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + PropertyRNA *prop; + + prop = RNA_def_int( + ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", cuts_min, 64); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + RNA_def_enum(ot->srna, + "interpolation", + prop_subd_edgering_types, + SUBD_RING_INTERP_PATH, + "Interpolation", + "Interpolation method"); + + RNA_def_float( + ot->srna, "smoothness", 1.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 2.0f); + + /* profile-shape */ + RNA_def_float(ot->srna, + "profile_shape_factor", + 0.0f, + -1e3f, + 1e3f, + "Profile Factor", + "How much intermediary new edges are shrunk/expanded", + -2.0f, + 2.0f); + + prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items); + RNA_def_property_enum_default(prop, PROP_SMOOTH); + RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */ } static void mesh_operator_edgering_props_get(wmOperator *op, struct EdgeRingOpSubdProps *op_props) { - op_props->interp_mode = RNA_enum_get(op->ptr, "interpolation"); - op_props->cuts = RNA_int_get(op->ptr, "number_cuts"); - op_props->smooth = RNA_float_get(op->ptr, "smoothness"); + op_props->interp_mode = RNA_enum_get(op->ptr, "interpolation"); + op_props->cuts = RNA_int_get(op->ptr, "number_cuts"); + op_props->smooth = RNA_float_get(op->ptr, "smoothness"); - op_props->profile_shape = RNA_enum_get(op->ptr, "profile_shape"); - op_props->profile_shape_factor = RNA_float_get(op->ptr, "profile_shape_factor"); + op_props->profile_shape = RNA_enum_get(op->ptr, "profile_shape"); + op_props->profile_shape_factor = RNA_float_get(op->ptr, "profile_shape_factor"); } static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - struct EdgeRingOpSubdProps op_props; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + struct EdgeRingOpSubdProps op_props; - mesh_operator_edgering_props_get(op, &op_props); + mesh_operator_edgering_props_get(op, &op_props); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totedgesel == 0) { - continue; - } + if (em->bm->totedgesel == 0) { + continue; + } - if (!EDBM_op_callf( - em, op, - "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f " - "profile_shape=%i profile_shape_factor=%f", - BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth, - op_props.profile_shape, op_props.profile_shape_factor)) - { - continue; - } + if (!EDBM_op_callf(em, + op, + "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f " + "profile_shape=%i profile_shape_factor=%f", + BM_ELEM_SELECT, + op_props.interp_mode, + op_props.cuts, + op_props.smooth, + op_props.profile_shape, + op_props.profile_shape_factor)) { + continue; + } - EDBM_update_generic(em, true, true); - } + EDBM_update_generic(em, true, true); + } - MEM_freeN(objects); - return OPERATOR_FINISHED; + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_subdivide_edgering(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Subdivide Edge-Ring"; - ot->idname = "MESH_OT_subdivide_edgering"; + /* identifiers */ + ot->name = "Subdivide Edge-Ring"; + ot->idname = "MESH_OT_subdivide_edgering"; - /* api callbacks */ - ot->exec = edbm_subdivide_edge_ring_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_subdivide_edge_ring_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - mesh_operator_edgering_props(ot, 1, 10); + /* properties */ + mesh_operator_edgering_props(ot, 1, 10); } /** \} */ @@ -301,96 +357,94 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot) static int edbm_unsubdivide_exec(bContext *C, wmOperator *op) { - const int iterations = RNA_int_get(op->ptr, "iterations"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int iterations = RNA_int_get(op->ptr, "iterations"); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if ((em->bm->totvertsel == 0) && - (em->bm->totedgesel == 0) && - (em->bm->totfacesel == 0)) - { - continue; - } + if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) { + continue; + } - BMOperator bmop; - EDBM_op_init(em, &bmop, op, - "unsubdivide verts=%hv iterations=%i", BM_ELEM_SELECT, iterations); + BMOperator bmop; + EDBM_op_init(em, &bmop, op, "unsubdivide verts=%hv iterations=%i", BM_ELEM_SELECT, iterations); - BMO_op_exec(em->bm, &bmop); + BMO_op_exec(em->bm, &bmop); - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { - EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); /* need to flush vert->face first */ - } - EDBM_selectmode_flush(em); + if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); /* need to flush vert->face first */ + } + EDBM_selectmode_flush(em); - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_unsubdivide(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Un-Subdivide"; - ot->description = "UnSubdivide selected edges & faces"; - ot->idname = "MESH_OT_unsubdivide"; + /* identifiers */ + ot->name = "Un-Subdivide"; + ot->description = "UnSubdivide selected edges & faces"; + ot->idname = "MESH_OT_unsubdivide"; - /* api callbacks */ - ot->exec = edbm_unsubdivide_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_unsubdivide_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_int(ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to unsubdivide", 1, 100); + /* props */ + RNA_def_int( + ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to unsubdivide", 1, 100); } void EDBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) { - Main *bmain = CTX_data_main(C); - Object *obedit = em->ob; - BMIter iter; - BMVert *eve; - - ED_view3d_init_mats_rv3d(obedit, ar->regiondata); - - struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0, - ar, CTX_wm_view3d(C)); - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - float mval[2], co_proj[3]; - if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - if (ED_transform_snap_object_project_view3d( - snap_context, - SCE_SNAP_MODE_FACE, - &(const struct SnapObjectParams){ - .snap_select = SNAP_NOT_ACTIVE, - .use_object_edit_cage = false, - .use_occlusion_test = true, - }, - mval, NULL, - co_proj, NULL)) - { - mul_v3_m4v3(eve->co, obedit->imat, co_proj); - } - } - } - } - - ED_transform_snap_object_context_destroy(snap_context); + Main *bmain = CTX_data_main(C); + Object *obedit = em->ob; + BMIter iter; + BMVert *eve; + + ED_view3d_init_mats_rv3d(obedit, ar->regiondata); + + struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( + bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0, ar, CTX_wm_view3d(C)); + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + float mval[2], co_proj[3]; + if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == + V3D_PROJ_RET_OK) { + if (ED_transform_snap_object_project_view3d(snap_context, + SCE_SNAP_MODE_FACE, + &(const struct SnapObjectParams){ + .snap_select = SNAP_NOT_ACTIVE, + .use_object_edit_cage = false, + .use_occlusion_test = true, + }, + mval, + NULL, + co_proj, + NULL)) { + mul_v3_m4v3(eve->co, obedit->imat, co_proj); + } + } + } + } + + ED_transform_snap_object_context_destroy(snap_context); } /** \} */ @@ -401,117 +455,124 @@ void EDBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) /* Note, these values must match delete_mesh() event values */ enum { - MESH_DELETE_VERT = 0, - MESH_DELETE_EDGE = 1, - MESH_DELETE_FACE = 2, - MESH_DELETE_EDGE_FACE = 3, - MESH_DELETE_ONLY_FACE = 4, + MESH_DELETE_VERT = 0, + MESH_DELETE_EDGE = 1, + MESH_DELETE_FACE = 2, + MESH_DELETE_EDGE_FACE = 3, + MESH_DELETE_ONLY_FACE = 4, }; -static void edbm_report_delete_info(ReportList *reports, const int totelem_old[3], const int totelem_new[3]) +static void edbm_report_delete_info(ReportList *reports, + const int totelem_old[3], + const int totelem_new[3]) { - BKE_reportf(reports, RPT_INFO, - "Removed: %d vertices, %d edges, %d faces", - totelem_old[0] - totelem_new[0], totelem_old[1] - totelem_new[1], totelem_old[2] - totelem_new[2]); + BKE_reportf(reports, + RPT_INFO, + "Removed: %d vertices, %d edges, %d faces", + totelem_old[0] - totelem_new[0], + totelem_old[1] - totelem_new[1], + totelem_old[2] - totelem_new[2]); } static int edbm_delete_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - bool changed_multi = false; - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int type = RNA_enum_get(op->ptr, "type"); - - switch (type) { - case MESH_DELETE_VERT: /* Erase Vertices */ - if (!(em->bm->totvertsel && - EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS))) - { - continue; - } - break; - case MESH_DELETE_EDGE: /* Erase Edges */ - if (!(em->bm->totedgesel && - EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES))) - { - continue; - } - break; - case MESH_DELETE_FACE: /* Erase Faces */ - if (!(em->bm->totfacesel && - EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES))) - { - continue; - } - break; - case MESH_DELETE_EDGE_FACE: - /* Edges and Faces */ - if (!((em->bm->totedgesel || em->bm->totfacesel) && - EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))) - { - continue; - } - break; - case MESH_DELETE_ONLY_FACE: - /* Only faces. */ - if (!(em->bm->totfacesel && - EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES))) - { - continue; - } - break; - default: - BLI_assert(0); - break; - } - - changed_multi = true; - - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - - EDBM_update_generic(em, true, true); - } - - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + ViewLayer *view_layer = CTX_data_view_layer(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + bool changed_multi = false; + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int type = RNA_enum_get(op->ptr, "type"); + + switch (type) { + case MESH_DELETE_VERT: /* Erase Vertices */ + if (!(em->bm->totvertsel && + EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS))) { + continue; + } + break; + case MESH_DELETE_EDGE: /* Erase Edges */ + if (!(em->bm->totedgesel && + EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES))) { + continue; + } + break; + case MESH_DELETE_FACE: /* Erase Faces */ + if (!(em->bm->totfacesel && + EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES))) { + continue; + } + break; + case MESH_DELETE_EDGE_FACE: + /* Edges and Faces */ + if (!((em->bm->totedgesel || em->bm->totfacesel) && + EDBM_op_callf( + em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))) { + continue; + } + break; + case MESH_DELETE_ONLY_FACE: + /* Only faces. */ + if (!(em->bm->totfacesel && + EDBM_op_callf( + em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES))) { + continue; + } + break; + default: + BLI_assert(0); + break; + } + + changed_multi = true; + + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + EDBM_update_generic(em, true, true); + } + + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void MESH_OT_delete(wmOperatorType *ot) { - static const EnumPropertyItem prop_mesh_delete_types[] = { - {MESH_DELETE_VERT, "VERT", 0, "Vertices", ""}, - {MESH_DELETE_EDGE, "EDGE", 0, "Edges", ""}, - {MESH_DELETE_FACE, "FACE", 0, "Faces", ""}, - {MESH_DELETE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""}, - {MESH_DELETE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""}, - {0, NULL, 0, NULL, NULL}, - }; + static const EnumPropertyItem prop_mesh_delete_types[] = { + {MESH_DELETE_VERT, "VERT", 0, "Vertices", ""}, + {MESH_DELETE_EDGE, "EDGE", 0, "Edges", ""}, + {MESH_DELETE_FACE, "FACE", 0, "Faces", ""}, + {MESH_DELETE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""}, + {MESH_DELETE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""}, + {0, NULL, 0, NULL, NULL}, + }; - /* identifiers */ - ot->name = "Delete"; - ot->description = "Delete selected vertices, edges or faces"; - ot->idname = "MESH_OT_delete"; + /* identifiers */ + ot->name = "Delete"; + ot->description = "Delete selected vertices, edges or faces"; + ot->idname = "MESH_OT_delete"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = edbm_delete_exec; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = edbm_delete_exec; - ot->poll = ED_operator_editmesh; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, MESH_DELETE_VERT, - "Type", "Method used for deleting mesh data"); - RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* props */ + ot->prop = RNA_def_enum(ot->srna, + "type", + prop_mesh_delete_types, + MESH_DELETE_VERT, + "Type", + "Method used for deleting mesh data"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /** \} */ @@ -522,113 +583,113 @@ void MESH_OT_delete(wmOperatorType *ot) static bool bm_face_is_loose(BMFace *f) { - BMLoop *l_iter, *l_first; + BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (!BM_edge_is_boundary(l_iter->e)) { - return false; - } - } while ((l_iter = l_iter->next) != l_first); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BM_edge_is_boundary(l_iter->e)) { + return false; + } + } while ((l_iter = l_iter->next) != l_first); - return true; + return true; } static int edbm_delete_loose_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - int totelem_old_sel[3]; - int totelem_old[3]; + ViewLayer *view_layer = CTX_data_view_layer(C); + int totelem_old_sel[3]; + int totelem_old[3]; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - EDBM_mesh_stats_multi(objects, objects_len, totelem_old, totelem_old_sel); + EDBM_mesh_stats_multi(objects, objects_len, totelem_old, totelem_old_sel); - const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && totelem_old_sel[0]); - const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && totelem_old_sel[1]); - const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && totelem_old_sel[2]); + const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && totelem_old_sel[0]); + const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && totelem_old_sel[1]); + const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && totelem_old_sel[2]); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter iter; - BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - if (use_faces) { - BMFace *f; + if (use_faces) { + BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_elem_flag_set(f, BM_ELEM_TAG, bm_face_is_loose(f)); - } - } + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_elem_flag_set(f, BM_ELEM_TAG, bm_face_is_loose(f)); + } + } - BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES); - } + BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES); + } - if (use_edges) { - BMEdge *e; + if (use_edges) { + BMEdge *e; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - BM_elem_flag_set(e, BM_ELEM_TAG, BM_edge_is_wire(e)); - } - } + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_edge_is_wire(e)); + } + } - BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_EDGES); - } + BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_EDGES); + } - if (use_verts) { - BMVert *v; + if (use_verts) { + BMVert *v; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - BM_elem_flag_set(v, BM_ELEM_TAG, (v->e == NULL)); - } - } + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + BM_elem_flag_set(v, BM_ELEM_TAG, (v->e == NULL)); + } + } - BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS); - } + BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS); + } - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - EDBM_update_generic(em, true, true); - } + EDBM_update_generic(em, true, true); + } - int totelem_new[3]; - EDBM_mesh_stats_multi(objects, objects_len, totelem_new, NULL); + int totelem_new[3]; + EDBM_mesh_stats_multi(objects, objects_len, totelem_new, NULL); - edbm_report_delete_info(op->reports, totelem_old, totelem_new); + edbm_report_delete_info(op->reports, totelem_old, totelem_new); - MEM_freeN(objects); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } - void MESH_OT_delete_loose(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Loose"; - ot->description = "Delete loose vertices, edges or faces"; - ot->idname = "MESH_OT_delete_loose"; + /* identifiers */ + ot->name = "Delete Loose"; + ot->description = "Delete loose vertices, edges or faces"; + ot->idname = "MESH_OT_delete_loose"; - /* api callbacks */ - ot->exec = edbm_delete_loose_exec; + /* api callbacks */ + ot->exec = edbm_delete_loose_exec; - ot->poll = ED_operator_editmesh; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_boolean(ot->srna, "use_verts", true, "Vertices", "Remove loose vertices"); - RNA_def_boolean(ot->srna, "use_edges", true, "Edges", "Remove loose edges"); - RNA_def_boolean(ot->srna, "use_faces", false, "Faces", "Remove loose faces"); + /* props */ + RNA_def_boolean(ot->srna, "use_verts", true, "Vertices", "Remove loose vertices"); + RNA_def_boolean(ot->srna, "use_edges", true, "Edges", "Remove loose edges"); + RNA_def_boolean(ot->srna, "use_faces", false, "Faces", "Remove loose faces"); } /** \} */ @@ -639,41 +700,42 @@ void MESH_OT_delete_loose(wmOperatorType *ot) static int edbm_collapse_edge_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totedgesel == 0) { - continue; - } + if (em->bm->totedgesel == 0) { + continue; + } - if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true)) { - continue; - } + if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true)) { + continue; + } - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_edge_collapse(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Edge Collapse"; - ot->description = "Collapse selected edges"; - ot->idname = "MESH_OT_edge_collapse"; + /* identifiers */ + ot->name = "Edge Collapse"; + ot->description = "Collapse selected edges"; + ot->idname = "MESH_OT_edge_collapse"; - /* api callbacks */ - ot->exec = edbm_collapse_edge_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_collapse_edge_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -684,18 +746,18 @@ void MESH_OT_edge_collapse(wmOperatorType *ot) static bool edbm_add_edge_face__smooth_get(BMesh *bm) { - BMEdge *e; - BMIter iter; + BMEdge *e; + BMIter iter; - unsigned int vote_on_smooth[2] = {0, 0}; + unsigned int vote_on_smooth[2] = {0, 0}; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) { - vote_on_smooth[BM_elem_flag_test_bool(e->l->f, BM_ELEM_SMOOTH)]++; - } - } + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) { + vote_on_smooth[BM_elem_flag_test_bool(e->l->f, BM_ELEM_SMOOTH)]++; + } + } - return (vote_on_smooth[0] < vote_on_smooth[1]); + return (vote_on_smooth[0] < vote_on_smooth[1]); } #ifdef USE_FACE_CREATE_SEL_EXTEND @@ -704,255 +766,257 @@ static bool edbm_add_edge_face__smooth_get(BMesh *bm) * This is used so we can request all boundary edges connected to a vertex for eg. */ static int edbm_add_edge_face_exec__vert_edge_lookup( - BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len, - bool (* func)(const BMEdge *)) -{ - BMIter iter; - BMEdge *e_iter; - int i = 0; - BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) { - if ((e_used == NULL) || (e_used != e_iter)) { - if (func(e_iter)) { - e_arr[i++] = e_iter; - if (i >= e_arr_len) { - break; - } - } - } - } - } - return i; + BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len, bool (*func)(const BMEdge *)) +{ + BMIter iter; + BMEdge *e_iter; + int i = 0; + BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) { + if ((e_used == NULL) || (e_used != e_iter)) { + if (func(e_iter)) { + e_arr[i++] = e_iter; + if (i >= e_arr_len) { + break; + } + } + } + } + } + return i; } static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm) { - BMIter iter; - bool found = false; - - if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) { - /* first look for 2 boundary edges */ - BMVert *v; - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - found = true; - break; - } - } - - if (found) { - BMEdge *ed_pair[3]; - if ( - ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_wire) == 2) && - (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) || - - ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_boundary) == 2) && - (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) - ) - { - BMEdge *e_other = BM_edge_exists( - BM_edge_other_vert(ed_pair[0], v), - BM_edge_other_vert(ed_pair[1], v)); - BM_edge_select_set(bm, ed_pair[0], true); - BM_edge_select_set(bm, ed_pair[1], true); - if (e_other) { - BM_edge_select_set(bm, e_other, true); - } - return (BMElem *)v; - } - } - } - else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) { - /* first look for 2 boundary edges */ - BMEdge *e; - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - found = true; - break; - } - } - if (found) { - BMEdge *ed_pair_v1[2]; - BMEdge *ed_pair_v2[2]; - if ( - ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == 1) && - (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == 1) && - (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && - (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) || - -#if 1 /* better support mixed cases [#37203] */ - ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == 1) && - (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) && - (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && - (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) || - - ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) && - (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == 1) && - (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && - (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) || -#endif - - ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) && - (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) && - (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && - (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) - ) - { - BMVert *v1_other = BM_edge_other_vert(ed_pair_v1[0], e->v1); - BMVert *v2_other = BM_edge_other_vert(ed_pair_v2[0], e->v2); - BMEdge *e_other = (v1_other != v2_other) ? BM_edge_exists(v1_other, v2_other) : NULL; - BM_edge_select_set(bm, ed_pair_v1[0], true); - BM_edge_select_set(bm, ed_pair_v2[0], true); - if (e_other) { - BM_edge_select_set(bm, e_other, true); - } - return (BMElem *)e; - } - } - } - - return NULL; + BMIter iter; + bool found = false; + + if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) { + /* first look for 2 boundary edges */ + BMVert *v; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + found = true; + break; + } + } + + if (found) { + BMEdge *ed_pair[3]; + if (((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_wire) == + 2) && + (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) || + + ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_boundary) == + 2) && + (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false))) { + BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v), + BM_edge_other_vert(ed_pair[1], v)); + BM_edge_select_set(bm, ed_pair[0], true); + BM_edge_select_set(bm, ed_pair[1], true); + if (e_other) { + BM_edge_select_set(bm, e_other, true); + } + return (BMElem *)v; + } + } + } + else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) { + /* first look for 2 boundary edges */ + BMEdge *e; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + found = true; + break; + } + } + if (found) { + BMEdge *ed_pair_v1[2]; + BMEdge *ed_pair_v2[2]; + if (((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == + 1) && + (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == + 1) && + (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && + (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) || + +# if 1 /* better support mixed cases [#37203] */ + ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == + 1) && + (edbm_add_edge_face_exec__vert_edge_lookup( + e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) && + (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && + (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) || + + ((edbm_add_edge_face_exec__vert_edge_lookup( + e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) && + (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == + 1) && + (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && + (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) || +# endif + + ((edbm_add_edge_face_exec__vert_edge_lookup( + e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) && + (edbm_add_edge_face_exec__vert_edge_lookup( + e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) && + (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && + (BM_edge_share_face_check(e, ed_pair_v2[0]) == false))) { + BMVert *v1_other = BM_edge_other_vert(ed_pair_v1[0], e->v1); + BMVert *v2_other = BM_edge_other_vert(ed_pair_v2[0], e->v2); + BMEdge *e_other = (v1_other != v2_other) ? BM_edge_exists(v1_other, v2_other) : NULL; + BM_edge_select_set(bm, ed_pair_v1[0], true); + BM_edge_select_set(bm, ed_pair_v2[0], true); + if (e_other) { + BM_edge_select_set(bm, e_other, true); + } + return (BMElem *)e; + } + } + } + + return NULL; } static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_desel, BMFace *f) { - /* now we need to find the edge that isnt connected to this element */ - BM_select_history_clear(bm); - - /* Notes on hidden geometry: - * - un-hide the face since its possible hidden was copied when copying surrounding face attributes. - * - un-hide before adding to select history - * since we may extend into an existing, hidden vert/edge. - */ - - BM_elem_flag_disable(f, BM_ELEM_HIDDEN); - BM_face_select_set(bm, f, false); - - if (ele_desel->head.htype == BM_VERT) { - BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel); - BLI_assert(f->len == 3); - BM_vert_select_set(bm, (BMVert *)ele_desel, false); - BM_edge_select_set(bm, l->next->e, true); - BM_select_history_store(bm, l->next->e); - } - else { - BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel); - BLI_assert(f->len == 4 || f->len == 3); - - BM_edge_select_set(bm, (BMEdge *)ele_desel, false); - if (f->len == 4) { - BMEdge *e_active = l->next->next->e; - BM_elem_flag_disable(e_active, BM_ELEM_HIDDEN); - BM_edge_select_set(bm, e_active, true); - BM_select_history_store(bm, e_active); - } - else { - BMVert *v_active = l->next->next->v; - BM_elem_flag_disable(v_active, BM_ELEM_HIDDEN); - BM_vert_select_set(bm, v_active, true); - BM_select_history_store(bm, v_active); - } - } -} -#endif /* USE_FACE_CREATE_SEL_EXTEND */ + /* now we need to find the edge that isnt connected to this element */ + BM_select_history_clear(bm); + + /* Notes on hidden geometry: + * - un-hide the face since its possible hidden was copied when copying surrounding face attributes. + * - un-hide before adding to select history + * since we may extend into an existing, hidden vert/edge. + */ + + BM_elem_flag_disable(f, BM_ELEM_HIDDEN); + BM_face_select_set(bm, f, false); + + if (ele_desel->head.htype == BM_VERT) { + BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel); + BLI_assert(f->len == 3); + BM_vert_select_set(bm, (BMVert *)ele_desel, false); + BM_edge_select_set(bm, l->next->e, true); + BM_select_history_store(bm, l->next->e); + } + else { + BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel); + BLI_assert(f->len == 4 || f->len == 3); + + BM_edge_select_set(bm, (BMEdge *)ele_desel, false); + if (f->len == 4) { + BMEdge *e_active = l->next->next->e; + BM_elem_flag_disable(e_active, BM_ELEM_HIDDEN); + BM_edge_select_set(bm, e_active, true); + BM_select_history_store(bm, e_active); + } + else { + BMVert *v_active = l->next->next->v; + BM_elem_flag_disable(v_active, BM_ELEM_HIDDEN); + BM_vert_select_set(bm, v_active, true); + BM_select_history_store(bm, v_active); + } + } +} +#endif /* USE_FACE_CREATE_SEL_EXTEND */ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) { - /* when this is used to dissolve we could avoid this, but checking isnt too slow */ + /* when this is used to dissolve we could avoid this, but checking isnt too slow */ - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if ((em->bm->totvertsel == 0) && - (em->bm->totedgesel == 0) && - (em->bm->totvertsel == 0)) - { - continue; - } + if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totvertsel == 0)) { + continue; + } - bool use_smooth = edbm_add_edge_face__smooth_get(em->bm); - int totedge_orig = em->bm->totedge; - int totface_orig = em->bm->totface; + bool use_smooth = edbm_add_edge_face__smooth_get(em->bm); + int totedge_orig = em->bm->totedge; + int totface_orig = em->bm->totface; - BMOperator bmop; + BMOperator bmop; #ifdef USE_FACE_CREATE_SEL_EXTEND - BMElem *ele_desel; - BMFace *ele_desel_face; + BMElem *ele_desel; + BMFace *ele_desel_face; - /* be extra clever, figure out if a partial selection should be extended so we can create geometry - * with single vert or single edge selection */ - ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm); + /* be extra clever, figure out if a partial selection should be extended so we can create geometry + * with single vert or single edge selection */ + ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm); #endif - if (!EDBM_op_init( - em, &bmop, op, - "contextual_create geom=%hfev mat_nr=%i use_smooth=%b", - BM_ELEM_SELECT, em->mat_nr, use_smooth)) - { - continue; - } - - BMO_op_exec(em->bm, &bmop); - - /* cancel if nothing was done */ - if ((totedge_orig == em->bm->totedge) && - (totface_orig == em->bm->totface)) - { - EDBM_op_finish(em, &bmop, op, true); - continue; - } + if (!EDBM_op_init(em, + &bmop, + op, + "contextual_create geom=%hfev mat_nr=%i use_smooth=%b", + BM_ELEM_SELECT, + em->mat_nr, + use_smooth)) { + continue; + } + + BMO_op_exec(em->bm, &bmop); + + /* cancel if nothing was done */ + if ((totedge_orig == em->bm->totedge) && (totface_orig == em->bm->totface)) { + EDBM_op_finish(em, &bmop, op, true); + continue; + } #ifdef USE_FACE_CREATE_SEL_EXTEND - /* normally we would want to leave the new geometry selected, - * but being able to press F many times to add geometry is too useful! */ - if (ele_desel && - (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) && - (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out"))) - { - edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face); - } - else + /* normally we would want to leave the new geometry selected, + * but being able to press F many times to add geometry is too useful! */ + if (ele_desel && (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) && + (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out"))) { + edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face); + } + else #endif - { - /* Newly created faces may include existing hidden edges, - * copying face data from surrounding, may have copied hidden face flag too. - * - * Important that faces use flushing since 'edges.out' wont include hidden edges that already existed. - */ - BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true); - BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false); - - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); - } - - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + { + /* Newly created faces may include existing hidden edges, + * copying face data from surrounding, may have copied hidden face flag too. + * + * Important that faces use flushing since 'edges.out' wont include hidden edges that already existed. + */ + BMO_slot_buffer_hflag_disable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true); + BMO_slot_buffer_hflag_disable( + em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false); + + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + } + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_edge_face_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Edge/Face"; - ot->description = "Add an edge or face to selected"; - ot->idname = "MESH_OT_edge_face_add"; + /* identifiers */ + ot->name = "Make Edge/Face"; + ot->description = "Add an edge or face to selected"; + ot->idname = "MESH_OT_edge_face_add"; - /* api callbacks */ - ot->exec = edbm_add_edge_face_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_add_edge_face_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -963,75 +1027,76 @@ void MESH_OT_edge_face_add(wmOperatorType *ot) static int edbm_mark_seam_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - BMEdge *eed; - BMIter iter; - const bool clear = RNA_boolean_get(op->ptr, "clear"); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if (bm->totedgesel == 0) { - continue; - } - - if (clear) { - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - continue; - } - - BM_elem_flag_disable(eed, BM_ELEM_SEAM); - } - } - else { - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - continue; - } - BM_elem_flag_enable(eed, BM_ELEM_SEAM); - } - } - } - - ED_uvedit_live_unwrap(scene, objects, objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - EDBM_update_generic(em, true, false); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + BMEdge *eed; + BMIter iter; + const bool clear = RNA_boolean_get(op->ptr, "clear"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if (bm->totedgesel == 0) { + continue; + } + + if (clear) { + BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + continue; + } + + BM_elem_flag_disable(eed, BM_ELEM_SEAM); + } + } + else { + BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + continue; + } + BM_elem_flag_enable(eed, BM_ELEM_SEAM); + } + } + } + + ED_uvedit_live_unwrap(scene, objects, objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + EDBM_update_generic(em, true, false); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_mark_seam(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Mark Seam"; - ot->idname = "MESH_OT_mark_seam"; - ot->description = "(Un)mark selected edges as a seam"; + /* identifiers */ + ot->name = "Mark Seam"; + ot->idname = "MESH_OT_mark_seam"; + ot->description = "(Un)mark selected edges as a seam"; - /* api callbacks */ - ot->exec = edbm_mark_seam_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_mark_seam_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - WM_operatortype_props_advanced_begin(ot); + WM_operatortype_props_advanced_begin(ot); } /** \} */ @@ -1042,178 +1107,192 @@ void MESH_OT_mark_seam(wmOperatorType *ot) static int edbm_mark_sharp_exec(bContext *C, wmOperator *op) { - BMEdge *eed; - BMIter iter; - const bool clear = RNA_boolean_get(op->ptr, "clear"); - const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); - ViewLayer *view_layer = CTX_data_view_layer(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if (bm->totedgesel == 0) { - continue; - } - - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - if (use_verts) { - if (!(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))) { - continue; - } - } - else if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - continue; - } - - BM_elem_flag_set(eed, BM_ELEM_SMOOTH, clear); - } - - EDBM_update_generic(em, true, false); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + BMEdge *eed; + BMIter iter; + const bool clear = RNA_boolean_get(op->ptr, "clear"); + const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); + ViewLayer *view_layer = CTX_data_view_layer(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if (bm->totedgesel == 0) { + continue; + } + + BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { + if (use_verts) { + if (!(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || + BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))) { + continue; + } + } + else if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + continue; + } + + BM_elem_flag_set(eed, BM_ELEM_SMOOTH, clear); + } + + EDBM_update_generic(em, true, false); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_mark_sharp(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Mark Sharp"; - ot->idname = "MESH_OT_mark_sharp"; - ot->description = "(Un)mark selected edges as sharp"; + /* identifiers */ + ot->name = "Mark Sharp"; + ot->idname = "MESH_OT_mark_sharp"; + ot->description = "(Un)mark selected edges as sharp"; - /* api callbacks */ - ot->exec = edbm_mark_sharp_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_mark_sharp_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "use_verts", false, "Vertices", - "Consider vertices instead of edges to select which edges to (un)tag as sharp"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, + "use_verts", + false, + "Vertices", + "Consider vertices instead of edges to select which edges to (un)tag as sharp"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static bool edbm_connect_vert_pair(BMEditMesh *em, wmOperator *op) { - BMesh *bm = em->bm; - BMOperator bmop; - const int verts_len = bm->totvertsel; - bool is_pair = (verts_len == 2); - int len = 0; - bool check_degenerate = true; - - BMVert **verts; - bool checks_succeded = true; - - /* sanity check */ - if (verts_len < 2) { - return false; - } - - verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__); - { - BMIter iter; - BMVert *v; - int i = 0; - - BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - verts[i++] = v; - } - } - - if (BM_vert_pair_share_face_check_cb( - verts[0], verts[1], - BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN))) - { - check_degenerate = false; - is_pair = false; - } - } - - if (is_pair) { - if (!EDBM_op_init( - em, &bmop, op, - "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf", - verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN)) - { - checks_succeded = false; - } - } - else { - if (!EDBM_op_init( - em, &bmop, op, - "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b", - verts, verts_len, BM_ELEM_HIDDEN, check_degenerate)) - { - checks_succeded = false; - } - } - if (checks_succeded) { - BMO_op_exec(bm, &bmop); - len = BMO_slot_get(bmop.slots_out, "edges.out")->len; - - if (len && is_pair) { - /* new verts have been added, we have to select the edges, not just flush */ - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); - } - - if (!EDBM_op_finish(em, &bmop, op, true)) { - len = 0; - } - else { - /* so newly created edges get the selection state from the vertex */ - EDBM_selectmode_flush(em); - - EDBM_update_generic(em, true, true); - } - } - MEM_freeN(verts); - - return len; + BMesh *bm = em->bm; + BMOperator bmop; + const int verts_len = bm->totvertsel; + bool is_pair = (verts_len == 2); + int len = 0; + bool check_degenerate = true; + + BMVert **verts; + bool checks_succeded = true; + + /* sanity check */ + if (verts_len < 2) { + return false; + } + + verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__); + { + BMIter iter; + BMVert *v; + int i = 0; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + verts[i++] = v; + } + } + + if (BM_vert_pair_share_face_check_cb( + verts[0], + verts[1], + BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN))) { + check_degenerate = false; + is_pair = false; + } + } + + if (is_pair) { + if (!EDBM_op_init(em, + &bmop, + op, + "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf", + verts, + verts_len, + BM_ELEM_HIDDEN, + BM_ELEM_HIDDEN)) { + checks_succeded = false; + } + } + else { + if (!EDBM_op_init(em, + &bmop, + op, + "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b", + verts, + verts_len, + BM_ELEM_HIDDEN, + check_degenerate)) { + checks_succeded = false; + } + } + if (checks_succeded) { + BMO_op_exec(bm, &bmop); + len = BMO_slot_get(bmop.slots_out, "edges.out")->len; + + if (len && is_pair) { + /* new verts have been added, we have to select the edges, not just flush */ + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + } + + if (!EDBM_op_finish(em, &bmop, op, true)) { + len = 0; + } + else { + /* so newly created edges get the selection state from the vertex */ + EDBM_selectmode_flush(em); + + EDBM_update_generic(em, true, true); + } + } + MEM_freeN(verts); + + return len; } static int edbm_vert_connect_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - uint failed_objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + uint failed_objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (!edbm_connect_vert_pair(em, op)) { - failed_objects_len++; - } - } - MEM_freeN(objects); - return failed_objects_len == objects_len ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + if (!edbm_connect_vert_pair(em, op)) { + failed_objects_len++; + } + } + MEM_freeN(objects); + return failed_objects_len == objects_len ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void MESH_OT_vert_connect(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Vertex Connect"; - ot->idname = "MESH_OT_vert_connect"; - ot->description = "Connect selected vertices of faces, splitting the face"; + /* identifiers */ + ot->name = "Vertex Connect"; + ot->idname = "MESH_OT_vert_connect"; + ot->description = "Connect selected vertices of faces, splitting the face"; - /* api callbacks */ - ot->exec = edbm_vert_connect_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_vert_connect_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -1227,146 +1306,139 @@ void MESH_OT_vert_connect(wmOperatorType *ot) */ static bool bm_vert_is_select_history_open(BMesh *bm) { - BMEditSelection *ele_a = bm->selected.first; - BMEditSelection *ele_b = bm->selected.last; - if ((ele_a->htype == BM_VERT) && - (ele_b->htype == BM_VERT)) - { - if ((BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_a->ele, BM_ELEM_SELECT, true) == 1) && - (BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_b->ele, BM_ELEM_SELECT, true) == 1)) - { - return true; - } - } + BMEditSelection *ele_a = bm->selected.first; + BMEditSelection *ele_b = bm->selected.last; + if ((ele_a->htype == BM_VERT) && (ele_b->htype == BM_VERT)) { + if ((BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_a->ele, BM_ELEM_SELECT, true) == + 1) && + (BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_b->ele, BM_ELEM_SELECT, true) == + 1)) { + return true; + } + } - return false; + return false; } static bool bm_vert_connect_pair(BMesh *bm, BMVert *v_a, BMVert *v_b) { - BMOperator bmop; - BMVert **verts; - const int totedge_orig = bm->totedge; + BMOperator bmop; + BMVert **verts; + const int totedge_orig = bm->totedge; - BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, "connect_vert_pair"); + BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, "connect_vert_pair"); - verts = BMO_slot_buffer_alloc(&bmop, bmop.slots_in, "verts", 2); - verts[0] = v_a; - verts[1] = v_b; + verts = BMO_slot_buffer_alloc(&bmop, bmop.slots_in, "verts", 2); + verts[0] = v_a; + verts[1] = v_b; - BM_vert_normal_update(verts[0]); - BM_vert_normal_update(verts[1]); + BM_vert_normal_update(verts[0]); + BM_vert_normal_update(verts[1]); - BMO_op_exec(bm, &bmop); - BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); - BMO_op_finish(bm, &bmop); - return (bm->totedge != totedge_orig); + BMO_op_exec(bm, &bmop); + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + BMO_op_finish(bm, &bmop); + return (bm->totedge != totedge_orig); } static bool bm_vert_connect_select_history(BMesh *bm) { - /* Logic is as follows: - * - * - If there are any isolated/wire verts - connect as edges. - * - Otherwise connect faces. - * - If all edges have been created already, closed the loop. - */ - if (BLI_listbase_count_at_most(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) { - BMEditSelection *ese; - int tot = 0; - bool changed = false; - bool has_wire = false; - // bool all_verts; - - /* ensure all verts have history */ - for (ese = bm->selected.first; ese; ese = ese->next, tot++) { - BMVert *v; - if (ese->htype != BM_VERT) { - break; - } - v = (BMVert *)ese->ele; - if ((has_wire == false) && ((v->e == NULL) || BM_vert_is_wire(v))) { - has_wire = true; - } - } - // all_verts = (ese == NULL); - - if (has_wire == false) { - /* all verts have faces , connect verts via faces! */ - if (tot == bm->totvertsel) { - BMEditSelection *ese_last; - ese_last = bm->selected.first; - ese = ese_last->next; - - do { - - if (BM_edge_exists((BMVert *)ese_last->ele, (BMVert *)ese->ele)) { - /* pass, edge exists (and will be selected) */ - } - else { - changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele); - } - } while ((void) - (ese_last = ese), - (ese = ese->next)); - - if (changed) { - return true; - } - } - - if (changed == false) { - /* existing loops: close the selection */ - if (bm_vert_is_select_history_open(bm)) { - changed |= bm_vert_connect_pair( - bm, - (BMVert *)((BMEditSelection *)bm->selected.first)->ele, - (BMVert *)((BMEditSelection *)bm->selected.last)->ele); - - if (changed) { - return true; - } - } - } - } - - else { - /* no faces, simply connect the verts by edges */ - BMEditSelection *ese_prev; - ese_prev = bm->selected.first; - ese = ese_prev->next; - - - do { - if (BM_edge_exists((BMVert *)ese_prev->ele, (BMVert *)ese->ele)) { - /* pass, edge exists (and will be selected) */ - } - else { - BMEdge *e; - e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0); - BM_edge_select_set(bm, e, true); - changed = true; - } - } while ((void) - (ese_prev = ese), - (ese = ese->next)); - - if (changed == false) { - /* existing loops: close the selection */ - if (bm_vert_is_select_history_open(bm)) { - BMEdge *e; - ese_prev = bm->selected.first; - ese = bm->selected.last; - e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0); - BM_edge_select_set(bm, e, true); - } - } - - return true; - } - } - - return false; + /* Logic is as follows: + * + * - If there are any isolated/wire verts - connect as edges. + * - Otherwise connect faces. + * - If all edges have been created already, closed the loop. + */ + if (BLI_listbase_count_at_most(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) { + BMEditSelection *ese; + int tot = 0; + bool changed = false; + bool has_wire = false; + // bool all_verts; + + /* ensure all verts have history */ + for (ese = bm->selected.first; ese; ese = ese->next, tot++) { + BMVert *v; + if (ese->htype != BM_VERT) { + break; + } + v = (BMVert *)ese->ele; + if ((has_wire == false) && ((v->e == NULL) || BM_vert_is_wire(v))) { + has_wire = true; + } + } + // all_verts = (ese == NULL); + + if (has_wire == false) { + /* all verts have faces , connect verts via faces! */ + if (tot == bm->totvertsel) { + BMEditSelection *ese_last; + ese_last = bm->selected.first; + ese = ese_last->next; + + do { + + if (BM_edge_exists((BMVert *)ese_last->ele, (BMVert *)ese->ele)) { + /* pass, edge exists (and will be selected) */ + } + else { + changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele); + } + } while ((void)(ese_last = ese), (ese = ese->next)); + + if (changed) { + return true; + } + } + + if (changed == false) { + /* existing loops: close the selection */ + if (bm_vert_is_select_history_open(bm)) { + changed |= bm_vert_connect_pair(bm, + (BMVert *)((BMEditSelection *)bm->selected.first)->ele, + (BMVert *)((BMEditSelection *)bm->selected.last)->ele); + + if (changed) { + return true; + } + } + } + } + + else { + /* no faces, simply connect the verts by edges */ + BMEditSelection *ese_prev; + ese_prev = bm->selected.first; + ese = ese_prev->next; + + do { + if (BM_edge_exists((BMVert *)ese_prev->ele, (BMVert *)ese->ele)) { + /* pass, edge exists (and will be selected) */ + } + else { + BMEdge *e; + e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0); + BM_edge_select_set(bm, e, true); + changed = true; + } + } while ((void)(ese_prev = ese), (ese = ese->next)); + + if (changed == false) { + /* existing loops: close the selection */ + if (bm_vert_is_select_history_open(bm)) { + BMEdge *e; + ese_prev = bm->selected.first; + ese = bm->selected.last; + e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0); + BM_edge_select_set(bm, e, true); + } + } + + return true; + } + } + + return false; } /** @@ -1375,186 +1447,184 @@ static bool bm_vert_connect_select_history(BMesh *bm) */ static bool bm_vert_connect_select_history_edge_to_vert_path(BMesh *bm, ListBase *r_selected) { - ListBase selected_orig = {NULL, NULL}; - BMEditSelection *ese; - int edges_len = 0; - bool side = false; - - /* first check all edges are OK */ - for (ese = bm->selected.first; ese; ese = ese->next) { - if (ese->htype == BM_EDGE) { - edges_len += 1; - } - else { - return false; - } - } - /* if this is a mixed selection, bail out! */ - if (bm->totedgesel != edges_len) { - return false; - } - - SWAP(ListBase, bm->selected, selected_orig); - - /* convert edge selection into 2 ordered loops (where the first edge ends up in the middle) */ - for (ese = selected_orig.first; ese; ese = ese->next) { - BMEdge *e_curr = (BMEdge *)ese->ele; - BMEdge *e_prev = ese->prev ? (BMEdge *)ese->prev->ele : NULL; - BMLoop *l_curr; - BMLoop *l_prev; - BMVert *v; - - if (e_prev) { - BMFace *f = BM_edge_pair_share_face_by_len(e_curr, e_prev, &l_curr, &l_prev, true); - if (f) { - if ((e_curr->v1 != l_curr->v) == (e_prev->v1 != l_prev->v)) { - side = !side; - } - } - else if (is_quad_flip_v3(e_curr->v1->co, e_curr->v2->co, e_prev->v2->co, e_prev->v1->co)) { - side = !side; - } - } - - v = (&e_curr->v1)[side]; - if (!bm->selected.last || (BMVert *)((BMEditSelection *)bm->selected.last)->ele != v) { - BM_select_history_store_notest(bm, v); - } - - v = (&e_curr->v1)[!side]; - if (!bm->selected.first || (BMVert *)((BMEditSelection *)bm->selected.first)->ele != v) { - BM_select_history_store_head_notest(bm, v); - } - - e_prev = e_curr; - } - - *r_selected = bm->selected; - bm->selected = selected_orig; - - return true; + ListBase selected_orig = {NULL, NULL}; + BMEditSelection *ese; + int edges_len = 0; + bool side = false; + + /* first check all edges are OK */ + for (ese = bm->selected.first; ese; ese = ese->next) { + if (ese->htype == BM_EDGE) { + edges_len += 1; + } + else { + return false; + } + } + /* if this is a mixed selection, bail out! */ + if (bm->totedgesel != edges_len) { + return false; + } + + SWAP(ListBase, bm->selected, selected_orig); + + /* convert edge selection into 2 ordered loops (where the first edge ends up in the middle) */ + for (ese = selected_orig.first; ese; ese = ese->next) { + BMEdge *e_curr = (BMEdge *)ese->ele; + BMEdge *e_prev = ese->prev ? (BMEdge *)ese->prev->ele : NULL; + BMLoop *l_curr; + BMLoop *l_prev; + BMVert *v; + + if (e_prev) { + BMFace *f = BM_edge_pair_share_face_by_len(e_curr, e_prev, &l_curr, &l_prev, true); + if (f) { + if ((e_curr->v1 != l_curr->v) == (e_prev->v1 != l_prev->v)) { + side = !side; + } + } + else if (is_quad_flip_v3(e_curr->v1->co, e_curr->v2->co, e_prev->v2->co, e_prev->v1->co)) { + side = !side; + } + } + + v = (&e_curr->v1)[side]; + if (!bm->selected.last || (BMVert *)((BMEditSelection *)bm->selected.last)->ele != v) { + BM_select_history_store_notest(bm, v); + } + + v = (&e_curr->v1)[!side]; + if (!bm->selected.first || (BMVert *)((BMEditSelection *)bm->selected.first)->ele != v) { + BM_select_history_store_head_notest(bm, v); + } + + e_prev = e_curr; + } + + *r_selected = bm->selected; + bm->selected = selected_orig; + + return true; } static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - uint failed_selection_order_len = 0; - uint failed_connect_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - const bool is_pair = (em->bm->totvertsel == 2); - ListBase selected_orig = {NULL, NULL}; - - if (bm->totvertsel == 0) { - continue; - } - - /* when there is only 2 vertices, we can ignore selection order */ - if (is_pair) { - if (!edbm_connect_vert_pair(em, op)) { - failed_connect_len++; - } - continue; - } - - if (bm->selected.first) { - BMEditSelection *ese = bm->selected.first; - if (ese->htype == BM_EDGE) { - if (bm_vert_connect_select_history_edge_to_vert_path(bm, &selected_orig)) { - SWAP(ListBase, bm->selected, selected_orig); - } - } - } - - if (bm_vert_connect_select_history(bm)) { - EDBM_selectmode_flush(em); - EDBM_update_generic(em, true, true); - } - else { - failed_selection_order_len++; - } - - if (!BLI_listbase_is_empty(&selected_orig)) { - BM_select_history_clear(bm); - bm->selected = selected_orig; - } - } - - MEM_freeN(objects); - - if (failed_selection_order_len == objects_len) { - BKE_report(op->reports, RPT_ERROR, "Invalid selection order"); - return OPERATOR_CANCELLED; - } - else if (failed_connect_len == objects_len) { - BKE_report(op->reports, RPT_ERROR, "Could not connect vertices"); - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + uint failed_selection_order_len = 0; + uint failed_connect_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + const bool is_pair = (em->bm->totvertsel == 2); + ListBase selected_orig = {NULL, NULL}; + + if (bm->totvertsel == 0) { + continue; + } + + /* when there is only 2 vertices, we can ignore selection order */ + if (is_pair) { + if (!edbm_connect_vert_pair(em, op)) { + failed_connect_len++; + } + continue; + } + + if (bm->selected.first) { + BMEditSelection *ese = bm->selected.first; + if (ese->htype == BM_EDGE) { + if (bm_vert_connect_select_history_edge_to_vert_path(bm, &selected_orig)) { + SWAP(ListBase, bm->selected, selected_orig); + } + } + } + + if (bm_vert_connect_select_history(bm)) { + EDBM_selectmode_flush(em); + EDBM_update_generic(em, true, true); + } + else { + failed_selection_order_len++; + } + + if (!BLI_listbase_is_empty(&selected_orig)) { + BM_select_history_clear(bm); + bm->selected = selected_orig; + } + } + + MEM_freeN(objects); + + if (failed_selection_order_len == objects_len) { + BKE_report(op->reports, RPT_ERROR, "Invalid selection order"); + return OPERATOR_CANCELLED; + } + else if (failed_connect_len == objects_len) { + BKE_report(op->reports, RPT_ERROR, "Could not connect vertices"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } void MESH_OT_vert_connect_path(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Vertex Connect Path"; - ot->idname = "MESH_OT_vert_connect_path"; - ot->description = "Connect vertices by their selection order, creating edges, splitting faces"; + /* identifiers */ + ot->name = "Vertex Connect Path"; + ot->idname = "MESH_OT_vert_connect_path"; + ot->description = "Connect vertices by their selection order, creating edges, splitting faces"; - /* api callbacks */ - ot->exec = edbm_vert_connect_path_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_vert_connect_path_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - if (!EDBM_op_call_and_selectf( - em, op, - "faces.out", true, - "connect_verts_concave faces=%hf", - BM_ELEM_SELECT)) - { - continue; - } - EDBM_update_generic(em, true, true); - } + if (!EDBM_op_call_and_selectf( + em, op, "faces.out", true, "connect_verts_concave faces=%hf", BM_ELEM_SELECT)) { + continue; + } + EDBM_update_generic(em, true, true); + } - MEM_freeN(objects); - return OPERATOR_FINISHED; + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_vert_connect_concave(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Split Concave Faces"; - ot->idname = "MESH_OT_vert_connect_concave"; - ot->description = "Make all faces convex"; + /* identifiers */ + ot->name = "Split Concave Faces"; + ot->idname = "MESH_OT_vert_connect_concave"; + ot->description = "Make all faces convex"; - /* api callbacks */ - ot->exec = edbm_vert_connect_concave_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_vert_connect_concave_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -1565,55 +1635,65 @@ void MESH_OT_vert_connect_concave(wmOperatorType *ot) static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const float angle_limit = RNA_float_get(op->ptr, "angle_limit"); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + const float angle_limit = RNA_float_get(op->ptr, "angle_limit"); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - if (!EDBM_op_call_and_selectf( - em, op, - "faces.out", true, - "connect_verts_nonplanar faces=%hf angle_limit=%f", - BM_ELEM_SELECT, angle_limit)) - { - continue; - } + if (!EDBM_op_call_and_selectf(em, + op, + "faces.out", + true, + "connect_verts_nonplanar faces=%hf angle_limit=%f", + BM_ELEM_SELECT, + angle_limit)) { + continue; + } - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Split Non-Planar Faces"; - ot->idname = "MESH_OT_vert_connect_nonplanar"; - ot->description = "Split non-planar faces that exceed the angle threshold"; + /* identifiers */ + ot->name = "Split Non-Planar Faces"; + ot->idname = "MESH_OT_vert_connect_nonplanar"; + ot->description = "Split non-planar faces that exceed the angle threshold"; - /* api callbacks */ - ot->exec = edbm_vert_connect_nonplaner_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_vert_connect_nonplaner_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f), - "Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f)); - RNA_def_property_float_default(prop, DEG2RADF(5.0f)); + /* props */ + prop = RNA_def_float_rotation(ot->srna, + "angle_limit", + 0, + NULL, + 0.0f, + DEG2RADF(180.0f), + "Max Angle", + "Angle limit", + 0.0f, + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(5.0f)); } /** \} */ @@ -1624,51 +1704,54 @@ void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot) static int edbm_face_make_planar_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - const int repeat = RNA_int_get(op->ptr, "repeat"); - const float fac = RNA_float_get(op->ptr, "factor"); + const int repeat = RNA_int_get(op->ptr, "repeat"); + const float fac = RNA_float_get(op->ptr, "factor"); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totfacesel == 0) { + continue; + } - if (!EDBM_op_callf( - em, op, "planar_faces faces=%hf iterations=%i factor=%f", - BM_ELEM_SELECT, repeat, fac)) - { - continue; - } + if (!EDBM_op_callf(em, + op, + "planar_faces faces=%hf iterations=%i factor=%f", + BM_ELEM_SELECT, + repeat, + fac)) { + continue; + } - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_face_make_planar(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Planar Faces"; - ot->idname = "MESH_OT_face_make_planar"; - ot->description = "Flatten selected faces"; + /* identifiers */ + ot->name = "Make Planar Faces"; + ot->idname = "MESH_OT_face_make_planar"; + ot->description = "Flatten selected faces"; - /* api callbacks */ - ot->exec = edbm_face_make_planar_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_face_make_planar_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_float(ot->srna, "factor", 1.0f, -10.0f, 10.0f, "Factor", "", 0.0f, 1.0f); - RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200); + /* props */ + RNA_def_float(ot->srna, "factor", 1.0f, -10.0f, 10.0f, "Factor", "", 0.0f, 1.0f); + RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200); } /** \} */ @@ -1679,49 +1762,46 @@ void MESH_OT_face_make_planar(wmOperatorType *ot) static int edbm_edge_split_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totedgesel == 0) { - continue; - } + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totedgesel == 0) { + continue; + } - if (!EDBM_op_call_and_selectf( - em, op, - "edges.out", false, - "split_edges edges=%he", - BM_ELEM_SELECT)) - { - continue; - } + if (!EDBM_op_call_and_selectf( + em, op, "edges.out", false, "split_edges edges=%he", BM_ELEM_SELECT)) { + continue; + } - if (em->selectmode == SCE_SELECT_FACE) { - EDBM_select_flush(em); - } + if (em->selectmode == SCE_SELECT_FACE) { + EDBM_select_flush(em); + } - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_edge_split(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Edge Split"; - ot->idname = "MESH_OT_edge_split"; - ot->description = "Split selected edges so that each neighbor face gets its own copy"; + /* identifiers */ + ot->name = "Edge Split"; + ot->idname = "MESH_OT_edge_split"; + ot->description = "Split selected edges so that each neighbor face gets its own copy"; - /* api callbacks */ - ot->exec = edbm_edge_split_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_edge_split_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -1732,71 +1812,76 @@ void MESH_OT_edge_split(wmOperatorType *ot) static int edbm_duplicate_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel == 0) { - continue; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel == 0) { + continue; + } - BMOperator bmop; - BMesh *bm = em->bm; + BMOperator bmop; + BMesh *bm = em->bm; - EDBM_op_init( - em, &bmop, op, - "duplicate geom=%hvef use_select_history=%b use_edge_flip_from_face=%b", - BM_ELEM_SELECT, true, true); + EDBM_op_init(em, + &bmop, + op, + "duplicate geom=%hvef use_select_history=%b use_edge_flip_from_face=%b", + BM_ELEM_SELECT, + true, + true); - BMO_op_exec(bm, &bmop); + BMO_op_exec(bm, &bmop); - /* de-select all would clear otherwise */ - BM_SELECT_HISTORY_BACKUP(bm); + /* de-select all would clear otherwise */ + BM_SELECT_HISTORY_BACKUP(bm); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable( + bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); - /* rebuild editselection */ - BM_SELECT_HISTORY_RESTORE(bm); + /* rebuild editselection */ + BM_SELECT_HISTORY_RESTORE(bm); - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - WM_cursor_wait(1); - edbm_duplicate_exec(C, op); - WM_cursor_wait(0); + WM_cursor_wait(1); + edbm_duplicate_exec(C, op); + WM_cursor_wait(0); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_duplicate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Duplicate"; - ot->description = "Duplicate selected vertices, edges or faces"; - ot->idname = "MESH_OT_duplicate"; + /* identifiers */ + ot->name = "Duplicate"; + ot->description = "Duplicate selected vertices, edges or faces"; + ot->idname = "MESH_OT_duplicate"; - /* api callbacks */ - ot->invoke = edbm_duplicate_invoke; - ot->exec = edbm_duplicate_exec; + /* api callbacks */ + ot->invoke = edbm_duplicate_invoke; + ot->exec = edbm_duplicate_exec; - ot->poll = ED_operator_editmesh; + ot->poll = ED_operator_editmesh; - /* to give to transform */ - RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX); + /* to give to transform */ + RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX); } /** \} */ @@ -1806,45 +1891,43 @@ void MESH_OT_duplicate(wmOperatorType *ot) * \{ */ static int edbm_flip_normals_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - if (!EDBM_op_callf( - em, op, "reverse_faces faces=%hf flip_multires=%b", - BM_ELEM_SELECT, true)) - { - continue; - } + if (!EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) { + continue; + } - EDBM_update_generic(em, true, false); - } + EDBM_update_generic(em, true, false); + } - MEM_freeN(objects); - return OPERATOR_FINISHED; + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_flip_normals(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Flip Normals"; - ot->description = "Flip the direction of selected faces' normals (and of their vertices)"; - ot->idname = "MESH_OT_flip_normals"; + /* identifiers */ + ot->name = "Flip Normals"; + ot->description = "Flip the direction of selected faces' normals (and of their vertices)"; + ot->idname = "MESH_OT_flip_normals"; - /* api callbacks */ - ot->exec = edbm_flip_normals_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_flip_normals_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -1858,120 +1941,124 @@ void MESH_OT_flip_normals(wmOperatorType *ot) */ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op) { - BMEdge *eed; - BMIter iter; - const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw"); - - int tot_rotate_all = 0, tot_failed_all = 0; - bool no_selected_edges = true, invalid_selected_edges = true; - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - int tot = 0; - - if (em->bm->totedgesel == 0) { - continue; - } - no_selected_edges = false; - - /* first see if we have two adjacent faces */ - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_disable(eed, BM_ELEM_TAG); - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - BMFace *fa, *fb; - if (BM_edge_face_pair(eed, &fa, &fb)) { - /* if both faces are selected we rotate between them, - * otherwise - rotate between 2 unselected - but not mixed */ - if (BM_elem_flag_test(fa, BM_ELEM_SELECT) == BM_elem_flag_test(fb, BM_ELEM_SELECT)) { - BM_elem_flag_enable(eed, BM_ELEM_TAG); - tot++; - } - } - } - } - - /* ok, we don't have two adjacent faces, but we do have two selected ones. - * that's an error condition.*/ - if (tot == 0) { - continue; - } - invalid_selected_edges = false; - - BMOperator bmop; - EDBM_op_init(em, &bmop, op, "rotate_edges edges=%he use_ccw=%b", BM_ELEM_TAG, use_ccw); - - /* avoids leaving old verts selected which can be a problem running multiple times, - * since this means the edges become selected around the face - * which then attempt to rotate */ - BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "edges", BM_EDGE, BM_ELEM_SELECT, true); - - BMO_op_exec(em->bm, &bmop); - /* edges may rotate into hidden vertices, if this does _not_ run we get an illogical state */ - BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); - - const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out"); - const int tot_failed = tot - tot_rotate; - - tot_rotate_all += tot_rotate; - tot_failed_all += tot_failed; - - if (tot_failed != 0) { - /* If some edges fail to rotate, we need to re-select them, - * otherwise we can end up with invalid selection - * (unselected edge between 2 selected faces). */ - BM_mesh_elem_hflag_enable_test(em->bm, BM_EDGE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); - } - - EDBM_selectmode_flush(em); - - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - - if (no_selected_edges) { - BKE_report(op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about"); - return OPERATOR_CANCELLED; - } - - /* Ok, we don't have two adjacent faces, but we do have two selected ones. - * that's an error condition. */ - if (invalid_selected_edges) { - BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated"); - return OPERATOR_CANCELLED; - } - - if (tot_failed_all != 0) { - BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all); - } - - return OPERATOR_FINISHED; + BMEdge *eed; + BMIter iter; + const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw"); + + int tot_rotate_all = 0, tot_failed_all = 0; + bool no_selected_edges = true, invalid_selected_edges = true; + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + int tot = 0; + + if (em->bm->totedgesel == 0) { + continue; + } + no_selected_edges = false; + + /* first see if we have two adjacent faces */ + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_disable(eed, BM_ELEM_TAG); + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + BMFace *fa, *fb; + if (BM_edge_face_pair(eed, &fa, &fb)) { + /* if both faces are selected we rotate between them, + * otherwise - rotate between 2 unselected - but not mixed */ + if (BM_elem_flag_test(fa, BM_ELEM_SELECT) == BM_elem_flag_test(fb, BM_ELEM_SELECT)) { + BM_elem_flag_enable(eed, BM_ELEM_TAG); + tot++; + } + } + } + } + + /* ok, we don't have two adjacent faces, but we do have two selected ones. + * that's an error condition.*/ + if (tot == 0) { + continue; + } + invalid_selected_edges = false; + + BMOperator bmop; + EDBM_op_init(em, &bmop, op, "rotate_edges edges=%he use_ccw=%b", BM_ELEM_TAG, use_ccw); + + /* avoids leaving old verts selected which can be a problem running multiple times, + * since this means the edges become selected around the face + * which then attempt to rotate */ + BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "edges", BM_EDGE, BM_ELEM_SELECT, true); + + BMO_op_exec(em->bm, &bmop); + /* edges may rotate into hidden vertices, if this does _not_ run we get an illogical state */ + BMO_slot_buffer_hflag_disable( + em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + + const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out"); + const int tot_failed = tot - tot_rotate; + + tot_rotate_all += tot_rotate; + tot_failed_all += tot_failed; + + if (tot_failed != 0) { + /* If some edges fail to rotate, we need to re-select them, + * otherwise we can end up with invalid selection + * (unselected edge between 2 selected faces). */ + BM_mesh_elem_hflag_enable_test(em->bm, BM_EDGE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); + } + + EDBM_selectmode_flush(em); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + + if (no_selected_edges) { + BKE_report( + op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about"); + return OPERATOR_CANCELLED; + } + + /* Ok, we don't have two adjacent faces, but we do have two selected ones. + * that's an error condition. */ + if (invalid_selected_edges) { + BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated"); + return OPERATOR_CANCELLED; + } + + if (tot_failed_all != 0) { + BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all); + } + + return OPERATOR_FINISHED; } void MESH_OT_edge_rotate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Rotate Selected Edge"; - ot->description = "Rotate selected edge or adjoining faces"; - ot->idname = "MESH_OT_edge_rotate"; + /* identifiers */ + ot->name = "Rotate Selected Edge"; + ot->description = "Rotate selected edge or adjoining faces"; + ot->idname = "MESH_OT_edge_rotate"; - /* api callbacks */ - ot->exec = edbm_edge_rotate_selected_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_edge_rotate_selected_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", ""); + /* props */ + RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", ""); } /** \} */ @@ -1982,58 +2069,60 @@ void MESH_OT_edge_rotate(wmOperatorType *ot) static int edbm_hide_exec(bContext *C, wmOperator *op) { - const bool unselected = RNA_boolean_get(op->ptr, "unselected"); - ViewLayer *view_layer = CTX_data_view_layer(C); - bool changed = false; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if (unselected) { - if (bm->totvertsel == bm->totvert) { - continue; - } - } - else { - if (bm->totvertsel == 0) { - continue; - } - } - - if (EDBM_mesh_hide(em, unselected)) { - EDBM_update_generic(em, true, false); - changed = true; - } - } - MEM_freeN(objects); - - if (!changed) { - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + const bool unselected = RNA_boolean_get(op->ptr, "unselected"); + ViewLayer *view_layer = CTX_data_view_layer(C); + bool changed = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if (unselected) { + if (bm->totvertsel == bm->totvert) { + continue; + } + } + else { + if (bm->totvertsel == 0) { + continue; + } + } + + if (EDBM_mesh_hide(em, unselected)) { + EDBM_update_generic(em, true, false); + changed = true; + } + } + MEM_freeN(objects); + + if (!changed) { + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } void MESH_OT_hide(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Hide Selected"; - ot->idname = "MESH_OT_hide"; - ot->description = "Hide (un)selected vertices, edges or faces"; + /* identifiers */ + ot->name = "Hide Selected"; + ot->idname = "MESH_OT_hide"; + ot->description = "Hide (un)selected vertices, edges or faces"; - /* api callbacks */ - ot->exec = edbm_hide_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_hide_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected"); + /* props */ + RNA_def_boolean( + ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected"); } /** \} */ @@ -2044,39 +2133,40 @@ void MESH_OT_hide(wmOperatorType *ot) static int edbm_reveal_exec(bContext *C, wmOperator *op) { - const bool select = RNA_boolean_get(op->ptr, "select"); - ViewLayer *view_layer = CTX_data_view_layer(C); + const bool select = RNA_boolean_get(op->ptr, "select"); + ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (EDBM_mesh_reveal(em, select)) { - EDBM_update_generic(em, true, false); - } - } - MEM_freeN(objects); + if (EDBM_mesh_reveal(em, select)) { + EDBM_update_generic(em, true, false); + } + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_reveal(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Reveal Hidden"; - ot->idname = "MESH_OT_reveal"; - ot->description = "Reveal all hidden vertices, edges and faces"; + /* identifiers */ + ot->name = "Reveal Hidden"; + ot->idname = "MESH_OT_reveal"; + ot->description = "Reveal all hidden vertices, edges and faces"; - /* api callbacks */ - ot->exec = edbm_reveal_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_reveal_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "select", true, "Select", ""); + RNA_def_boolean(ot->srna, "select", true, "Select", ""); } /** \} */ @@ -2087,47 +2177,48 @@ void MESH_OT_reveal(wmOperatorType *ot) static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); + ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) { - continue; - } - if (RNA_boolean_get(op->ptr, "inside")) { - EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true); - } + if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) { + continue; + } + if (RNA_boolean_get(op->ptr, "inside")) { + EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true); + } - EDBM_update_generic(em, true, false); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, false); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_normals_make_consistent(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Normals Consistent"; - ot->description = "Make face and vertex normals point either outside or inside the mesh"; - ot->idname = "MESH_OT_normals_make_consistent"; + /* identifiers */ + ot->name = "Make Normals Consistent"; + ot->description = "Make face and vertex normals point either outside or inside the mesh"; + ot->idname = "MESH_OT_normals_make_consistent"; - /* api callbacks */ - ot->exec = edbm_normals_make_consistent_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_normals_make_consistent_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "inside", false, "Inside", ""); + RNA_def_boolean(ot->srna, "inside", false, "Inside", ""); } /** \} */ @@ -2138,105 +2229,116 @@ void MESH_OT_normals_make_consistent(wmOperatorType *ot) static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op) { - const float fac = RNA_float_get(op->ptr, "factor"); - - const bool xaxis = RNA_boolean_get(op->ptr, "xaxis"); - const bool yaxis = RNA_boolean_get(op->ptr, "yaxis"); - const bool zaxis = RNA_boolean_get(op->ptr, "zaxis"); - int repeat = RNA_int_get(op->ptr, "repeat"); - - if (!repeat) { - repeat = 1; - } - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - Mesh *me = obedit->data; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - ModifierData *md; - bool mirrx = false, mirry = false, mirrz = false; - int i; - float clip_dist = 0.0f; - const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - - if (em->bm->totvertsel == 0) { - continue; - } - - /* mirror before smooth */ - if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { - EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology); - } - - /* if there is a mirror modifier with clipping, flag the verts that - * are within tolerance of the plane(s) of reflection - */ - for (md = obedit->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) { - MirrorModifierData *mmd = (MirrorModifierData *)md; - - if (mmd->flag & MOD_MIR_CLIPPING) { - if (mmd->flag & MOD_MIR_AXIS_X) - mirrx = true; - if (mmd->flag & MOD_MIR_AXIS_Y) - mirry = true; - if (mmd->flag & MOD_MIR_AXIS_Z) - mirrz = true; - - clip_dist = mmd->tolerance; - } - } - } - - for (i = 0; i < repeat; i++) { - if (!EDBM_op_callf( - em, op, - "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b " - "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b", - BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis)) - { - continue; - } - } - - /* apply mirror */ - if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { - EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0); - EDBM_verts_mirror_cache_end(em); - } - - EDBM_update_generic(em, true, false); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const float fac = RNA_float_get(op->ptr, "factor"); + + const bool xaxis = RNA_boolean_get(op->ptr, "xaxis"); + const bool yaxis = RNA_boolean_get(op->ptr, "yaxis"); + const bool zaxis = RNA_boolean_get(op->ptr, "zaxis"); + int repeat = RNA_int_get(op->ptr, "repeat"); + + if (!repeat) { + repeat = 1; + } + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + Mesh *me = obedit->data; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + ModifierData *md; + bool mirrx = false, mirry = false, mirrz = false; + int i; + float clip_dist = 0.0f; + const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + + if (em->bm->totvertsel == 0) { + continue; + } + + /* mirror before smooth */ + if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { + EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology); + } + + /* if there is a mirror modifier with clipping, flag the verts that + * are within tolerance of the plane(s) of reflection + */ + for (md = obedit->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) { + MirrorModifierData *mmd = (MirrorModifierData *)md; + + if (mmd->flag & MOD_MIR_CLIPPING) { + if (mmd->flag & MOD_MIR_AXIS_X) + mirrx = true; + if (mmd->flag & MOD_MIR_AXIS_Y) + mirry = true; + if (mmd->flag & MOD_MIR_AXIS_Z) + mirrz = true; + + clip_dist = mmd->tolerance; + } + } + } + + for (i = 0; i < repeat; i++) { + if (!EDBM_op_callf( + em, + op, + "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b " + "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b", + BM_ELEM_SELECT, + fac, + mirrx, + mirry, + mirrz, + clip_dist, + xaxis, + yaxis, + zaxis)) { + continue; + } + } + + /* apply mirror */ + if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { + EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0); + EDBM_verts_mirror_cache_end(em); + } + + EDBM_update_generic(em, true, false); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_vertices_smooth(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Smooth Vertices"; - ot->description = "Flatten angles of selected vertices"; - ot->idname = "MESH_OT_vertices_smooth"; + /* identifiers */ + ot->name = "Smooth Vertices"; + ot->description = "Flatten angles of selected vertices"; + ot->idname = "MESH_OT_vertices_smooth"; - /* api callbacks */ - ot->exec = edbm_do_smooth_vertex_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_do_smooth_vertex_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_float_factor(ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f); - RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100); + ot->prop = RNA_def_float_factor( + ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f); + RNA_def_int( + ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100); - WM_operatortype_props_advanced_begin(ot); + WM_operatortype_props_advanced_begin(ot); - RNA_def_boolean(ot->srna, "xaxis", true, "X-Axis", "Smooth along the X axis"); - RNA_def_boolean(ot->srna, "yaxis", true, "Y-Axis", "Smooth along the Y axis"); - RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis"); + RNA_def_boolean(ot->srna, "xaxis", true, "X-Axis", "Smooth along the X axis"); + RNA_def_boolean(ot->srna, "yaxis", true, "Y-Axis", "Smooth along the Y axis"); + RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis"); } /** \} */ @@ -2247,122 +2349,140 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot) static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) { - BMIter fiter; - BMFace *f; - int tot_invalid = 0; - int tot_unselected = 0; - ViewLayer *view_layer = CTX_data_view_layer(C); - - const float lambda_factor = RNA_float_get(op->ptr, "lambda_factor"); - const float lambda_border = RNA_float_get(op->ptr, "lambda_border"); - const bool usex = RNA_boolean_get(op->ptr, "use_x"); - const bool usey = RNA_boolean_get(op->ptr, "use_y"); - const bool usez = RNA_boolean_get(op->ptr, "use_z"); - const bool preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume"); - int repeat = RNA_int_get(op->ptr, "repeat"); - - if (!repeat) { - repeat = 1; - } - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - Mesh *me = obedit->data; - bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - - if (em->bm->totvertsel == 0) { - tot_unselected++; - tot_invalid++; - continue; - } - - bool is_invalid = false; - /* Check if select faces are triangles. */ - BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - if (f->len > 4) { - tot_invalid++; - is_invalid = true; - break; - } - } - } - if (is_invalid) { - continue; - } - - /* Mirror before smooth. */ - if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { - EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology); - } - - bool failed_repeat_loop = false; - for (int i = 0; i < repeat; i++) { - if (!EDBM_op_callf( - em, op, - "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b", - BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume)) - { - failed_repeat_loop = true; - break; - } - } - if (failed_repeat_loop) { - continue; - } - - /* Apply mirror. */ - if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { - EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0); - EDBM_verts_mirror_cache_end(em); - } - - EDBM_update_generic(em, true, false); - } - MEM_freeN(objects); - - if (tot_unselected == objects_len) { - BKE_report(op->reports, RPT_WARNING, "No selected vertex"); - return OPERATOR_CANCELLED; - } - else if (tot_invalid == objects_len) { - BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads"); - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + BMIter fiter; + BMFace *f; + int tot_invalid = 0; + int tot_unselected = 0; + ViewLayer *view_layer = CTX_data_view_layer(C); + + const float lambda_factor = RNA_float_get(op->ptr, "lambda_factor"); + const float lambda_border = RNA_float_get(op->ptr, "lambda_border"); + const bool usex = RNA_boolean_get(op->ptr, "use_x"); + const bool usey = RNA_boolean_get(op->ptr, "use_y"); + const bool usez = RNA_boolean_get(op->ptr, "use_z"); + const bool preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume"); + int repeat = RNA_int_get(op->ptr, "repeat"); + + if (!repeat) { + repeat = 1; + } + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + Mesh *me = obedit->data; + bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + + if (em->bm->totvertsel == 0) { + tot_unselected++; + tot_invalid++; + continue; + } + + bool is_invalid = false; + /* Check if select faces are triangles. */ + BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + if (f->len > 4) { + tot_invalid++; + is_invalid = true; + break; + } + } + } + if (is_invalid) { + continue; + } + + /* Mirror before smooth. */ + if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { + EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology); + } + + bool failed_repeat_loop = false; + for (int i = 0; i < repeat; i++) { + if (!EDBM_op_callf(em, + op, + "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f " + "use_x=%b use_y=%b use_z=%b preserve_volume=%b", + BM_ELEM_SELECT, + lambda_factor, + lambda_border, + usex, + usey, + usez, + preserve_volume)) { + failed_repeat_loop = true; + break; + } + } + if (failed_repeat_loop) { + continue; + } + + /* Apply mirror. */ + if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { + EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0); + EDBM_verts_mirror_cache_end(em); + } + + EDBM_update_generic(em, true, false); + } + MEM_freeN(objects); + + if (tot_unselected == objects_len) { + BKE_report(op->reports, RPT_WARNING, "No selected vertex"); + return OPERATOR_CANCELLED; + } + else if (tot_invalid == objects_len) { + BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Laplacian Smooth Vertices"; - ot->description = "Laplacian smooth of selected vertices"; - ot->idname = "MESH_OT_vertices_smooth_laplacian"; - - /* api callbacks */ - ot->exec = edbm_do_smooth_laplacian_vertex_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_int(ot->srna, "repeat", 1, 1, 1000, - "Number of iterations to smooth the mesh", "", 1, 200); - RNA_def_float(ot->srna, "lambda_factor", 1.0f, 1e-7f, 1000.0f, - "Lambda factor", "", 1e-7f, 1000.0f); - RNA_def_float(ot->srna, "lambda_border", 5e-5f, 1e-7f, 1000.0f, - "Lambda factor in border", "", 1e-7f, 1000.0f); - - WM_operatortype_props_advanced_begin(ot); - - RNA_def_boolean(ot->srna, "use_x", true, "Smooth X Axis", "Smooth object along X axis"); - RNA_def_boolean(ot->srna, "use_y", true, "Smooth Y Axis", "Smooth object along Y axis"); - RNA_def_boolean(ot->srna, "use_z", true, "Smooth Z Axis", "Smooth object along Z axis"); - RNA_def_boolean(ot->srna, "preserve_volume", true, "Preserve Volume", "Apply volume preservation after smooth"); + /* identifiers */ + ot->name = "Laplacian Smooth Vertices"; + ot->description = "Laplacian smooth of selected vertices"; + ot->idname = "MESH_OT_vertices_smooth_laplacian"; + + /* api callbacks */ + ot->exec = edbm_do_smooth_laplacian_vertex_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_int( + ot->srna, "repeat", 1, 1, 1000, "Number of iterations to smooth the mesh", "", 1, 200); + RNA_def_float( + ot->srna, "lambda_factor", 1.0f, 1e-7f, 1000.0f, "Lambda factor", "", 1e-7f, 1000.0f); + RNA_def_float(ot->srna, + "lambda_border", + 5e-5f, + 1e-7f, + 1000.0f, + "Lambda factor in border", + "", + 1e-7f, + 1000.0f); + + WM_operatortype_props_advanced_begin(ot); + + RNA_def_boolean(ot->srna, "use_x", true, "Smooth X Axis", "Smooth object along X axis"); + RNA_def_boolean(ot->srna, "use_y", true, "Smooth Y Axis", "Smooth object along Y axis"); + RNA_def_boolean(ot->srna, "use_z", true, "Smooth Z Axis", "Smooth object along Z axis"); + RNA_def_boolean(ot->srna, + "preserve_volume", + true, + "Preserve Volume", + "Apply volume preservation after smooth"); } /** \} */ @@ -2373,52 +2493,54 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot) static void mesh_set_smooth_faces(BMEditMesh *em, short smooth) { - BMIter iter; - BMFace *efa; + BMIter iter; + BMFace *efa; - if (em == NULL) return; + if (em == NULL) + return; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_elem_flag_set(efa, BM_ELEM_SMOOTH, smooth); - } - } + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_elem_flag_set(efa, BM_ELEM_SMOOTH, smooth); + } + } } static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op)) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - mesh_set_smooth_faces(em, 1); - EDBM_update_generic(em, false, false); - } - MEM_freeN(objects); + mesh_set_smooth_faces(em, 1); + EDBM_update_generic(em, false, false); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_faces_shade_smooth(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Shade Smooth"; - ot->description = "Display faces smooth (using vertex normals)"; - ot->idname = "MESH_OT_faces_shade_smooth"; + /* identifiers */ + ot->name = "Shade Smooth"; + ot->description = "Display faces smooth (using vertex normals)"; + ot->idname = "MESH_OT_faces_shade_smooth"; - /* api callbacks */ - ot->exec = edbm_faces_shade_smooth_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_faces_shade_smooth_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -2429,38 +2551,39 @@ void MESH_OT_faces_shade_smooth(wmOperatorType *ot) static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op)) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - mesh_set_smooth_faces(em, 0); - EDBM_update_generic(em, false, false); - } - MEM_freeN(objects); + mesh_set_smooth_faces(em, 0); + EDBM_update_generic(em, false, false); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_faces_shade_flat(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Shade Flat"; - ot->description = "Display faces flat"; - ot->idname = "MESH_OT_faces_shade_flat"; + /* identifiers */ + ot->name = "Shade Flat"; + ot->description = "Display faces flat"; + ot->idname = "MESH_OT_faces_shade_flat"; - /* api callbacks */ - ot->exec = edbm_faces_shade_flat_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_faces_shade_flat_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -2471,214 +2594,217 @@ void MESH_OT_faces_shade_flat(wmOperatorType *ot) static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op) { - /* get the direction from RNA */ - const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw"); + /* get the direction from RNA */ + const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - BMOperator bmop; + BMOperator bmop; - /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ - EDBM_op_init(em, &bmop, op, "rotate_uvs faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw); + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_op_init(em, &bmop, op, "rotate_uvs faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw); - /* execute the operator */ - BMO_op_exec(em->bm, &bmop); + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - EDBM_update_generic(em, false, false); - } + EDBM_update_generic(em, false, false); + } - MEM_freeN(objects); - return OPERATOR_FINISHED; + MEM_freeN(objects); + return OPERATOR_FINISHED; } static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - BMOperator bmop; + BMOperator bmop; - /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ - EDBM_op_init(em, &bmop, op, "reverse_uvs faces=%hf", BM_ELEM_SELECT); + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_op_init(em, &bmop, op, "reverse_uvs faces=%hf", BM_ELEM_SELECT); - /* execute the operator */ - BMO_op_exec(em->bm, &bmop); + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); - /* finish the operator */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - EDBM_update_generic(em, false, false); - } + /* finish the operator */ + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + EDBM_update_generic(em, false, false); + } - MEM_freeN(objects); - return OPERATOR_FINISHED; + MEM_freeN(objects); + return OPERATOR_FINISHED; } static int edbm_rotate_colors_exec(bContext *C, wmOperator *op) { - /* get the direction from RNA */ - const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw"); + /* get the direction from RNA */ + const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - if (em->bm->totfacesel == 0) { - continue; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + if (em->bm->totfacesel == 0) { + continue; + } - BMOperator bmop; + BMOperator bmop; - /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ - EDBM_op_init(em, &bmop, op, "rotate_colors faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw); + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_op_init(em, &bmop, op, "rotate_colors faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw); - /* execute the operator */ - BMO_op_exec(em->bm, &bmop); + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); - /* finish the operator */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } + /* finish the operator */ + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - /* dependencies graph and notification stuff */ - EDBM_update_generic(em, false, false); - } + /* dependencies graph and notification stuff */ + EDBM_update_generic(em, false, false); + } - MEM_freeN(objects); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } - static int edbm_reverse_colors_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - BMOperator bmop; + BMOperator bmop; - /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ - EDBM_op_init(em, &bmop, op, "reverse_colors faces=%hf", BM_ELEM_SELECT); + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_op_init(em, &bmop, op, "reverse_colors faces=%hf", BM_ELEM_SELECT); - /* execute the operator */ - BMO_op_exec(em->bm, &bmop); + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); - /* finish the operator */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } + /* finish the operator */ + if (!EDBM_op_finish(em, &bmop, op, true)) { + return OPERATOR_CANCELLED; + } - EDBM_update_generic(em, false, false); - } - MEM_freeN(objects); + EDBM_update_generic(em, false, false); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_uvs_rotate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Rotate UVs"; - ot->idname = "MESH_OT_uvs_rotate"; - ot->description = "Rotate UV coordinates inside faces"; + /* identifiers */ + ot->name = "Rotate UVs"; + ot->idname = "MESH_OT_uvs_rotate"; + ot->description = "Rotate UV coordinates inside faces"; - /* api callbacks */ - ot->exec = edbm_rotate_uvs_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_rotate_uvs_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", ""); + /* props */ + RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", ""); } void MESH_OT_uvs_reverse(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Reverse UVs"; - ot->idname = "MESH_OT_uvs_reverse"; - ot->description = "Flip direction of UV coordinates inside faces"; + /* identifiers */ + ot->name = "Reverse UVs"; + ot->idname = "MESH_OT_uvs_reverse"; + ot->description = "Flip direction of UV coordinates inside faces"; - /* api callbacks */ - ot->exec = edbm_reverse_uvs_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_reverse_uvs_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around"); + /* props */ + //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around"); } void MESH_OT_colors_rotate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Rotate Colors"; - ot->idname = "MESH_OT_colors_rotate"; - ot->description = "Rotate vertex colors inside faces"; + /* identifiers */ + ot->name = "Rotate Colors"; + ot->idname = "MESH_OT_colors_rotate"; + ot->description = "Rotate vertex colors inside faces"; - /* api callbacks */ - ot->exec = edbm_rotate_colors_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_rotate_colors_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", ""); + /* props */ + RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", ""); } void MESH_OT_colors_reverse(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Reverse Colors"; - ot->idname = "MESH_OT_colors_reverse"; - ot->description = "Flip direction of vertex colors inside faces"; + /* identifiers */ + ot->name = "Reverse Colors"; + ot->idname = "MESH_OT_colors_reverse"; + ot->description = "Flip direction of vertex colors inside faces"; - /* api callbacks */ - ot->exec = edbm_reverse_colors_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_reverse_colors_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around"); + /* props */ + //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around"); } /** \} */ @@ -2688,238 +2814,251 @@ void MESH_OT_colors_reverse(wmOperatorType *ot) * \{ */ enum { - MESH_MERGE_LAST = 1, - MESH_MERGE_CENTER = 3, - MESH_MERGE_CURSOR = 4, - MESH_MERGE_COLLAPSE = 5, - MESH_MERGE_FIRST = 6, + MESH_MERGE_LAST = 1, + MESH_MERGE_CENTER = 3, + MESH_MERGE_CURSOR = 4, + MESH_MERGE_COLLAPSE = 5, + MESH_MERGE_FIRST = 6, }; -static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use_uvmerge, wmOperator *wmop) -{ - BMVert *mergevert; - BMEditSelection *ese; - - /* operator could be called directly from shortcut or python, - * so do extra check for data here - */ - - /* do sanity check in mergemenu in edit.c ?*/ - if (use_first == false) { - if (!em->bm->selected.last || ((BMEditSelection *)em->bm->selected.last)->htype != BM_VERT) - return false; - - ese = em->bm->selected.last; - mergevert = (BMVert *)ese->ele; - } - else { - if (!em->bm->selected.first || ((BMEditSelection *)em->bm->selected.first)->htype != BM_VERT) - return false; - - ese = em->bm->selected.first; - mergevert = (BMVert *)ese->ele; - } - - if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT)) - return false; - - if (use_uvmerge) { - if (!EDBM_op_callf(em, wmop, "pointmerge_facedata verts=%hv vert_snap=%e", BM_ELEM_SELECT, mergevert)) - return false; - } - - if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, mergevert->co)) - return false; - - return true; -} - -static bool merge_target( - BMEditMesh *em, Scene *scene, Object *ob, - const bool use_cursor, const bool use_uvmerge, wmOperator *wmop) -{ - BMIter iter; - BMVert *v; - float co[3], cent[3] = {0.0f, 0.0f, 0.0f}; - const float *vco = NULL; - - if (use_cursor) { - vco = scene->cursor.location; - copy_v3_v3(co, vco); - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->imat, co); - } - else { - float fac; - int i = 0; - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) - continue; - add_v3_v3(cent, v->co); - i++; - } - - if (!i) - return false; - - fac = 1.0f / (float)i; - mul_v3_fl(cent, fac); - copy_v3_v3(co, cent); - vco = co; - } - - if (!vco) - return false; - - if (use_uvmerge) { - if (!EDBM_op_callf(em, wmop, "average_vert_facedata verts=%hv", BM_ELEM_SELECT)) - return false; - } - - if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, co)) - return false; - - return true; +static bool merge_firstlast(BMEditMesh *em, + const bool use_first, + const bool use_uvmerge, + wmOperator *wmop) +{ + BMVert *mergevert; + BMEditSelection *ese; + + /* operator could be called directly from shortcut or python, + * so do extra check for data here + */ + + /* do sanity check in mergemenu in edit.c ?*/ + if (use_first == false) { + if (!em->bm->selected.last || ((BMEditSelection *)em->bm->selected.last)->htype != BM_VERT) + return false; + + ese = em->bm->selected.last; + mergevert = (BMVert *)ese->ele; + } + else { + if (!em->bm->selected.first || ((BMEditSelection *)em->bm->selected.first)->htype != BM_VERT) + return false; + + ese = em->bm->selected.first; + mergevert = (BMVert *)ese->ele; + } + + if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT)) + return false; + + if (use_uvmerge) { + if (!EDBM_op_callf( + em, wmop, "pointmerge_facedata verts=%hv vert_snap=%e", BM_ELEM_SELECT, mergevert)) + return false; + } + + if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, mergevert->co)) + return false; + + return true; +} + +static bool merge_target(BMEditMesh *em, + Scene *scene, + Object *ob, + const bool use_cursor, + const bool use_uvmerge, + wmOperator *wmop) +{ + BMIter iter; + BMVert *v; + float co[3], cent[3] = {0.0f, 0.0f, 0.0f}; + const float *vco = NULL; + + if (use_cursor) { + vco = scene->cursor.location; + copy_v3_v3(co, vco); + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_v3(ob->imat, co); + } + else { + float fac; + int i = 0; + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) + continue; + add_v3_v3(cent, v->co); + i++; + } + + if (!i) + return false; + + fac = 1.0f / (float)i; + mul_v3_fl(cent, fac); + copy_v3_v3(co, cent); + vco = co; + } + + if (!vco) + return false; + + if (use_uvmerge) { + if (!EDBM_op_callf(em, wmop, "average_vert_facedata verts=%hv", BM_ELEM_SELECT)) + return false; + } + + if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, co)) + return false; + + return true; } static int edbm_merge_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - const int type = RNA_enum_get(op->ptr, "type"); - const bool uvs = RNA_boolean_get(op->ptr, "uvs"); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totvertsel == 0) { - continue; - } - - bool ok = false; - switch (type) { - case MESH_MERGE_CENTER: - ok = merge_target(em, scene, obedit, false, uvs, op); - break; - case MESH_MERGE_CURSOR: - ok = merge_target(em, scene, obedit, true, uvs, op); - break; - case MESH_MERGE_LAST: - ok = merge_firstlast(em, false, uvs, op); - break; - case MESH_MERGE_FIRST: - ok = merge_firstlast(em, true, uvs, op); - break; - case MESH_MERGE_COLLAPSE: - ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs); - break; - default: - BLI_assert(0); - break; - } - - if (!ok) { - continue; - } - - EDBM_update_generic(em, true, true); - - /* once collapsed, we can't have edge/face selection */ - if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - } - /* Only active object supported, see comment below. */ - if (ELEM(type, MESH_MERGE_FIRST, MESH_MERGE_LAST)) { - break; - } - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + const int type = RNA_enum_get(op->ptr, "type"); + const bool uvs = RNA_boolean_get(op->ptr, "uvs"); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totvertsel == 0) { + continue; + } + + bool ok = false; + switch (type) { + case MESH_MERGE_CENTER: + ok = merge_target(em, scene, obedit, false, uvs, op); + break; + case MESH_MERGE_CURSOR: + ok = merge_target(em, scene, obedit, true, uvs, op); + break; + case MESH_MERGE_LAST: + ok = merge_firstlast(em, false, uvs, op); + break; + case MESH_MERGE_FIRST: + ok = merge_firstlast(em, true, uvs, op); + break; + case MESH_MERGE_COLLAPSE: + ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs); + break; + default: + BLI_assert(0); + break; + } + + if (!ok) { + continue; + } + + EDBM_update_generic(em, true, true); + + /* once collapsed, we can't have edge/face selection */ + if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } + /* Only active object supported, see comment below. */ + if (ELEM(type, MESH_MERGE_FIRST, MESH_MERGE_LAST)) { + break; + } + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } static const EnumPropertyItem merge_type_items[] = { - {MESH_MERGE_FIRST, "FIRST", 0, "At First", ""}, - {MESH_MERGE_LAST, "LAST", 0, "At Last", ""}, - {MESH_MERGE_CENTER, "CENTER", 0, "At Center", ""}, - {MESH_MERGE_CURSOR, "CURSOR", 0, "At Cursor", ""}, - {MESH_MERGE_COLLAPSE, "COLLAPSE", 0, "Collapse", ""}, - {0, NULL, 0, NULL, NULL}, + {MESH_MERGE_FIRST, "FIRST", 0, "At First", ""}, + {MESH_MERGE_LAST, "LAST", 0, "At Last", ""}, + {MESH_MERGE_CENTER, "CENTER", 0, "At Center", ""}, + {MESH_MERGE_CURSOR, "CURSOR", 0, "At Cursor", ""}, + {MESH_MERGE_COLLAPSE, "COLLAPSE", 0, "Collapse", ""}, + {0, NULL, 0, NULL, NULL}, }; -static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - Object *obedit; - EnumPropertyItem *item = NULL; - int totitem = 0; - - if (!C) /* needed for docs */ - return merge_type_items; - - obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_MESH) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - /* Only active object supported: - * In practice it doesn't make sense to run this operation on non-active meshes - * since selecting will activate - we could have own code-path for these but it's a hassle - * for now just apply to the active (first) object. */ - if (em->selectmode & SCE_SELECT_VERTEX) { - if (em->bm->selected.first && em->bm->selected.last && - ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT && - ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) - { - RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST); - RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST); - } - else if (em->bm->selected.first && ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) { - RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST); - } - else if (em->bm->selected.last && ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) { - RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST); - } - } - - RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CENTER); - RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CURSOR); - RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_COLLAPSE); - RNA_enum_item_end(&item, &totitem); - - *r_free = true; - - return item; - } - - /* Get all items e.g. when creating keymap item. */ - return merge_type_items; +static const EnumPropertyItem *merge_type_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + Object *obedit; + EnumPropertyItem *item = NULL; + int totitem = 0; + + if (!C) /* needed for docs */ + return merge_type_items; + + obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + /* Only active object supported: + * In practice it doesn't make sense to run this operation on non-active meshes + * since selecting will activate - we could have own code-path for these but it's a hassle + * for now just apply to the active (first) object. */ + if (em->selectmode & SCE_SELECT_VERTEX) { + if (em->bm->selected.first && em->bm->selected.last && + ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT && + ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) { + RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST); + RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST); + } + else if (em->bm->selected.first && + ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) { + RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST); + } + else if (em->bm->selected.last && + ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) { + RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST); + } + } + + RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CENTER); + RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CURSOR); + RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_COLLAPSE); + RNA_enum_item_end(&item, &totitem); + + *r_free = true; + + return item; + } + + /* Get all items e.g. when creating keymap item. */ + return merge_type_items; } void MESH_OT_merge(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Merge"; - ot->description = "Merge selected vertices"; - ot->idname = "MESH_OT_merge"; + /* identifiers */ + ot->name = "Merge"; + ot->description = "Merge selected vertices"; + ot->idname = "MESH_OT_merge"; - /* api callbacks */ - ot->exec = edbm_merge_exec; - ot->invoke = WM_menu_invoke; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_merge_exec; + ot->invoke = WM_menu_invoke; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, MESH_MERGE_CENTER, "Type", "Merge method to use"); - RNA_def_enum_funcs(ot->prop, merge_type_itemf); + /* properties */ + ot->prop = RNA_def_enum( + ot->srna, "type", merge_type_items, MESH_MERGE_CENTER, "Type", "Merge method to use"); + RNA_def_enum_funcs(ot->prop, merge_type_itemf); - WM_operatortype_props_advanced_begin(ot); + WM_operatortype_props_advanced_begin(ot); - RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge"); + RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge"); } /** \} */ @@ -2930,100 +3069,108 @@ void MESH_OT_merge(wmOperatorType *ot) static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) { - const float threshold = RNA_float_get(op->ptr, "threshold"); - const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected"); - int count_multi = 0; + const float threshold = RNA_float_get(op->ptr, "threshold"); + const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected"); + int count_multi = 0; - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* Selection used as target with 'use_unselected'. */ - if (em->bm->totvertsel == 0) { - continue; - } + /* Selection used as target with 'use_unselected'. */ + if (em->bm->totvertsel == 0) { + continue; + } - BMOperator bmop; - const int totvert_orig = em->bm->totvert; + BMOperator bmop; + const int totvert_orig = em->bm->totvert; - /* avoid losing selection state (select -> tags) */ - char htype_select; - if (em->selectmode & SCE_SELECT_VERTEX) htype_select = BM_VERT; - else if (em->selectmode & SCE_SELECT_EDGE) htype_select = BM_EDGE; - else htype_select = BM_FACE; + /* avoid losing selection state (select -> tags) */ + char htype_select; + if (em->selectmode & SCE_SELECT_VERTEX) + htype_select = BM_VERT; + else if (em->selectmode & SCE_SELECT_EDGE) + htype_select = BM_EDGE; + else + htype_select = BM_FACE; - /* store selection as tags */ - BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT); + /* store selection as tags */ + 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 (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; + } + } + else { + EDBM_op_init(em, &bmop, op, "find_doubles verts=%hv dist=%f", BM_ELEM_SELECT, threshold); - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - } - else { - EDBM_op_init( - em, &bmop, op, - "find_doubles verts=%hv dist=%f", - BM_ELEM_SELECT, threshold); + BMO_op_exec(em->bm, &bmop); - BMO_op_exec(em->bm, &bmop); + if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) { + BMO_op_finish(em->bm, &bmop); + continue; + } - if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) { - BMO_op_finish(em->bm, &bmop); - continue; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + } - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - } + const int count = (totvert_orig - em->bm->totvert); - const int count = (totvert_orig - em->bm->totvert); + /* restore selection from tags */ + BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_SELECT, true, true, BM_ELEM_TAG); + EDBM_selectmode_flush(em); - /* restore selection from tags */ - BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_SELECT, true, true, BM_ELEM_TAG); - EDBM_selectmode_flush(em); + if (count) { + count_multi += count; + EDBM_update_generic(em, true, true); + } + } + MEM_freeN(objects); - if (count) { - count_multi += count; - EDBM_update_generic(em, true, true); - } - } - MEM_freeN(objects); + BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count_multi); - BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count_multi); - - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_remove_doubles(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Doubles"; - ot->description = "Remove duplicate vertices"; - ot->idname = "MESH_OT_remove_doubles"; - - /* api callbacks */ - ot->exec = edbm_remove_doubles_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_float_distance(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance", - "Minimum distance between elements to merge", 1e-5f, 10.0f); - RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices"); + /* identifiers */ + ot->name = "Remove Doubles"; + ot->description = "Remove duplicate vertices"; + ot->idname = "MESH_OT_remove_doubles"; + + /* api callbacks */ + ot->exec = edbm_remove_doubles_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_float_distance(ot->srna, + "threshold", + 1e-4f, + 1e-6f, + 50.0f, + "Merge Distance", + "Minimum distance between elements to merge", + 1e-5f, + 10.0f); + RNA_def_boolean(ot->srna, + "use_unselected", + false, + "Unselected", + "Merge selected to other unselected vertices"); } /** \} */ @@ -3035,85 +3182,83 @@ void MESH_OT_remove_doubles(wmOperatorType *ot) /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/ static bool shape_propagate(BMEditMesh *em) { - BMIter iter; - BMVert *eve = NULL; - float *co; - int totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY); + BMIter iter; + BMVert *eve = NULL; + float *co; + int totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY); - if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) { - return false; - } + if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) { + return false; + } - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - continue; - } + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + continue; + } - for (int i = 0; i < totshape; i++) { - co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i); - copy_v3_v3(co, eve->co); - } - } - return true; + for (int i = 0; i < totshape; i++) { + co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i); + copy_v3_v3(co, eve->co); + } + } + return true; } static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - int tot_shapekeys = 0; - int tot_selected_verts_objects = 0; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - Mesh *me = obedit->data; - BMEditMesh *em = me->edit_mesh; - - if (em->bm->totvertsel == 0) { - continue; - } - tot_selected_verts_objects++; - - if (shape_propagate(em)) { - tot_shapekeys++; - } - - EDBM_update_generic(em, false, false); - } - MEM_freeN(objects); - - if (tot_selected_verts_objects == 0) { - BKE_report(op->reports, RPT_ERROR, "No selected vertex"); - return OPERATOR_CANCELLED; - } - else if (tot_shapekeys == 0) { - BKE_report( - op->reports, - RPT_ERROR, - objects_len > 1 ? - "Meshes do not have shape keys" : - "Mesh does not have shape keys"); - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + int tot_shapekeys = 0; + int tot_selected_verts_objects = 0; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + Mesh *me = obedit->data; + BMEditMesh *em = me->edit_mesh; + + if (em->bm->totvertsel == 0) { + continue; + } + tot_selected_verts_objects++; + + if (shape_propagate(em)) { + tot_shapekeys++; + } + + EDBM_update_generic(em, false, false); + } + MEM_freeN(objects); + + if (tot_selected_verts_objects == 0) { + BKE_report(op->reports, RPT_ERROR, "No selected vertex"); + return OPERATOR_CANCELLED; + } + else if (tot_shapekeys == 0) { + BKE_report(op->reports, + RPT_ERROR, + objects_len > 1 ? "Meshes do not have shape keys" : + "Mesh does not have shape keys"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } - void MESH_OT_shape_propagate_to_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Shape Propagate"; - ot->description = "Apply selected vertex locations to all other shape keys"; - ot->idname = "MESH_OT_shape_propagate_to_all"; + /* identifiers */ + ot->name = "Shape Propagate"; + ot->description = "Apply selected vertex locations to all other shape keys"; + ot->idname = "MESH_OT_shape_propagate_to_all"; - /* api callbacks */ - ot->exec = edbm_shape_propagate_to_all_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_shape_propagate_to_all_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -3125,171 +3270,175 @@ void MESH_OT_shape_propagate_to_all(wmOperatorType *ot) /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op) { - Object *obedit_ref = CTX_data_edit_object(C); - Mesh *me_ref = obedit_ref->data; - Key *key_ref = me_ref->key; - KeyBlock *kb_ref = NULL; - BMEditMesh *em_ref = me_ref->edit_mesh; - BMVert *eve; - BMIter iter; - ViewLayer *view_layer = CTX_data_view_layer(C); - float co[3], *sco; - int totshape_ref = 0; - - const float blend = RNA_float_get(op->ptr, "blend"); - int shape_ref = RNA_enum_get(op->ptr, "shape"); - const bool use_add = RNA_boolean_get(op->ptr, "add"); - - /* Sanity check. */ - totshape_ref = CustomData_number_of_layers(&em_ref->bm->vdata, CD_SHAPEKEY); - - if (totshape_ref == 0 || shape_ref < 0) { - BKE_report(op->reports, RPT_ERROR, "Active mesh does not have shape keys"); - return OPERATOR_CANCELLED; - } - else if (shape_ref >= totshape_ref) { - /* This case occurs if operator was used before on object with more keys than current one. */ - shape_ref = 0; /* default to basis */ - } - - /* Get shape key - needed for finding reference shape (for add mode only). */ - if (key_ref) { - kb_ref = BLI_findlink(&key_ref->block, shape_ref); - } - - int tot_selected_verts_objects = 0; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - Mesh *me = obedit->data; - Key *key = me->key; - KeyBlock *kb = NULL; - BMEditMesh *em = me->edit_mesh; - int shape; - - if (em->bm->totvertsel == 0) { - continue; - } - tot_selected_verts_objects++; - - if (!key) { - continue; - } - else { - kb = BKE_keyblock_find_name(key, kb_ref->name); - shape = BLI_findindex(&key->block, kb); - } - - if (kb) { - /* Perform blending on selected vertices. */ - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) - continue; - - /* Get coordinates of shapekey we're blending from. */ - sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape); - copy_v3_v3(co, sco); - - if (use_add) { - /* In add mode, we add relative shape key offset. */ - if (kb) { - const float *rco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative); - sub_v3_v3v3(co, co, rco); - } - - madd_v3_v3fl(eve->co, co, blend); - } - else { - /* In blend mode, we interpolate to the shape key. */ - interp_v3_v3v3(eve->co, eve->co, co, blend); - } - } - EDBM_update_generic(em, true, false); - } - } - MEM_freeN(objects); - - if (tot_selected_verts_objects == 0) { - BKE_report(op->reports, RPT_ERROR, "No selected vertex"); - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; -} - -static const EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em; - EnumPropertyItem *item = NULL; - int totitem = 0; - - if ((obedit && obedit->type == OB_MESH) && - (em = BKE_editmesh_from_object(obedit)) && - CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) - { - EnumPropertyItem tmp = {0, "", 0, "", ""}; - int a; - - for (a = 0; a < em->bm->vdata.totlayer; a++) { - if (em->bm->vdata.layers[a].type != CD_SHAPEKEY) - continue; - - tmp.value = totitem; - tmp.identifier = em->bm->vdata.layers[a].name; - tmp.name = em->bm->vdata.layers[a].name; - /* RNA_enum_item_add sets totitem itself! */ - RNA_enum_item_add(&item, &totitem, &tmp); - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + Object *obedit_ref = CTX_data_edit_object(C); + Mesh *me_ref = obedit_ref->data; + Key *key_ref = me_ref->key; + KeyBlock *kb_ref = NULL; + BMEditMesh *em_ref = me_ref->edit_mesh; + BMVert *eve; + BMIter iter; + ViewLayer *view_layer = CTX_data_view_layer(C); + float co[3], *sco; + int totshape_ref = 0; + + const float blend = RNA_float_get(op->ptr, "blend"); + int shape_ref = RNA_enum_get(op->ptr, "shape"); + const bool use_add = RNA_boolean_get(op->ptr, "add"); + + /* Sanity check. */ + totshape_ref = CustomData_number_of_layers(&em_ref->bm->vdata, CD_SHAPEKEY); + + if (totshape_ref == 0 || shape_ref < 0) { + BKE_report(op->reports, RPT_ERROR, "Active mesh does not have shape keys"); + return OPERATOR_CANCELLED; + } + else if (shape_ref >= totshape_ref) { + /* This case occurs if operator was used before on object with more keys than current one. */ + shape_ref = 0; /* default to basis */ + } + + /* Get shape key - needed for finding reference shape (for add mode only). */ + if (key_ref) { + kb_ref = BLI_findlink(&key_ref->block, shape_ref); + } + + int tot_selected_verts_objects = 0; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + Mesh *me = obedit->data; + Key *key = me->key; + KeyBlock *kb = NULL; + BMEditMesh *em = me->edit_mesh; + int shape; + + if (em->bm->totvertsel == 0) { + continue; + } + tot_selected_verts_objects++; + + if (!key) { + continue; + } + else { + kb = BKE_keyblock_find_name(key, kb_ref->name); + shape = BLI_findindex(&key->block, kb); + } + + if (kb) { + /* Perform blending on selected vertices. */ + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) + continue; + + /* Get coordinates of shapekey we're blending from. */ + sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape); + copy_v3_v3(co, sco); + + if (use_add) { + /* In add mode, we add relative shape key offset. */ + if (kb) { + const float *rco = CustomData_bmesh_get_n( + &em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative); + sub_v3_v3v3(co, co, rco); + } + + madd_v3_v3fl(eve->co, co, blend); + } + else { + /* In blend mode, we interpolate to the shape key. */ + interp_v3_v3v3(eve->co, eve->co, co, blend); + } + } + EDBM_update_generic(em, true, false); + } + } + MEM_freeN(objects); + + if (tot_selected_verts_objects == 0) { + BKE_report(op->reports, RPT_ERROR, "No selected vertex"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +static const EnumPropertyItem *shape_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em; + EnumPropertyItem *item = NULL; + int totitem = 0; + + if ((obedit && obedit->type == OB_MESH) && (em = BKE_editmesh_from_object(obedit)) && + CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) { + EnumPropertyItem tmp = {0, "", 0, "", ""}; + int a; + + for (a = 0; a < em->bm->vdata.totlayer; a++) { + if (em->bm->vdata.layers[a].type != CD_SHAPEKEY) + continue; + + tmp.value = totitem; + tmp.identifier = em->bm->vdata.layers[a].name; + tmp.name = em->bm->vdata.layers[a].name; + /* RNA_enum_item_add sets totitem itself! */ + RNA_enum_item_add(&item, &totitem, &tmp); + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } static void edbm_blend_from_shape_ui(bContext *C, wmOperator *op) { - uiLayout *layout = op->layout; - PointerRNA ptr; - Object *obedit = CTX_data_edit_object(C); - Mesh *me = obedit->data; - PointerRNA ptr_key; + uiLayout *layout = op->layout; + PointerRNA ptr; + Object *obedit = CTX_data_edit_object(C); + Mesh *me = obedit->data; + PointerRNA ptr_key; - RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); - RNA_id_pointer_create((ID *)me->key, &ptr_key); + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + RNA_id_pointer_create((ID *)me->key, &ptr_key); - uiItemPointerR(layout, &ptr, "shape", &ptr_key, "key_blocks", "", ICON_SHAPEKEY_DATA); - uiItemR(layout, &ptr, "blend", 0, NULL, ICON_NONE); - uiItemR(layout, &ptr, "add", 0, NULL, ICON_NONE); + uiItemPointerR(layout, &ptr, "shape", &ptr_key, "key_blocks", "", ICON_SHAPEKEY_DATA); + uiItemR(layout, &ptr, "blend", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "add", 0, NULL, ICON_NONE); } void MESH_OT_blend_from_shape(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Blend From Shape"; - ot->description = "Blend in shape from a shape key"; - ot->idname = "MESH_OT_blend_from_shape"; + /* identifiers */ + ot->name = "Blend From Shape"; + ot->description = "Blend in shape from a shape key"; + ot->idname = "MESH_OT_blend_from_shape"; - /* api callbacks */ - ot->exec = edbm_blend_from_shape_exec; -// ot->invoke = WM_operator_props_popup_call; /* disable because search popup closes too easily */ - ot->ui = edbm_blend_from_shape_ui; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_blend_from_shape_exec; + // ot->invoke = WM_operator_props_popup_call; /* disable because search popup closes too easily */ + ot->ui = edbm_blend_from_shape_ui; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - prop = RNA_def_enum(ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending"); - RNA_def_enum_funcs(prop, shape_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_NEVER_UNLINK); - RNA_def_float(ot->srna, "blend", 1.0f, -1e3f, 1e3f, "Blend", "Blending factor", -2.0f, 2.0f); - RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes"); + /* properties */ + prop = RNA_def_enum( + ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending"); + RNA_def_enum_funcs(prop, shape_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_NEVER_UNLINK); + RNA_def_float(ot->srna, "blend", 1.0f, -1e3f, 1e3f, "Blend", "Blending factor", -2.0f, 2.0f); + RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes"); } /** \} */ @@ -3300,65 +3449,68 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot) static int edbm_solidify_exec(bContext *C, wmOperator *op) { - const float thickness = RNA_float_get(op->ptr, "thickness"); + const float thickness = RNA_float_get(op->ptr, "thickness"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - BMOperator bmop; + BMOperator bmop; - if (!EDBM_op_init(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) { - continue; - } + if (!EDBM_op_init( + em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) { + continue; + } - /* deselect only the faces in the region to be solidified (leave wire - * edges and loose verts selected, as there will be no corresponding - * geometry selected below) */ - BMO_slot_buffer_hflag_disable(bm, bmop.slots_in, "geom", BM_FACE, BM_ELEM_SELECT, true); + /* deselect only the faces in the region to be solidified (leave wire + * edges and loose verts selected, as there will be no corresponding + * geometry selected below) */ + BMO_slot_buffer_hflag_disable(bm, bmop.slots_in, "geom", BM_FACE, BM_ELEM_SELECT, true); - /* run the solidify operator */ - BMO_op_exec(bm, &bmop); + /* run the solidify operator */ + BMO_op_exec(bm, &bmop); - /* select the newly generated faces */ - BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); + /* select the newly generated faces */ + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - EDBM_update_generic(em, true, true); - } + EDBM_update_generic(em, true, true); + } - MEM_freeN(objects); - return OPERATOR_FINISHED; + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_solidify(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ - ot->name = "Solidify"; - ot->description = "Create a solid skin by extruding, compensating for sharp angles"; - ot->idname = "MESH_OT_solidify"; + PropertyRNA *prop; + /* identifiers */ + ot->name = "Solidify"; + ot->description = "Create a solid skin by extruding, compensating for sharp angles"; + ot->idname = "MESH_OT_solidify"; - /* api callbacks */ - ot->exec = edbm_solidify_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_solidify_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f); - RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4); + prop = RNA_def_float_distance( + ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f); + RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4); } /** \} */ @@ -3367,322 +3519,328 @@ void MESH_OT_solidify(wmOperatorType *ot) /** \name Knife Subdivide Operator * \{ */ -#define KNIFE_EXACT 1 -#define KNIFE_MIDPOINT 2 -#define KNIFE_MULTICUT 3 +#define KNIFE_EXACT 1 +#define KNIFE_MIDPOINT 2 +#define KNIFE_MULTICUT 3 static const EnumPropertyItem knife_items[] = { - {KNIFE_EXACT, "EXACT", 0, "Exact", ""}, - {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""}, - {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""}, - {0, NULL, 0, NULL, NULL}, + {KNIFE_EXACT, "EXACT", 0, "Exact", ""}, + {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""}, + {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""}, + {0, NULL, 0, NULL, NULL}, }; /* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */ -static float bm_edge_seg_isect( - const float sco_a[2], const float sco_b[2], - float (*mouse_path)[2], int len, char mode, int *isected) +static float bm_edge_seg_isect(const float sco_a[2], + const float sco_b[2], + float (*mouse_path)[2], + int len, + char mode, + int *isected) { #define MAXSLOPE 100000 - float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max; - float y2min, dist, lastdist = 0, xdiff2, xdiff1; - float m1, b1, m2, b2, x21, x22, y21, y22, xi; - float yi, x1min, x1max, y1max, y1min, perc = 0; - float threshold = 0.0; - int i; - - //threshold = 0.000001; /* tolerance for vertex intersection */ - // XXX threshold = scene->toolsettings->select_thresh / 100; - - /* Get screen coords of verts */ - x21 = sco_a[0]; - y21 = sco_a[1]; - - x22 = sco_b[0]; - y22 = sco_b[1]; - - xdiff2 = (x22 - x21); - if (xdiff2) { - m2 = (y22 - y21) / xdiff2; - b2 = ((x22 * y21) - (x21 * y22)) / xdiff2; - } - else { - m2 = MAXSLOPE; /* Vertical slope */ - b2 = x22; - } - - *isected = 0; - - /* check for _exact_ vertex intersection first */ - if (mode != KNIFE_MULTICUT) { - for (i = 0; i < len; i++) { - if (i > 0) { - x11 = x12; - y11 = y12; - } - else { - x11 = mouse_path[i][0]; - y11 = mouse_path[i][1]; - } - x12 = mouse_path[i][0]; - y12 = mouse_path[i][1]; - - /* test e->v1 */ - if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) { - perc = 0; - *isected = 1; - return perc; - } - /* test e->v2 */ - else if ((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)) { - perc = 0; - *isected = 2; - return perc; - } - } - } - - /* now check for edge intersect (may produce vertex intersection as well) */ - for (i = 0; i < len; i++) { - if (i > 0) { - x11 = x12; - y11 = y12; - } - else { - x11 = mouse_path[i][0]; - y11 = mouse_path[i][1]; - } - x12 = mouse_path[i][0]; - y12 = mouse_path[i][1]; - - /* Perp. Distance from point to line */ - if (m2 != MAXSLOPE) { - /* sqrt(m2 * m2 + 1); Only looking for change in sign. Skip extra math .*/ - dist = (y12 - m2 * x12 - b2); - } - else dist = x22 - x12; - - if (i == 0) lastdist = dist; - - /* if dist changes sign, and intersect point in edge's Bound Box */ - if ((lastdist * dist) <= 0) { - xdiff1 = (x12 - x11); /* Equation of line between last 2 points */ - if (xdiff1) { - m1 = (y12 - y11) / xdiff1; - b1 = ((x12 * y11) - (x11 * y12)) / xdiff1; - } - else { - m1 = MAXSLOPE; - b1 = x12; - } - x2max = max_ff(x21, x22) + 0.001f; /* prevent missed edges */ - x2min = min_ff(x21, x22) - 0.001f; /* due to round off error */ - y2max = max_ff(y21, y22) + 0.001f; - y2min = min_ff(y21, y22) - 0.001f; - - /* Found an intersect, calc intersect point */ - if (m1 == m2) { /* co-incident lines */ - /* cut at 50% of overlap area */ - x1max = max_ff(x11, x12); - x1min = min_ff(x11, x12); - xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f; - - y1max = max_ff(y11, y12); - y1min = min_ff(y11, y12); - yi = (min_ff(y2max, y1max) + max_ff(y2min, y1min)) / 2.0f; - } - else if (m2 == MAXSLOPE) { - xi = x22; - yi = m1 * x22 + b1; - } - else if (m1 == MAXSLOPE) { - xi = x12; - yi = m2 * x12 + b2; - } - else { - xi = (b1 - b2) / (m2 - m1); - yi = (b1 * m2 - m1 * b2) / (m2 - m1); - } - - /* Intersect inside bounding box of edge?*/ - if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) { - /* test for vertex intersect that may be 'close enough'*/ - if (mode != KNIFE_MULTICUT) { - if (xi <= (x21 + threshold) && xi >= (x21 - threshold)) { - if (yi <= (y21 + threshold) && yi >= (y21 - threshold)) { - *isected = 1; - perc = 0; - break; - } - } - if (xi <= (x22 + threshold) && xi >= (x22 - threshold)) { - if (yi <= (y22 + threshold) && yi >= (y22 - threshold)) { - *isected = 2; - perc = 0; - break; - } - } - } - if ((m2 <= 1.0f) && (m2 >= -1.0f)) perc = (xi - x21) / (x22 - x21); - else perc = (yi - y21) / (y22 - y21); /* lower slope more accurate */ - //isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */ - - break; - } - } - lastdist = dist; - } - return perc; + float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max; + float y2min, dist, lastdist = 0, xdiff2, xdiff1; + float m1, b1, m2, b2, x21, x22, y21, y22, xi; + float yi, x1min, x1max, y1max, y1min, perc = 0; + float threshold = 0.0; + int i; + + //threshold = 0.000001; /* tolerance for vertex intersection */ + // XXX threshold = scene->toolsettings->select_thresh / 100; + + /* Get screen coords of verts */ + x21 = sco_a[0]; + y21 = sco_a[1]; + + x22 = sco_b[0]; + y22 = sco_b[1]; + + xdiff2 = (x22 - x21); + if (xdiff2) { + m2 = (y22 - y21) / xdiff2; + b2 = ((x22 * y21) - (x21 * y22)) / xdiff2; + } + else { + m2 = MAXSLOPE; /* Vertical slope */ + b2 = x22; + } + + *isected = 0; + + /* check for _exact_ vertex intersection first */ + if (mode != KNIFE_MULTICUT) { + for (i = 0; i < len; i++) { + if (i > 0) { + x11 = x12; + y11 = y12; + } + else { + x11 = mouse_path[i][0]; + y11 = mouse_path[i][1]; + } + x12 = mouse_path[i][0]; + y12 = mouse_path[i][1]; + + /* test e->v1 */ + if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) { + perc = 0; + *isected = 1; + return perc; + } + /* test e->v2 */ + else if ((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)) { + perc = 0; + *isected = 2; + return perc; + } + } + } + + /* now check for edge intersect (may produce vertex intersection as well) */ + for (i = 0; i < len; i++) { + if (i > 0) { + x11 = x12; + y11 = y12; + } + else { + x11 = mouse_path[i][0]; + y11 = mouse_path[i][1]; + } + x12 = mouse_path[i][0]; + y12 = mouse_path[i][1]; + + /* Perp. Distance from point to line */ + if (m2 != MAXSLOPE) { + /* sqrt(m2 * m2 + 1); Only looking for change in sign. Skip extra math .*/ + dist = (y12 - m2 * x12 - b2); + } + else + dist = x22 - x12; + + if (i == 0) + lastdist = dist; + + /* if dist changes sign, and intersect point in edge's Bound Box */ + if ((lastdist * dist) <= 0) { + xdiff1 = (x12 - x11); /* Equation of line between last 2 points */ + if (xdiff1) { + m1 = (y12 - y11) / xdiff1; + b1 = ((x12 * y11) - (x11 * y12)) / xdiff1; + } + else { + m1 = MAXSLOPE; + b1 = x12; + } + x2max = max_ff(x21, x22) + 0.001f; /* prevent missed edges */ + x2min = min_ff(x21, x22) - 0.001f; /* due to round off error */ + y2max = max_ff(y21, y22) + 0.001f; + y2min = min_ff(y21, y22) - 0.001f; + + /* Found an intersect, calc intersect point */ + if (m1 == m2) { /* co-incident lines */ + /* cut at 50% of overlap area */ + x1max = max_ff(x11, x12); + x1min = min_ff(x11, x12); + xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f; + + y1max = max_ff(y11, y12); + y1min = min_ff(y11, y12); + yi = (min_ff(y2max, y1max) + max_ff(y2min, y1min)) / 2.0f; + } + else if (m2 == MAXSLOPE) { + xi = x22; + yi = m1 * x22 + b1; + } + else if (m1 == MAXSLOPE) { + xi = x12; + yi = m2 * x12 + b2; + } + else { + xi = (b1 - b2) / (m2 - m1); + yi = (b1 * m2 - m1 * b2) / (m2 - m1); + } + + /* Intersect inside bounding box of edge?*/ + if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) { + /* test for vertex intersect that may be 'close enough'*/ + if (mode != KNIFE_MULTICUT) { + if (xi <= (x21 + threshold) && xi >= (x21 - threshold)) { + if (yi <= (y21 + threshold) && yi >= (y21 - threshold)) { + *isected = 1; + perc = 0; + break; + } + } + if (xi <= (x22 + threshold) && xi >= (x22 - threshold)) { + if (yi <= (y22 + threshold) && yi >= (y22 - threshold)) { + *isected = 2; + perc = 0; + break; + } + } + } + if ((m2 <= 1.0f) && (m2 >= -1.0f)) + perc = (xi - x21) / (x22 - x21); + else + perc = (yi - y21) / (y22 - y21); /* lower slope more accurate */ + //isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */ + + break; + } + } + lastdist = dist; + } + return perc; } #define ELE_EDGE_CUT 1 static int edbm_knife_cut_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - ARegion *ar = CTX_wm_region(C); - BMVert *bv; - BMIter iter; - BMEdge *be; - BMOperator bmop; - float isect = 0.0f; - int len = 0, isected, i; - short numcuts = 1; - const short mode = RNA_int_get(op->ptr, "type"); - BMOpSlot *slot_edge_percents; - - /* allocd vars */ - float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2]; - - /* edit-object needed for matrix, and ar->regiondata for projections to work */ - if (ELEM(NULL, obedit, ar, ar->regiondata)) - return OPERATOR_CANCELLED; - - if (bm->totvertsel < 2) { - BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on"); - return OPERATOR_CANCELLED; - } - - len = RNA_collection_length(op->ptr, "path"); - - if (len < 2) { - BKE_report(op->reports, RPT_ERROR, "Mouse path too short"); - return OPERATOR_CANCELLED; - } + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + ARegion *ar = CTX_wm_region(C); + BMVert *bv; + BMIter iter; + BMEdge *be; + BMOperator bmop; + float isect = 0.0f; + int len = 0, isected, i; + short numcuts = 1; + const short mode = RNA_int_get(op->ptr, "type"); + BMOpSlot *slot_edge_percents; + + /* allocd vars */ + float(*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2]; + + /* edit-object needed for matrix, and ar->regiondata for projections to work */ + if (ELEM(NULL, obedit, ar, ar->regiondata)) + return OPERATOR_CANCELLED; + + if (bm->totvertsel < 2) { + BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on"); + return OPERATOR_CANCELLED; + } + + len = RNA_collection_length(op->ptr, "path"); + + if (len < 2) { + BKE_report(op->reports, RPT_ERROR, "Mouse path too short"); + return OPERATOR_CANCELLED; + } + + mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__); + + /* get the cut curve */ + RNA_BEGIN (op->ptr, itemptr, "path") { + RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]); + } + RNA_END; + + /* for ED_view3d_project_float_object */ + ED_view3d_init_mats_rv3d(obedit, ar->regiondata); + + /* TODO, investigate using index lookup for screen_vert_coords() rather then a hash table */ + + /* the floating point coordinates of verts in screen space will be + * stored in a hash table according to the vertices pointer */ + screen_vert_coords = sco = MEM_mallocN(bm->totvert * sizeof(float) * 2, __func__); + + BM_ITER_MESH_INDEX (bv, &iter, bm, BM_VERTS_OF_MESH, i) { + if (ED_view3d_project_float_object(ar, bv->co, *sco, V3D_PROJ_TEST_CLIP_NEAR) != + V3D_PROJ_RET_OK) { + copy_v2_fl(*sco, FLT_MAX); /* set error value */ + } + BM_elem_index_set(bv, i); /* set_inline */ + sco++; + } + bm->elem_index_dirty &= ~BM_VERT; /* clear dirty flag */ + + if (!EDBM_op_init(em, &bmop, op, "subdivide_edges")) { + MEM_freeN(mouse_path); + MEM_freeN(screen_vert_coords); + return OPERATOR_CANCELLED; + } + + /* store percentage of edge cut for KNIFE_EXACT here.*/ + slot_edge_percents = BMO_slot_get(bmop.slots_in, "edge_percents"); + BM_ITER_MESH (be, &iter, bm, BM_EDGES_OF_MESH) { + bool is_cut = false; + if (BM_elem_flag_test(be, BM_ELEM_SELECT)) { + const float *sco_a = screen_vert_coords[BM_elem_index_get(be->v1)]; + const float *sco_b = screen_vert_coords[BM_elem_index_get(be->v2)]; + + /* check for error value (vert cant be projected) */ + if ((sco_a[0] != FLT_MAX) && (sco_b[0] != FLT_MAX)) { + isect = bm_edge_seg_isect(sco_a, sco_b, mouse_path, len, mode, &isected); + + if (isect != 0.0f) { + if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) { + BMO_slot_map_float_insert(&bmop, slot_edge_percents, be, isect); + } + } + } + } + + BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut); + } + + /* free all allocs */ + MEM_freeN(screen_vert_coords); + MEM_freeN(mouse_path); + + BMO_slot_buffer_from_enabled_flag(bm, &bmop, bmop.slots_in, "edges", BM_EDGE, ELE_EDGE_CUT); + + if (mode == KNIFE_MIDPOINT) + numcuts = 1; + BMO_slot_int_set(bmop.slots_in, "cuts", numcuts); + + BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_CORNER_STRAIGHT_CUT); + BMO_slot_bool_set(bmop.slots_in, "use_single_edge", false); + BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false); + + BMO_slot_float_set(bmop.slots_in, "radius", 0); + + BMO_op_exec(bm, &bmop); + if (!EDBM_op_finish(em, &bmop, op, true)) { + return OPERATOR_CANCELLED; + } - mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__); + EDBM_update_generic(em, true, true); - /* get the cut curve */ - RNA_BEGIN (op->ptr, itemptr, "path") - { - RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]); - } - RNA_END; - - /* for ED_view3d_project_float_object */ - ED_view3d_init_mats_rv3d(obedit, ar->regiondata); - - /* TODO, investigate using index lookup for screen_vert_coords() rather then a hash table */ - - /* the floating point coordinates of verts in screen space will be - * stored in a hash table according to the vertices pointer */ - screen_vert_coords = sco = MEM_mallocN(bm->totvert * sizeof(float) * 2, __func__); - - BM_ITER_MESH_INDEX (bv, &iter, bm, BM_VERTS_OF_MESH, i) { - if (ED_view3d_project_float_object(ar, bv->co, *sco, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK) { - copy_v2_fl(*sco, FLT_MAX); /* set error value */ - } - BM_elem_index_set(bv, i); /* set_inline */ - sco++; - - } - bm->elem_index_dirty &= ~BM_VERT; /* clear dirty flag */ - - if (!EDBM_op_init(em, &bmop, op, "subdivide_edges")) { - MEM_freeN(mouse_path); - MEM_freeN(screen_vert_coords); - return OPERATOR_CANCELLED; - } - - /* store percentage of edge cut for KNIFE_EXACT here.*/ - slot_edge_percents = BMO_slot_get(bmop.slots_in, "edge_percents"); - BM_ITER_MESH (be, &iter, bm, BM_EDGES_OF_MESH) { - bool is_cut = false; - if (BM_elem_flag_test(be, BM_ELEM_SELECT)) { - const float *sco_a = screen_vert_coords[BM_elem_index_get(be->v1)]; - const float *sco_b = screen_vert_coords[BM_elem_index_get(be->v2)]; - - /* check for error value (vert cant be projected) */ - if ((sco_a[0] != FLT_MAX) && (sco_b[0] != FLT_MAX)) { - isect = bm_edge_seg_isect(sco_a, sco_b, mouse_path, len, mode, &isected); - - if (isect != 0.0f) { - if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) { - BMO_slot_map_float_insert(&bmop, slot_edge_percents, be, isect); - } - } - } - } - - BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut); - } - - - /* free all allocs */ - MEM_freeN(screen_vert_coords); - MEM_freeN(mouse_path); - - - BMO_slot_buffer_from_enabled_flag(bm, &bmop, bmop.slots_in, "edges", BM_EDGE, ELE_EDGE_CUT); - - if (mode == KNIFE_MIDPOINT) numcuts = 1; - BMO_slot_int_set(bmop.slots_in, "cuts", numcuts); - - BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_CORNER_STRAIGHT_CUT); - BMO_slot_bool_set(bmop.slots_in, "use_single_edge", false); - BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false); - - BMO_slot_float_set(bmop.slots_in, "radius", 0); - - BMO_op_exec(bm, &bmop); - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } - - EDBM_update_generic(em, true, true); - - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } #undef ELE_EDGE_CUT void MESH_OT_knife_cut(wmOperatorType *ot) { - ot->name = "Knife Cut"; - ot->description = "Cut selected edges and faces into parts"; - ot->idname = "MESH_OT_knife_cut"; + ot->name = "Knife Cut"; + ot->description = "Cut selected edges and faces into parts"; + ot->idname = "MESH_OT_knife_cut"; - ot->invoke = WM_gesture_lines_invoke; - ot->modal = WM_gesture_lines_modal; - ot->exec = edbm_knife_cut_exec; + ot->invoke = WM_gesture_lines_invoke; + ot->modal = WM_gesture_lines_modal; + ot->exec = edbm_knife_cut_exec; - ot->poll = EDBM_view3d_poll; + ot->poll = EDBM_view3d_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - PropertyRNA *prop; - prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* properties */ + PropertyRNA *prop; + prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", ""); + RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", ""); - /* internal */ - RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS); + /* internal */ + RNA_def_int( + ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS); } /** \} */ @@ -3692,108 +3850,116 @@ void MESH_OT_knife_cut(wmOperatorType *ot) * \{ */ enum { - MESH_SEPARATE_SELECTED = 0, - MESH_SEPARATE_MATERIAL = 1, - MESH_SEPARATE_LOOSE = 2, + MESH_SEPARATE_SELECTED = 0, + MESH_SEPARATE_MATERIAL = 1, + MESH_SEPARATE_LOOSE = 2, }; -static Base *mesh_separate_tagged(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) +static Base *mesh_separate_tagged( + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) { - Base *base_new; - Object *obedit = base_old->object; - BMesh *bm_new; + Base *base_new; + Object *obedit = base_old->object; + BMesh *bm_new; - bm_new = BM_mesh_create( - &bm_mesh_allocsize_default, - &((struct BMeshCreateParams){.use_toolflags = true,})); - BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */ + bm_new = BM_mesh_create(&bm_mesh_allocsize_default, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); + BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */ - CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); - CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); - CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); - CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); - CustomData_bmesh_init_pool(&bm_new->vdata, bm_mesh_allocsize_default.totvert, BM_VERT); - CustomData_bmesh_init_pool(&bm_new->edata, bm_mesh_allocsize_default.totedge, BM_EDGE); - CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP); - CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE); + CustomData_bmesh_init_pool(&bm_new->vdata, bm_mesh_allocsize_default.totvert, BM_VERT); + CustomData_bmesh_init_pool(&bm_new->edata, bm_mesh_allocsize_default.totedge, BM_EDGE); + CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP); + CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE); - base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, USER_DUP_MESH); + base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, USER_DUP_MESH); - /* normally would call directly after but in this case delay recalc */ - /* DAG_relations_tag_update(bmain); */ + /* normally would call directly after but in this case delay recalc */ + /* DAG_relations_tag_update(bmain); */ - /* new in 2.5 */ - assign_matarar(bmain, base_new->object, give_matarar(obedit), *give_totcolp(obedit)); + /* new in 2.5 */ + assign_matarar(bmain, base_new->object, give_matarar(obedit), *give_totcolp(obedit)); - ED_object_base_select(base_new, BA_SELECT); + ED_object_base_select(base_new, BA_SELECT); - BMO_op_callf(bm_old, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "duplicate geom=%hvef dest=%p", BM_ELEM_TAG, bm_new); - BMO_op_callf(bm_old, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "delete geom=%hvef context=%i", BM_ELEM_TAG, DEL_FACES); + BMO_op_callf(bm_old, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "duplicate geom=%hvef dest=%p", + BM_ELEM_TAG, + bm_new); + BMO_op_callf(bm_old, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "delete geom=%hvef context=%i", + BM_ELEM_TAG, + DEL_FACES); - /* deselect loose data - this used to get deleted, - * we could de-select edges and verts only, but this turns out to be less complicated - * since de-selecting all skips selection flushing logic */ - BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + /* deselect loose data - this used to get deleted, + * we could de-select edges and verts only, but this turns out to be less complicated + * since de-selecting all skips selection flushing logic */ + BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - BM_mesh_normals_update(bm_new); + BM_mesh_normals_update(bm_new); - BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0})); + BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0})); - BM_mesh_free(bm_new); - ((Mesh *)base_new->object->data)->edit_mesh = NULL; + BM_mesh_free(bm_new); + ((Mesh *)base_new->object->data)->edit_mesh = NULL; - return base_new; + return base_new; } -static bool mesh_separate_selected(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) +static bool mesh_separate_selected( + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) { - /* we may have tags from previous operators */ - BM_mesh_elem_hflag_disable_all(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, false); + /* we may have tags from previous operators */ + BM_mesh_elem_hflag_disable_all(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, false); - /* sel -> tag */ - BM_mesh_elem_hflag_enable_test(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, false, BM_ELEM_SELECT); + /* sel -> tag */ + BM_mesh_elem_hflag_enable_test( + bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, false, BM_ELEM_SELECT); - return (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL); + return (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL); } /* flush a hflag to from verts to edges/faces */ static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag) { - BMEdge *e; - BMLoop *l_iter; - BMLoop *l_first; - BMFace *f; - - BMIter eiter; - BMIter fiter; - - bool ok; - - BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e->v1, hflag) && - BM_elem_flag_test(e->v2, hflag)) - { - BM_elem_flag_enable(e, hflag); - } - else { - BM_elem_flag_disable(e, hflag); - } - } - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - ok = true; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (!BM_elem_flag_test(l_iter->v, hflag)) { - ok = false; - break; - } - } while ((l_iter = l_iter->next) != l_first); - - BM_elem_flag_set(f, hflag, ok); - } + BMEdge *e; + BMLoop *l_iter; + BMLoop *l_first; + BMFace *f; + + BMIter eiter; + BMIter fiter; + + bool ok; + + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e->v1, hflag) && BM_elem_flag_test(e->v2, hflag)) { + BM_elem_flag_enable(e, hflag); + } + else { + BM_elem_flag_disable(e, hflag); + } + } + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + ok = true; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BM_elem_flag_test(l_iter->v, hflag)) { + ok = false; + break; + } + } while ((l_iter = l_iter->next) != l_first); + + BM_elem_flag_set(f, hflag, ok); + } } /** @@ -3804,307 +3970,322 @@ static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag) */ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const short mat_nr) { - ID *obdata = ob->data; - - Material ***matarar; - const short *totcolp; - - totcolp = give_totcolp_id(obdata); - matarar = give_matarar_id(obdata); - - if ((totcolp && matarar) == 0) { - BLI_assert(0); - return; - } - - if (*totcolp) { - Material *ma_ob; - Material *ma_obdata; - char matbit; - - if (mat_nr < ob->totcol) { - ma_ob = ob->mat[mat_nr]; - matbit = ob->matbits[mat_nr]; - } - else { - ma_ob = NULL; - matbit = 0; - } - - if (mat_nr < *totcolp) { - ma_obdata = (*matarar)[mat_nr]; - } - else { - ma_obdata = NULL; - } - - BKE_material_clear_id(bmain, obdata, true); - BKE_material_resize_object(bmain, ob, 1, true); - BKE_material_resize_id(bmain, obdata, 1, true); - - ob->mat[0] = ma_ob; - id_us_plus((ID *)ma_ob); - ob->matbits[0] = matbit; - (*matarar)[0] = ma_obdata; - id_us_plus((ID *)ma_obdata); - } - else { - BKE_material_clear_id(bmain, obdata, true); - BKE_material_resize_object(bmain, ob, 0, true); - BKE_material_resize_id(bmain, obdata, 0, true); - } -} - -static bool mesh_separate_material(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) -{ - BMFace *f_cmp, *f; - BMIter iter; - bool result = false; - - while ((f_cmp = BM_iter_at_index(bm_old, BM_FACES_OF_MESH, NULL, 0))) { - Base *base_new; - const short mat_nr = f_cmp->mat_nr; - int tot = 0; - - BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - - BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) { - if (f->mat_nr == mat_nr) { - BMLoop *l_iter; - BMLoop *l_first; - - BM_elem_flag_enable(f, BM_ELEM_TAG); - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG); - BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG); - } while ((l_iter = l_iter->next) != l_first); - - tot++; - } - } - - /* leave the current object with some materials */ - if (tot == bm_old->totface) { - mesh_separate_material_assign_mat_nr(bmain, base_old->object, mat_nr); - - /* since we're in editmode, must set faces here */ - BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) { - f->mat_nr = 0; - } - break; - } - - /* Move selection into a separate object */ - base_new = mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old); - if (base_new) { - mesh_separate_material_assign_mat_nr(bmain, base_new->object, mat_nr); - } - - result |= (base_new != NULL); - } - - return result; -} - -static bool mesh_separate_loose(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) -{ - int i; - BMEdge *e; - BMVert *v_seed; - BMWalker walker; - bool result = false; - int max_iter = bm_old->totvert; - - /* Clear all selected vertices */ - BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - - /* A "while (true)" loop should work here as each iteration should - * select and remove at least one vertex and when all vertices - * are selected the loop will break out. But guard against bad - * behavior by limiting iterations to the number of vertices in the - * original mesh.*/ - for (i = 0; i < max_iter; i++) { - int tot = 0; - /* Get a seed vertex to start the walk */ - v_seed = BM_iter_at_index(bm_old, BM_VERTS_OF_MESH, NULL, 0); - - /* No vertices available, can't do anything */ - if (v_seed == NULL) { - break; - } - - /* Select the seed explicitly, in case it has no edges */ - if (!BM_elem_flag_test(v_seed, BM_ELEM_TAG)) { BM_elem_flag_enable(v_seed, BM_ELEM_TAG); tot++; } - - /* Walk from the single vertex, selecting everything connected - * to it */ - BMW_init(&walker, bm_old, BMW_VERT_SHELL, - BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_NOP, - BMW_NIL_LAY); - - for (e = BMW_begin(&walker, v_seed); e; e = BMW_step(&walker)) { - if (!BM_elem_flag_test(e->v1, BM_ELEM_TAG)) { BM_elem_flag_enable(e->v1, BM_ELEM_TAG); tot++; } - if (!BM_elem_flag_test(e->v2, BM_ELEM_TAG)) { BM_elem_flag_enable(e->v2, BM_ELEM_TAG); tot++; } - } - BMW_end(&walker); - - if (bm_old->totvert == tot) { - /* Every vertex selected, nothing to separate, work is done */ - break; - } - - /* Flush the selection to get edge/face selections matching - * the vertex selection */ - bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG); - - /* Move selection into a separate object */ - result |= (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL); - } - - return result; + ID *obdata = ob->data; + + Material ***matarar; + const short *totcolp; + + totcolp = give_totcolp_id(obdata); + matarar = give_matarar_id(obdata); + + if ((totcolp && matarar) == 0) { + BLI_assert(0); + return; + } + + if (*totcolp) { + Material *ma_ob; + Material *ma_obdata; + char matbit; + + if (mat_nr < ob->totcol) { + ma_ob = ob->mat[mat_nr]; + matbit = ob->matbits[mat_nr]; + } + else { + ma_ob = NULL; + matbit = 0; + } + + if (mat_nr < *totcolp) { + ma_obdata = (*matarar)[mat_nr]; + } + else { + ma_obdata = NULL; + } + + BKE_material_clear_id(bmain, obdata, true); + BKE_material_resize_object(bmain, ob, 1, true); + BKE_material_resize_id(bmain, obdata, 1, true); + + ob->mat[0] = ma_ob; + id_us_plus((ID *)ma_ob); + ob->matbits[0] = matbit; + (*matarar)[0] = ma_obdata; + id_us_plus((ID *)ma_obdata); + } + else { + BKE_material_clear_id(bmain, obdata, true); + BKE_material_resize_object(bmain, ob, 0, true); + BKE_material_resize_id(bmain, obdata, 0, true); + } +} + +static bool mesh_separate_material( + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) +{ + BMFace *f_cmp, *f; + BMIter iter; + bool result = false; + + while ((f_cmp = BM_iter_at_index(bm_old, BM_FACES_OF_MESH, NULL, 0))) { + Base *base_new; + const short mat_nr = f_cmp->mat_nr; + int tot = 0; + + BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) { + if (f->mat_nr == mat_nr) { + BMLoop *l_iter; + BMLoop *l_first; + + BM_elem_flag_enable(f, BM_ELEM_TAG); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG); + BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG); + } while ((l_iter = l_iter->next) != l_first); + + tot++; + } + } + + /* leave the current object with some materials */ + if (tot == bm_old->totface) { + mesh_separate_material_assign_mat_nr(bmain, base_old->object, mat_nr); + + /* since we're in editmode, must set faces here */ + BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) { + f->mat_nr = 0; + } + break; + } + + /* Move selection into a separate object */ + base_new = mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old); + if (base_new) { + mesh_separate_material_assign_mat_nr(bmain, base_new->object, mat_nr); + } + + result |= (base_new != NULL); + } + + return result; +} + +static bool mesh_separate_loose( + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) +{ + int i; + BMEdge *e; + BMVert *v_seed; + BMWalker walker; + bool result = false; + int max_iter = bm_old->totvert; + + /* Clear all selected vertices */ + BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + /* A "while (true)" loop should work here as each iteration should + * select and remove at least one vertex and when all vertices + * are selected the loop will break out. But guard against bad + * behavior by limiting iterations to the number of vertices in the + * original mesh.*/ + for (i = 0; i < max_iter; i++) { + int tot = 0; + /* Get a seed vertex to start the walk */ + v_seed = BM_iter_at_index(bm_old, BM_VERTS_OF_MESH, NULL, 0); + + /* No vertices available, can't do anything */ + if (v_seed == NULL) { + break; + } + + /* Select the seed explicitly, in case it has no edges */ + if (!BM_elem_flag_test(v_seed, BM_ELEM_TAG)) { + BM_elem_flag_enable(v_seed, BM_ELEM_TAG); + tot++; + } + + /* Walk from the single vertex, selecting everything connected + * to it */ + BMW_init(&walker, + bm_old, + BMW_VERT_SHELL, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_NOP, + BMW_NIL_LAY); + + for (e = BMW_begin(&walker, v_seed); e; e = BMW_step(&walker)) { + if (!BM_elem_flag_test(e->v1, BM_ELEM_TAG)) { + BM_elem_flag_enable(e->v1, BM_ELEM_TAG); + tot++; + } + if (!BM_elem_flag_test(e->v2, BM_ELEM_TAG)) { + BM_elem_flag_enable(e->v2, BM_ELEM_TAG); + tot++; + } + } + BMW_end(&walker); + + if (bm_old->totvert == tot) { + /* Every vertex selected, nothing to separate, work is done */ + break; + } + + /* Flush the selection to get edge/face selections matching + * the vertex selection */ + bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG); + + /* Move selection into a separate object */ + result |= (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL); + } + + return result; } static int edbm_separate_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const int type = RNA_enum_get(op->ptr, "type"); - int retval = 0; - - if (ED_operator_editmesh(C)) { - uint bases_len = 0; - uint empty_selection_len = 0; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &bases_len); - for (uint bs_index = 0; bs_index < bases_len; bs_index++) { - Base *base = bases[bs_index]; - BMEditMesh *em = BKE_editmesh_from_object(base->object); - - if (type == 0) { - if ((em->bm->totvertsel == 0) && - (em->bm->totedgesel == 0) && - (em->bm->totfacesel == 0)) - { - /* when all objects has no selection */ - if (++empty_selection_len == bases_len) { - BKE_report(op->reports, RPT_ERROR, "Nothing selected"); - } - continue; - } - } - - /* editmode separate */ - switch (type) { - case MESH_SEPARATE_SELECTED: - retval = mesh_separate_selected(bmain, scene, view_layer, base, em->bm); - break; - case MESH_SEPARATE_MATERIAL: - retval = mesh_separate_material(bmain, scene, view_layer, base, em->bm); - break; - case MESH_SEPARATE_LOOSE: - retval = mesh_separate_loose(bmain, scene, view_layer, base, em->bm); - break; - default: - BLI_assert(0); - break; - } - - if (retval) { - EDBM_update_generic(em, true, true); - } - } - MEM_freeN(bases); - } - else { - if (type == MESH_SEPARATE_SELECTED) { - BKE_report(op->reports, RPT_ERROR, "Selection not supported in object mode"); - return OPERATOR_CANCELLED; - } - - /* object mode separate */ - CTX_DATA_BEGIN(C, Base *, base_iter, selected_editable_bases) - { - Object *ob = base_iter->object; - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - if (!ID_IS_LINKED(me)) { - BMesh *bm_old = NULL; - int retval_iter = 0; - - bm_old = BM_mesh_create( - &bm_mesh_allocsize_default, - &((struct BMeshCreateParams){.use_toolflags = true,})); - - BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0})); - - switch (type) { - case MESH_SEPARATE_MATERIAL: - retval_iter = mesh_separate_material(bmain, scene, view_layer, base_iter, bm_old); - break; - case MESH_SEPARATE_LOOSE: - retval_iter = mesh_separate_loose(bmain, scene, view_layer, base_iter, bm_old); - break; - default: - BLI_assert(0); - break; - } - - if (retval_iter) { - BM_mesh_bm_to_me( - bmain, bm_old, me, - (&(struct BMeshToMeshParams){ - .calc_object_remap = true, - })); - - DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - } - - BM_mesh_free(bm_old); - - retval |= retval_iter; - } - } - } - CTX_DATA_END; - } - - if (retval) { - /* delay depsgraph recalc until all objects are duplicated */ - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); - - return OPERATOR_FINISHED; - } - - return OPERATOR_CANCELLED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const int type = RNA_enum_get(op->ptr, "type"); + int retval = 0; + + if (ED_operator_editmesh(C)) { + uint bases_len = 0; + uint empty_selection_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &bases_len); + for (uint bs_index = 0; bs_index < bases_len; bs_index++) { + Base *base = bases[bs_index]; + BMEditMesh *em = BKE_editmesh_from_object(base->object); + + if (type == 0) { + if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) { + /* when all objects has no selection */ + if (++empty_selection_len == bases_len) { + BKE_report(op->reports, RPT_ERROR, "Nothing selected"); + } + continue; + } + } + + /* editmode separate */ + switch (type) { + case MESH_SEPARATE_SELECTED: + retval = mesh_separate_selected(bmain, scene, view_layer, base, em->bm); + break; + case MESH_SEPARATE_MATERIAL: + retval = mesh_separate_material(bmain, scene, view_layer, base, em->bm); + break; + case MESH_SEPARATE_LOOSE: + retval = mesh_separate_loose(bmain, scene, view_layer, base, em->bm); + break; + default: + BLI_assert(0); + break; + } + + if (retval) { + EDBM_update_generic(em, true, true); + } + } + MEM_freeN(bases); + } + else { + if (type == MESH_SEPARATE_SELECTED) { + BKE_report(op->reports, RPT_ERROR, "Selection not supported in object mode"); + return OPERATOR_CANCELLED; + } + + /* object mode separate */ + CTX_DATA_BEGIN (C, Base *, base_iter, selected_editable_bases) { + Object *ob = base_iter->object; + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + if (!ID_IS_LINKED(me)) { + BMesh *bm_old = NULL; + int retval_iter = 0; + + bm_old = BM_mesh_create(&bm_mesh_allocsize_default, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); + + BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0})); + + switch (type) { + case MESH_SEPARATE_MATERIAL: + retval_iter = mesh_separate_material(bmain, scene, view_layer, base_iter, bm_old); + break; + case MESH_SEPARATE_LOOSE: + retval_iter = mesh_separate_loose(bmain, scene, view_layer, base_iter, bm_old); + break; + default: + BLI_assert(0); + break; + } + + if (retval_iter) { + BM_mesh_bm_to_me(bmain, + bm_old, + me, + (&(struct BMeshToMeshParams){ + .calc_object_remap = true, + })); + + DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + } + + BM_mesh_free(bm_old); + + retval |= retval_iter; + } + } + } + CTX_DATA_END; + } + + if (retval) { + /* delay depsgraph recalc until all objects are duplicated */ + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; } void MESH_OT_separate(wmOperatorType *ot) { - static const EnumPropertyItem prop_separate_types[] = { - {MESH_SEPARATE_SELECTED, "SELECTED", 0, "Selection", ""}, - {MESH_SEPARATE_MATERIAL, "MATERIAL", 0, "By Material", ""}, - {MESH_SEPARATE_LOOSE, "LOOSE", 0, "By loose parts", ""}, - {0, NULL, 0, NULL, NULL}, - }; + static const EnumPropertyItem prop_separate_types[] = { + {MESH_SEPARATE_SELECTED, "SELECTED", 0, "Selection", ""}, + {MESH_SEPARATE_MATERIAL, "MATERIAL", 0, "By Material", ""}, + {MESH_SEPARATE_LOOSE, "LOOSE", 0, "By loose parts", ""}, + {0, NULL, 0, NULL, NULL}, + }; - /* identifiers */ - ot->name = "Separate"; - ot->description = "Separate selected geometry into a new mesh"; - ot->idname = "MESH_OT_separate"; + /* identifiers */ + ot->name = "Separate"; + ot->description = "Separate selected geometry into a new mesh"; + ot->idname = "MESH_OT_separate"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = edbm_separate_exec; - ot->poll = ED_operator_scene_editable; /* object and editmode */ + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = edbm_separate_exec; + ot->poll = ED_operator_scene_editable; /* object and editmode */ - /* flags */ - ot->flag = OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", ""); + ot->prop = RNA_def_enum( + ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", ""); } /** \} */ @@ -4115,81 +4296,80 @@ void MESH_OT_separate(wmOperatorType *ot) static int edbm_fill_exec(bContext *C, wmOperator *op) { - const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty"); + const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty"); - bool has_selected_edges = false, has_faces_filled = false; + bool has_selected_edges = false, has_faces_filled = false; - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int totface_orig = em->bm->totface; + const int totface_orig = em->bm->totface; - if (em->bm->totedgesel == 0) { - continue; - } - has_selected_edges = true; + if (em->bm->totedgesel == 0) { + continue; + } + has_selected_edges = true; - BMOperator bmop; - if (!EDBM_op_init( - em, &bmop, op, - "triangle_fill edges=%he use_beauty=%b", - BM_ELEM_SELECT, use_beauty)) - { - continue; - } + BMOperator bmop; + if (!EDBM_op_init( + em, &bmop, op, "triangle_fill edges=%he use_beauty=%b", BM_ELEM_SELECT, use_beauty)) { + continue; + } - BMO_op_exec(em->bm, &bmop); + BMO_op_exec(em->bm, &bmop); - /* cancel if nothing was done */ - if (totface_orig == em->bm->totface) { - EDBM_op_finish(em, &bmop, op, true); - continue; - } - has_faces_filled = true; + /* cancel if nothing was done */ + if (totface_orig == em->bm->totface) { + EDBM_op_finish(em, &bmop, op, true); + continue; + } + has_faces_filled = true; - /* select new geometry */ - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true); + /* select new geometry */ + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true); - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - if (!has_selected_edges) { - BKE_report(op->reports, RPT_ERROR, "No edges selected"); - return OPERATOR_CANCELLED; - } + if (!has_selected_edges) { + BKE_report(op->reports, RPT_ERROR, "No edges selected"); + return OPERATOR_CANCELLED; + } - if (!has_faces_filled) { - BKE_report(op->reports, RPT_WARNING, "No faces filled"); - return OPERATOR_CANCELLED; - } + if (!has_faces_filled) { + BKE_report(op->reports, RPT_WARNING, "No faces filled"); + return OPERATOR_CANCELLED; + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_fill(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Fill"; - ot->idname = "MESH_OT_fill"; - ot->description = "Fill a selected edge loop with faces"; + /* identifiers */ + ot->name = "Fill"; + ot->idname = "MESH_OT_fill"; + ot->description = "Fill a selected edge loop with faces"; - /* api callbacks */ - ot->exec = edbm_fill_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_fill_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division"); + RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division"); } /** \} */ @@ -4200,23 +4380,23 @@ void MESH_OT_fill(wmOperatorType *ot) static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v)) { - return BM_elem_flag_test_bool(e, BM_ELEM_TAG); + return BM_elem_flag_test_bool(e, BM_ELEM_TAG); } static float edbm_fill_grid_vert_tag_angle(BMVert *v) { - BMIter iter; - BMEdge *e_iter; - BMVert *v_pair[2]; - int i = 0; - BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) { - v_pair[i++] = BM_edge_other_vert(e_iter, v); - } - } - BLI_assert(i == 2); + BMIter iter; + BMEdge *e_iter; + BMVert *v_pair[2]; + int i = 0; + BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) { + v_pair[i++] = BM_edge_other_vert(e_iter, v); + } + } + BLI_assert(i == 2); - return fabsf((float)M_PI - angle_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)); + return fabsf((float)M_PI - angle_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)); } /** @@ -4224,245 +4404,254 @@ static float edbm_fill_grid_vert_tag_angle(BMVert *v) */ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span_calc) { - /* angle differences below this value are considered 'even' - * in that they shouldn't be used to calculate corners used for the 'span' */ - const float eps_even = 1e-3f; - BMEdge *e; - BMIter iter; - int count; - int span = *r_span; - - ListBase eloops = {NULL}; - struct BMEdgeLoopStore *el_store; - // LinkData *el_store; - - /* select -> tag */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); - } - - count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm); - el_store = eloops.first; - - if (count == 1 && BM_edgeloop_is_closed(el_store) && (BM_edgeloop_length_get(el_store) & 1) == 0) { - /* be clever! detect 2 edge loops from one closed edge loop */ - const int verts_len = BM_edgeloop_length_get(el_store); - ListBase *verts = BM_edgeloop_verts_get(el_store); - BMVert *v_act = BM_mesh_active_vert_get(bm); - LinkData *v_act_link; - BMEdge **edges = MEM_mallocN(sizeof(*edges) * verts_len, __func__); - int i; - - if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) { - /* pass */ - } - else { - /* find the vertex with the best angle (a corner vertex) */ - LinkData *v_link, *v_link_best = NULL; - float angle_best = -1.0f; - for (v_link = verts->first; v_link; v_link = v_link->next) { - const float angle = edbm_fill_grid_vert_tag_angle(v_link->data); - if ((angle > angle_best) || (v_link_best == NULL)) { - angle_best = angle; - v_link_best = v_link; - } - } - - v_act_link = v_link_best; - v_act = v_act_link->data; - } - - /* set this vertex first */ - BLI_listbase_rotate_first(verts, v_act_link); - - if (offset != 0) { - v_act_link = BLI_findlink(verts, offset); - v_act = v_act_link->data; - BLI_listbase_rotate_first(verts, v_act_link); - } - - BM_edgeloop_edges_get(el_store, edges); - - - if (span_calc) { - /* calculate the span by finding the next corner in 'verts' - * we dont know what defines a corner exactly so find the 4 verts - * in the loop with the greatest angle. - * Tag them and use the first tagged vertex to calculate the span. - * - * note: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each - * vert, but advantage of de-duplicating is minimal. */ - struct SortPtrByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__); - LinkData *v_link; - for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) { - BMVert *v = v_link->data; - const float angle = edbm_fill_grid_vert_tag_angle(v); - ele_sort[i].sort_value = angle; - ele_sort[i].data = v; - - BM_elem_flag_disable(v, BM_ELEM_TAG); - } - - qsort(ele_sort, verts_len, sizeof(*ele_sort), BLI_sortutil_cmp_float_reverse); - - /* check that we have at least 3 corners, - * if the angle on the 3rd angle is roughly the same as the last, - * then we can't calculate 3+ corners - fallback to the even span. */ - if ((ele_sort[2].sort_value - ele_sort[verts_len - 1].sort_value) > eps_even) { - for (i = 0; i < 4; i++) { - BMVert *v = ele_sort[i].data; - BM_elem_flag_enable(v, BM_ELEM_TAG); - } - - /* now find the first... */ - for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) { - BMVert *v = v_link->data; - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - if (v != v_act) { - span = i; - break; - } - } - } - } - MEM_freeN(ele_sort); - } - /* end span calc */ - - - /* un-flag 'rails' */ - for (i = 0; i < span; i++) { - BM_elem_flag_disable(edges[i], BM_ELEM_TAG); - BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG); - } - MEM_freeN(edges); - } - /* else let the bmesh-operator handle it */ - - BM_mesh_edgeloops_free(&eloops); - - *r_span = span; + /* angle differences below this value are considered 'even' + * in that they shouldn't be used to calculate corners used for the 'span' */ + const float eps_even = 1e-3f; + BMEdge *e; + BMIter iter; + int count; + int span = *r_span; + + ListBase eloops = {NULL}; + struct BMEdgeLoopStore *el_store; + // LinkData *el_store; + + /* select -> tag */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + } + + count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm); + el_store = eloops.first; + + if (count == 1 && BM_edgeloop_is_closed(el_store) && + (BM_edgeloop_length_get(el_store) & 1) == 0) { + /* be clever! detect 2 edge loops from one closed edge loop */ + const int verts_len = BM_edgeloop_length_get(el_store); + ListBase *verts = BM_edgeloop_verts_get(el_store); + BMVert *v_act = BM_mesh_active_vert_get(bm); + LinkData *v_act_link; + BMEdge **edges = MEM_mallocN(sizeof(*edges) * verts_len, __func__); + int i; + + if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) { + /* pass */ + } + else { + /* find the vertex with the best angle (a corner vertex) */ + LinkData *v_link, *v_link_best = NULL; + float angle_best = -1.0f; + for (v_link = verts->first; v_link; v_link = v_link->next) { + const float angle = edbm_fill_grid_vert_tag_angle(v_link->data); + if ((angle > angle_best) || (v_link_best == NULL)) { + angle_best = angle; + v_link_best = v_link; + } + } + + v_act_link = v_link_best; + v_act = v_act_link->data; + } + + /* set this vertex first */ + BLI_listbase_rotate_first(verts, v_act_link); + + if (offset != 0) { + v_act_link = BLI_findlink(verts, offset); + v_act = v_act_link->data; + BLI_listbase_rotate_first(verts, v_act_link); + } + + BM_edgeloop_edges_get(el_store, edges); + + if (span_calc) { + /* calculate the span by finding the next corner in 'verts' + * we dont know what defines a corner exactly so find the 4 verts + * in the loop with the greatest angle. + * Tag them and use the first tagged vertex to calculate the span. + * + * note: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each + * vert, but advantage of de-duplicating is minimal. */ + struct SortPtrByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__); + LinkData *v_link; + for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) { + BMVert *v = v_link->data; + const float angle = edbm_fill_grid_vert_tag_angle(v); + ele_sort[i].sort_value = angle; + ele_sort[i].data = v; + + BM_elem_flag_disable(v, BM_ELEM_TAG); + } + + qsort(ele_sort, verts_len, sizeof(*ele_sort), BLI_sortutil_cmp_float_reverse); + + /* check that we have at least 3 corners, + * if the angle on the 3rd angle is roughly the same as the last, + * then we can't calculate 3+ corners - fallback to the even span. */ + if ((ele_sort[2].sort_value - ele_sort[verts_len - 1].sort_value) > eps_even) { + for (i = 0; i < 4; i++) { + BMVert *v = ele_sort[i].data; + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + + /* now find the first... */ + for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) { + BMVert *v = v_link->data; + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + if (v != v_act) { + span = i; + break; + } + } + } + } + MEM_freeN(ele_sort); + } + /* end span calc */ + + /* un-flag 'rails' */ + for (i = 0; i < span; i++) { + BM_elem_flag_disable(edges[i], BM_ELEM_TAG); + BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG); + } + MEM_freeN(edges); + } + /* else let the bmesh-operator handle it */ + + BM_mesh_edgeloops_free(&eloops); + + *r_span = span; } static int edbm_fill_grid_exec(bContext *C, wmOperator *op) { - const bool use_prepare = true; - const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple"); - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm); - const int totedge_orig = em->bm->totedge; - const int totface_orig = em->bm->totface; - - if (em->bm->totedgesel == 0) { - continue; - } - - if (use_prepare) { - /* use when we have a single loop selected */ - PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span"); - PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset"); - bool calc_span; - - const int clamp = em->bm->totvertsel; - int span; - int offset; - - /* Only reuse on redo because these settings need to match the current selection. - * We never want to use them on other geometry, repeat last for eg, see: T60777. */ - if ((op->flag & OP_IS_REPEAT) && - RNA_property_is_set(op->ptr, prop_span)) - { - span = RNA_property_int_get(op->ptr, prop_span); - span = min_ii(span, (clamp / 2) - 1); - calc_span = false; - } - else { - span = clamp / 4; - calc_span = true; - } - - offset = RNA_property_int_get(op->ptr, prop_offset); - offset = clamp ? mod_i(offset, clamp) : 0; - - /* in simple cases, move selection for tags, but also support more advanced cases */ - edbm_fill_grid_prepare(em->bm, offset, &span, calc_span); - - RNA_property_int_set(op->ptr, prop_span, span); - } - /* end tricky prepare code */ - - BMOperator bmop; - if (!EDBM_op_init( - em, &bmop, op, - "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b", - use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT, - em->mat_nr, use_smooth, use_interp_simple)) - { - continue; - } - - BMO_op_exec(em->bm, &bmop); - - /* NOTE: EDBM_op_finish() will change bmesh pointer inside of edit mesh, - * so need to tell evaluated objects to sync new bmesh pointer to their - * edit mesh structures. - */ - DEG_id_tag_update(&obedit->id, 0); - - /* cancel if nothing was done */ - if ((totedge_orig == em->bm->totedge) && - (totface_orig == em->bm->totface)) - { - EDBM_op_finish(em, &bmop, op, true); - continue; - } - - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - - EDBM_update_generic(em, true, true); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const bool use_prepare = true; + const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple"); + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm); + const int totedge_orig = em->bm->totedge; + const int totface_orig = em->bm->totface; + + if (em->bm->totedgesel == 0) { + continue; + } + + if (use_prepare) { + /* use when we have a single loop selected */ + PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span"); + PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset"); + bool calc_span; + + const int clamp = em->bm->totvertsel; + int span; + int offset; + + /* Only reuse on redo because these settings need to match the current selection. + * We never want to use them on other geometry, repeat last for eg, see: T60777. */ + if ((op->flag & OP_IS_REPEAT) && RNA_property_is_set(op->ptr, prop_span)) { + span = RNA_property_int_get(op->ptr, prop_span); + span = min_ii(span, (clamp / 2) - 1); + calc_span = false; + } + else { + span = clamp / 4; + calc_span = true; + } + + offset = RNA_property_int_get(op->ptr, prop_offset); + offset = clamp ? mod_i(offset, clamp) : 0; + + /* in simple cases, move selection for tags, but also support more advanced cases */ + edbm_fill_grid_prepare(em->bm, offset, &span, calc_span); + + RNA_property_int_set(op->ptr, prop_span, span); + } + /* end tricky prepare code */ + + BMOperator bmop; + if (!EDBM_op_init(em, + &bmop, + op, + "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b", + use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT, + em->mat_nr, + use_smooth, + use_interp_simple)) { + continue; + } + + BMO_op_exec(em->bm, &bmop); + + /* NOTE: EDBM_op_finish() will change bmesh pointer inside of edit mesh, + * so need to tell evaluated objects to sync new bmesh pointer to their + * edit mesh structures. + */ + DEG_id_tag_update(&obedit->id, 0); + + /* cancel if nothing was done */ + if ((totedge_orig == em->bm->totedge) && (totface_orig == em->bm->totface)) { + EDBM_op_finish(em, &bmop, op, true); + continue; + } + + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_update_generic(em, true, true); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_fill_grid(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Grid Fill"; - ot->description = "Fill grid from two loops"; - ot->idname = "MESH_OT_fill_grid"; - - /* api callbacks */ - ot->exec = edbm_fill_grid_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_int(ot->srna, "span", 1, 1, 1000, "Span", "Number of grid columns", 1, 100); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_int(ot->srna, "offset", 0, -1000, 1000, "Offset", - "Vertex that is the corner of the grid", -100, 100); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - RNA_def_boolean(ot->srna, "use_interp_simple", false, "Simple Blending", - "Use simple interpolation of grid vertices"); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Grid Fill"; + ot->description = "Fill grid from two loops"; + ot->idname = "MESH_OT_fill_grid"; + + /* api callbacks */ + ot->exec = edbm_fill_grid_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_int(ot->srna, "span", 1, 1, 1000, "Span", "Number of grid columns", 1, 100); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, + "offset", + 0, + -1000, + 1000, + "Offset", + "Vertex that is the corner of the grid", + -100, + 100); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_boolean(ot->srna, + "use_interp_simple", + false, + "Simple Blending", + "Use simple interpolation of grid vertices"); } /** \} */ @@ -4473,53 +4662,56 @@ void MESH_OT_fill_grid(wmOperatorType *ot) static int edbm_fill_holes_exec(bContext *C, wmOperator *op) { - const int sides = RNA_int_get(op->ptr, "sides"); - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + const int sides = RNA_int_get(op->ptr, "sides"); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - if (em->bm->totedgesel == 0) { - continue; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (!EDBM_op_call_and_selectf( - em, op, - "faces.out", true, - "holes_fill edges=%he sides=%i", - BM_ELEM_SELECT, sides)) - { - continue; - } + if (em->bm->totedgesel == 0) { + continue; + } - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + if (!EDBM_op_call_and_selectf( + em, op, "faces.out", true, "holes_fill edges=%he sides=%i", BM_ELEM_SELECT, sides)) { + continue; + } - return OPERATOR_FINISHED; + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_fill_holes(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Fill Holes"; - ot->idname = "MESH_OT_fill_holes"; - ot->description = "Fill in holes (boundary edge loops)"; + /* identifiers */ + ot->name = "Fill Holes"; + ot->idname = "MESH_OT_fill_holes"; + ot->description = "Fill in holes (boundary edge loops)"; - /* api callbacks */ - ot->exec = edbm_fill_holes_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_fill_holes_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_int(ot->srna, "sides", 4, 0, 1000, - "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100); + RNA_def_int(ot->srna, + "sides", + 4, + 0, + 1000, + "Sides", + "Number of sides in hole required to fill (zero fills all holes)", + 0, + 100); } /** \} */ @@ -4530,75 +4722,85 @@ void MESH_OT_fill_holes(wmOperatorType *ot) static int edbm_beautify_fill_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - const float angle_max = M_PI; - const float angle_limit = RNA_float_get(op->ptr, "angle_limit"); - char hflag; - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totfacesel == 0) { - continue; - } - - if (angle_limit >= angle_max) { - hflag = BM_ELEM_SELECT; - } - else { - BMIter iter; - BMEdge *e; - - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set( - e, BM_ELEM_TAG, - (BM_elem_flag_test(e, BM_ELEM_SELECT) && - BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit)); - - } - hflag = BM_ELEM_TAG; - } - - if (!EDBM_op_call_and_selectf( - em, op, "geom.out", true, - "beautify_fill faces=%hf edges=%he", - BM_ELEM_SELECT, hflag)) - { - continue; - } - - EDBM_update_generic(em, true, true); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + const float angle_max = M_PI; + const float angle_limit = RNA_float_get(op->ptr, "angle_limit"); + char hflag; + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totfacesel == 0) { + continue; + } + + if (angle_limit >= angle_max) { + hflag = BM_ELEM_SELECT; + } + else { + BMIter iter; + BMEdge *e; + + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, + BM_ELEM_TAG, + (BM_elem_flag_test(e, BM_ELEM_SELECT) && + BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit)); + } + hflag = BM_ELEM_TAG; + } + + if (!EDBM_op_call_and_selectf(em, + op, + "geom.out", + true, + "beautify_fill faces=%hf edges=%he", + BM_ELEM_SELECT, + hflag)) { + continue; + } + + EDBM_update_generic(em, true, true); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_beautify_fill(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Beautify Faces"; - ot->idname = "MESH_OT_beautify_fill"; - ot->description = "Rearrange some faces to try to get less degenerated geometry"; + /* identifiers */ + ot->name = "Beautify Faces"; + ot->idname = "MESH_OT_beautify_fill"; + ot->description = "Rearrange some faces to try to get less degenerated geometry"; - /* api callbacks */ - ot->exec = edbm_beautify_fill_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_beautify_fill_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f), - "Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f)); - RNA_def_property_float_default(prop, DEG2RADF(180.0f)); + /* props */ + prop = RNA_def_float_rotation(ot->srna, + "angle_limit", + 0, + NULL, + 0.0f, + DEG2RADF(180.0f), + "Max Angle", + "Angle limit", + 0.0f, + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(180.0f)); } /** \} */ @@ -4609,71 +4811,91 @@ void MESH_OT_beautify_fill(wmOperatorType *ot) static int edbm_poke_face_exec(bContext *C, wmOperator *op) { - const float offset = RNA_float_get(op->ptr, "offset"); - const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset"); - const int center_mode = RNA_enum_get(op->ptr, "center_mode"); + const float offset = RNA_float_get(op->ptr, "offset"); + const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset"); + const int center_mode = RNA_enum_get(op->ptr, "center_mode"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - BMOperator bmop; - EDBM_op_init(em, &bmop, op, "poke faces=%hf offset=%f use_relative_offset=%b center_mode=%i", - BM_ELEM_SELECT, offset, use_relative_offset, center_mode); - BMO_op_exec(em->bm, &bmop); + BMOperator bmop; + EDBM_op_init(em, + &bmop, + op, + "poke faces=%hf offset=%f use_relative_offset=%b center_mode=%i", + BM_ELEM_SELECT, + offset, + use_relative_offset, + center_mode); + BMO_op_exec(em->bm, &bmop); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - EDBM_mesh_normals_update(em); + EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_poke(wmOperatorType *ot) { - static const EnumPropertyItem poke_center_modes[] = { - {BMOP_POKE_MEDIAN_WEIGHTED, "MEDIAN_WEIGHTED", 0, "Weighted Median", "Weighted median face center"}, - {BMOP_POKE_MEDIAN, "MEDIAN", 0, "Median", "Median face center"}, - {BMOP_POKE_BOUNDS, "BOUNDS", 0, "Bounds", "Face bounds center"}, - {0, NULL, 0, NULL, NULL}, - }; - - - /* identifiers */ - ot->name = "Poke Faces"; - ot->idname = "MESH_OT_poke"; - ot->description = "Split a face into a fan"; - - /* api callbacks */ - ot->exec = edbm_poke_face_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_float_distance(ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f); - RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry"); - RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEDIAN_WEIGHTED, - "Poke Center", "Poke Face Center Calculation"); + static const EnumPropertyItem poke_center_modes[] = { + {BMOP_POKE_MEDIAN_WEIGHTED, + "MEDIAN_WEIGHTED", + 0, + "Weighted Median", + "Weighted median face center"}, + {BMOP_POKE_MEDIAN, "MEDIAN", 0, "Median", "Median face center"}, + {BMOP_POKE_BOUNDS, "BOUNDS", 0, "Bounds", "Face bounds center"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Poke Faces"; + ot->idname = "MESH_OT_poke"; + ot->description = "Split a face into a fan"; + + /* api callbacks */ + ot->exec = edbm_poke_face_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_float_distance( + ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f); + RNA_def_boolean(ot->srna, + "use_relative_offset", + false, + "Offset Relative", + "Scale the offset by surrounding geometry"); + RNA_def_enum(ot->srna, + "center_mode", + poke_center_modes, + BMOP_POKE_MEDIAN_WEIGHTED, + "Poke Center", + "Poke Face Center Calculation"); } /** \} */ @@ -4684,71 +4906,83 @@ void MESH_OT_poke(wmOperatorType *ot) static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op) { - const int quad_method = RNA_enum_get(op->ptr, "quad_method"); - const int ngon_method = RNA_enum_get(op->ptr, "ngon_method"); - ViewLayer *view_layer = CTX_data_view_layer(C); + const int quad_method = RNA_enum_get(op->ptr, "quad_method"); + const int ngon_method = RNA_enum_get(op->ptr, "ngon_method"); + ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - BMOperator bmop; - BMOIter oiter; - BMFace *f; + BMOperator bmop; + BMOIter oiter; + BMFace *f; - EDBM_op_init( - em, &bmop, op, - "triangulate faces=%hf quad_method=%i ngon_method=%i", - BM_ELEM_SELECT, quad_method, ngon_method); - BMO_op_exec(em->bm, &bmop); + EDBM_op_init(em, + &bmop, + op, + "triangulate faces=%hf quad_method=%i ngon_method=%i", + BM_ELEM_SELECT, + quad_method, + ngon_method); + BMO_op_exec(em->bm, &bmop); - /* select the output */ - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + /* select the output */ + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - /* remove the doubles */ - BMO_ITER (f, &oiter, bmop.slots_out, "face_map_double.out", BM_FACE) { - BM_face_kill(em->bm, f); - } + /* remove the doubles */ + BMO_ITER (f, &oiter, bmop.slots_out, "face_map_double.out", BM_FACE) { + BM_face_kill(em->bm, f); + } - EDBM_selectmode_flush(em); + EDBM_selectmode_flush(em); - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - EDBM_update_generic(em, true, true); - } + EDBM_update_generic(em, true, true); + } - MEM_freeN(objects); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } - void MESH_OT_quads_convert_to_tris(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Triangulate Faces"; - ot->idname = "MESH_OT_quads_convert_to_tris"; - ot->description = "Triangulate selected faces"; + /* identifiers */ + ot->name = "Triangulate Faces"; + ot->idname = "MESH_OT_quads_convert_to_tris"; + ot->description = "Triangulate selected faces"; - /* api callbacks */ - ot->exec = edbm_quads_convert_to_tris_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_quads_convert_to_tris_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_enum(ot->srna, "quad_method", rna_enum_modifier_triangulate_quad_method_items, MOD_TRIANGULATE_QUAD_BEAUTY, - "Quad Method", "Method for splitting the quads into triangles"); - RNA_def_enum(ot->srna, "ngon_method", rna_enum_modifier_triangulate_ngon_method_items, MOD_TRIANGULATE_NGON_BEAUTY, - "Polygon Method", "Method for splitting the polygons into triangles"); + RNA_def_enum(ot->srna, + "quad_method", + rna_enum_modifier_triangulate_quad_method_items, + MOD_TRIANGULATE_QUAD_BEAUTY, + "Quad Method", + "Method for splitting the quads into triangles"); + RNA_def_enum(ot->srna, + "ngon_method", + rna_enum_modifier_triangulate_ngon_method_items, + MOD_TRIANGULATE_NGON_BEAUTY, + "Polygon Method", + "Method for splitting the polygons into triangles"); } /** \} */ @@ -4759,109 +4993,127 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot) static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - bool is_face_pair; - - { - int totelem_sel[3]; - EDBM_mesh_stats_multi(objects, objects_len, NULL, totelem_sel); - is_face_pair = (totelem_sel[2] == 2); - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - bool do_seam, do_sharp, do_uvs, do_vcols, do_materials; - float angle_face_threshold, angle_shape_threshold; - PropertyRNA *prop; - - /* When joining exactly 2 faces, no limit. - * this is useful for one off joins while editing. */ - prop = RNA_struct_find_property(op->ptr, "face_threshold"); - if (is_face_pair && - (RNA_property_is_set(op->ptr, prop) == false)) - { - angle_face_threshold = DEG2RADF(180.0f); - } - else { - angle_face_threshold = RNA_property_float_get(op->ptr, prop); - } - - prop = RNA_struct_find_property(op->ptr, "shape_threshold"); - if (is_face_pair && - (RNA_property_is_set(op->ptr, prop) == false)) - { - angle_shape_threshold = DEG2RADF(180.0f); - } - else { - angle_shape_threshold = RNA_property_float_get(op->ptr, prop); - } - - do_seam = RNA_boolean_get(op->ptr, "seam"); - do_sharp = RNA_boolean_get(op->ptr, "sharp"); - do_uvs = RNA_boolean_get(op->ptr, "uvs"); - do_vcols = RNA_boolean_get(op->ptr, "vcols"); - do_materials = RNA_boolean_get(op->ptr, "materials"); - - if (!EDBM_op_call_and_selectf( - em, op, - "faces.out", true, - "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f " - "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b", - BM_ELEM_SELECT, angle_face_threshold, angle_shape_threshold, - do_seam, do_sharp, do_uvs, do_vcols, do_materials)) - { - continue; - } - - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + bool is_face_pair; + + { + int totelem_sel[3]; + EDBM_mesh_stats_multi(objects, objects_len, NULL, totelem_sel); + is_face_pair = (totelem_sel[2] == 2); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bool do_seam, do_sharp, do_uvs, do_vcols, do_materials; + float angle_face_threshold, angle_shape_threshold; + PropertyRNA *prop; + + /* When joining exactly 2 faces, no limit. + * this is useful for one off joins while editing. */ + prop = RNA_struct_find_property(op->ptr, "face_threshold"); + if (is_face_pair && (RNA_property_is_set(op->ptr, prop) == false)) { + angle_face_threshold = DEG2RADF(180.0f); + } + else { + angle_face_threshold = RNA_property_float_get(op->ptr, prop); + } + + prop = RNA_struct_find_property(op->ptr, "shape_threshold"); + if (is_face_pair && (RNA_property_is_set(op->ptr, prop) == false)) { + angle_shape_threshold = DEG2RADF(180.0f); + } + else { + angle_shape_threshold = RNA_property_float_get(op->ptr, prop); + } + + do_seam = RNA_boolean_get(op->ptr, "seam"); + do_sharp = RNA_boolean_get(op->ptr, "sharp"); + do_uvs = RNA_boolean_get(op->ptr, "uvs"); + do_vcols = RNA_boolean_get(op->ptr, "vcols"); + do_materials = RNA_boolean_get(op->ptr, "materials"); + + if (!EDBM_op_call_and_selectf( + em, + op, + "faces.out", + true, + "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f " + "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b", + BM_ELEM_SELECT, + angle_face_threshold, + angle_shape_threshold, + do_seam, + do_sharp, + do_uvs, + do_vcols, + do_materials)) { + continue; + } + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } static void join_triangle_props(wmOperatorType *ot) { - PropertyRNA *prop; - - prop = RNA_def_float_rotation( - ot->srna, "face_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f), - "Max Face Angle", "Face angle limit", 0.0f, DEG2RADF(180.0f)); - RNA_def_property_float_default(prop, DEG2RADF(40.0f)); - - prop = RNA_def_float_rotation( - ot->srna, "shape_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f), - "Max Shape Angle", "Shape angle limit", 0.0f, DEG2RADF(180.0f)); - RNA_def_property_float_default(prop, DEG2RADF(40.0f)); - - RNA_def_boolean(ot->srna, "uvs", false, "Compare UVs", ""); - RNA_def_boolean(ot->srna, "vcols", false, "Compare VCols", ""); - RNA_def_boolean(ot->srna, "seam", false, "Compare Seam", ""); - RNA_def_boolean(ot->srna, "sharp", false, "Compare Sharp", ""); - RNA_def_boolean(ot->srna, "materials", false, "Compare Materials", ""); + PropertyRNA *prop; + + prop = RNA_def_float_rotation(ot->srna, + "face_threshold", + 0, + NULL, + 0.0f, + DEG2RADF(180.0f), + "Max Face Angle", + "Face angle limit", + 0.0f, + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(40.0f)); + + prop = RNA_def_float_rotation(ot->srna, + "shape_threshold", + 0, + NULL, + 0.0f, + DEG2RADF(180.0f), + "Max Shape Angle", + "Shape angle limit", + 0.0f, + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(40.0f)); + + RNA_def_boolean(ot->srna, "uvs", false, "Compare UVs", ""); + RNA_def_boolean(ot->srna, "vcols", false, "Compare VCols", ""); + RNA_def_boolean(ot->srna, "seam", false, "Compare Seam", ""); + RNA_def_boolean(ot->srna, "sharp", false, "Compare Sharp", ""); + RNA_def_boolean(ot->srna, "materials", false, "Compare Materials", ""); } void MESH_OT_tris_convert_to_quads(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Tris to Quads"; - ot->idname = "MESH_OT_tris_convert_to_quads"; - ot->description = "Join triangles into quads"; + /* identifiers */ + ot->name = "Tris to Quads"; + ot->idname = "MESH_OT_tris_convert_to_quads"; + ot->description = "Join triangles into quads"; - /* api callbacks */ - ot->exec = edbm_tris_convert_to_quads_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_tris_convert_to_quads_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - join_triangle_props(ot); + join_triangle_props(ot); } /** \} */ @@ -4877,187 +5129,192 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot) static int edbm_decimate_exec(bContext *C, wmOperator *op) { - const float ratio = RNA_float_get(op->ptr, "ratio"); - bool use_vertex_group = RNA_boolean_get(op->ptr, "use_vertex_group"); - const float vertex_group_factor = RNA_float_get(op->ptr, "vertex_group_factor"); - const bool invert_vertex_group = RNA_boolean_get(op->ptr, "invert_vertex_group"); - const bool use_symmetry = RNA_boolean_get(op->ptr, "use_symmetry"); - const float symmetry_eps = 0.00002f; - const int symmetry_axis = use_symmetry ? RNA_enum_get(op->ptr, "symmetry_axis") : -1; - - /* nop */ - if (ratio == 1.0f) { - return OPERATOR_FINISHED; - } - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - if (bm->totedgesel == 0) { - continue; - } - - float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__); - { - const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - const int defbase_act = obedit->actdef - 1; - - if (use_vertex_group && (cd_dvert_offset == -1)) { - BKE_report(op->reports, RPT_WARNING, "No active vertex group"); - use_vertex_group = false; - } - - BMIter iter; - BMVert *v; - int i; - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - float weight = 0.0f; - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - if (use_vertex_group) { - const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset); - weight = defvert_find_weight(dv, defbase_act); - if (invert_vertex_group) { - weight = 1.0f - weight; - } - } - else { - weight = 1.0f; - } - } - - vweights[i] = weight; - BM_elem_index_set(v, i); /* set_inline */ - } - bm->elem_index_dirty &= ~BM_VERT; - } - - float ratio_adjust; - - if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) { - ratio_adjust = ratio; - } - else { - /** - * Calculate a new ratio based on faces that could be removed during decimation. - * needed so 0..1 has a meaningful range when operating on the selection. - * - * This doesn't have to be totally accurate, - * but needs to be greater than the number of selected faces - */ - - int totface_basis = 0; - int totface_adjacent = 0; - BMIter iter; - BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - /* count faces during decimation, ngons are triangulated */ - const int f_len = f->len > 4 ? (f->len - 2) : 1; - totface_basis += f_len; - - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (vweights[BM_elem_index_get(l_iter->v)] != 0.0f) { - totface_adjacent += f_len; - break; - } - } while ((l_iter = l_iter->next) != l_first); - } - - ratio_adjust = ratio; - ratio_adjust = 1.0f - ratio_adjust; - ratio_adjust *= (float)totface_adjacent / (float)totface_basis; - ratio_adjust = 1.0f - ratio_adjust; - } - - BM_mesh_decimate_collapse( - em->bm, ratio_adjust, vweights, vertex_group_factor, false, - symmetry_axis, symmetry_eps); - - MEM_freeN(vweights); - - { - short selectmode = em->selectmode; - if ((selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) { - /* ensure we flush edges -> faces */ - selectmode |= SCE_SELECT_EDGE; - } - EDBM_selectmode_flush_ex(em, selectmode); - } - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const float ratio = RNA_float_get(op->ptr, "ratio"); + bool use_vertex_group = RNA_boolean_get(op->ptr, "use_vertex_group"); + const float vertex_group_factor = RNA_float_get(op->ptr, "vertex_group_factor"); + const bool invert_vertex_group = RNA_boolean_get(op->ptr, "invert_vertex_group"); + const bool use_symmetry = RNA_boolean_get(op->ptr, "use_symmetry"); + const float symmetry_eps = 0.00002f; + const int symmetry_axis = use_symmetry ? RNA_enum_get(op->ptr, "symmetry_axis") : -1; + + /* nop */ + if (ratio == 1.0f) { + return OPERATOR_FINISHED; + } + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + if (bm->totedgesel == 0) { + continue; + } + + float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__); + { + const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); + const int defbase_act = obedit->actdef - 1; + + if (use_vertex_group && (cd_dvert_offset == -1)) { + BKE_report(op->reports, RPT_WARNING, "No active vertex group"); + use_vertex_group = false; + } + + BMIter iter; + BMVert *v; + int i; + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + float weight = 0.0f; + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + if (use_vertex_group) { + const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset); + weight = defvert_find_weight(dv, defbase_act); + if (invert_vertex_group) { + weight = 1.0f - weight; + } + } + else { + weight = 1.0f; + } + } + + vweights[i] = weight; + BM_elem_index_set(v, i); /* set_inline */ + } + bm->elem_index_dirty &= ~BM_VERT; + } + + float ratio_adjust; + + if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) { + ratio_adjust = ratio; + } + else { + /** + * Calculate a new ratio based on faces that could be removed during decimation. + * needed so 0..1 has a meaningful range when operating on the selection. + * + * This doesn't have to be totally accurate, + * but needs to be greater than the number of selected faces + */ + + int totface_basis = 0; + int totface_adjacent = 0; + BMIter iter; + BMFace *f; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + /* count faces during decimation, ngons are triangulated */ + const int f_len = f->len > 4 ? (f->len - 2) : 1; + totface_basis += f_len; + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (vweights[BM_elem_index_get(l_iter->v)] != 0.0f) { + totface_adjacent += f_len; + break; + } + } while ((l_iter = l_iter->next) != l_first); + } + + ratio_adjust = ratio; + ratio_adjust = 1.0f - ratio_adjust; + ratio_adjust *= (float)totface_adjacent / (float)totface_basis; + ratio_adjust = 1.0f - ratio_adjust; + } + + BM_mesh_decimate_collapse( + em->bm, ratio_adjust, vweights, vertex_group_factor, false, symmetry_axis, symmetry_eps); + + MEM_freeN(vweights); + + { + short selectmode = em->selectmode; + if ((selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) { + /* ensure we flush edges -> faces */ + selectmode |= SCE_SELECT_EDGE; + } + EDBM_selectmode_flush_ex(em, selectmode); + } + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } - static bool edbm_decimate_check(bContext *UNUSED(C), wmOperator *UNUSED(op)) { - return true; + return true; } - static void edbm_decimate_ui(bContext *UNUSED(C), wmOperator *op) { - uiLayout *layout = op->layout, *box, *row, *col; - PointerRNA ptr; + uiLayout *layout = op->layout, *box, *row, *col; + PointerRNA ptr; - RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); - uiItemR(layout, &ptr, "ratio", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "ratio", 0, NULL, ICON_NONE); - box = uiLayoutBox(layout); - uiItemR(box, &ptr, "use_vertex_group", 0, NULL, ICON_NONE); - col = uiLayoutColumn(box, false); - uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_vertex_group")); - uiItemR(col, &ptr, "vertex_group_factor", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "invert_vertex_group", 0, NULL, ICON_NONE); + box = uiLayoutBox(layout); + uiItemR(box, &ptr, "use_vertex_group", 0, NULL, ICON_NONE); + col = uiLayoutColumn(box, false); + uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_vertex_group")); + uiItemR(col, &ptr, "vertex_group_factor", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "invert_vertex_group", 0, NULL, ICON_NONE); - box = uiLayoutBox(layout); - uiItemR(box, &ptr, "use_symmetry", 0, NULL, ICON_NONE); - row = uiLayoutRow(box, true); - uiLayoutSetActive(row, RNA_boolean_get(&ptr, "use_symmetry")); - uiItemR(row, &ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + box = uiLayoutBox(layout); + uiItemR(box, &ptr, "use_symmetry", 0, NULL, ICON_NONE); + row = uiLayoutRow(box, true); + uiLayoutSetActive(row, RNA_boolean_get(&ptr, "use_symmetry")); + uiItemR(row, &ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE); } - void MESH_OT_decimate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Decimate Geometry"; - ot->idname = "MESH_OT_decimate"; - ot->description = "Simplify geometry by collapsing edges"; - - /* api callbacks */ - ot->exec = edbm_decimate_exec; - ot->check = edbm_decimate_check; - ot->ui = edbm_decimate_ui; - ot->poll = ED_operator_editmesh; - - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* Note, keep in sync with 'rna_def_modifier_decimate' */ - RNA_def_float(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f); - - RNA_def_boolean(ot->srna, "use_vertex_group", false, "Vertex Group", - "Use active vertex group as an influence"); - RNA_def_float(ot->srna, "vertex_group_factor", 1.0f, 0.0f, 1000.0f, "Weight", - "Vertex group strength", 0.0f, 10.0f); - RNA_def_boolean(ot->srna, "invert_vertex_group", false, "Invert", - "Invert vertex group influence"); - - RNA_def_boolean(ot->srna, "use_symmetry", false, "Symmetry", - "Maintain symmetry on an axis"); - - RNA_def_enum(ot->srna, "symmetry_axis", rna_enum_axis_xyz_items, 1, "Axis", "Axis of symmetry"); + /* identifiers */ + ot->name = "Decimate Geometry"; + ot->idname = "MESH_OT_decimate"; + ot->description = "Simplify geometry by collapsing edges"; + + /* api callbacks */ + ot->exec = edbm_decimate_exec; + ot->check = edbm_decimate_check; + ot->ui = edbm_decimate_ui; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Note, keep in sync with 'rna_def_modifier_decimate' */ + RNA_def_float(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f); + + RNA_def_boolean(ot->srna, + "use_vertex_group", + false, + "Vertex Group", + "Use active vertex group as an influence"); + RNA_def_float(ot->srna, + "vertex_group_factor", + 1.0f, + 0.0f, + 1000.0f, + "Weight", + "Vertex group strength", + 0.0f, + 10.0f); + RNA_def_boolean( + ot->srna, "invert_vertex_group", false, "Invert", "Invert vertex group influence"); + + RNA_def_boolean(ot->srna, "use_symmetry", false, "Symmetry", "Maintain symmetry on an axis"); + + RNA_def_enum(ot->srna, "symmetry_axis", rna_enum_axis_xyz_items, 1, "Axis", "Axis of symmetry"); } /** \} */ @@ -5068,73 +5325,81 @@ void MESH_OT_decimate(wmOperatorType *ot) static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag) { - PropertyRNA *prop; + PropertyRNA *prop; - prop = RNA_def_boolean(ot->srna, "use_verts", value, "Dissolve Verts", - "Dissolve remaining vertices"); + prop = RNA_def_boolean( + ot->srna, "use_verts", value, "Dissolve Verts", "Dissolve remaining vertices"); - if (flag) { - RNA_def_property_flag(prop, flag); - } + if (flag) { + RNA_def_property_flag(prop, flag); + } } static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot) { - RNA_def_boolean(ot->srna, "use_face_split", false, "Face Split", - "Split off face corners to maintain surrounding geometry"); + RNA_def_boolean(ot->srna, + "use_face_split", + false, + "Face Split", + "Split off face corners to maintain surrounding geometry"); } static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot) { - RNA_def_boolean(ot->srna, "use_boundary_tear", false, "Tear Boundary", - "Split off face corners instead of merging faces"); + RNA_def_boolean(ot->srna, + "use_boundary_tear", + false, + "Tear Boundary", + "Split off face corners instead of merging faces"); } static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op) { - const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); - const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear"); + const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); + const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel == 0) { - continue; - } + if (em->bm->totvertsel == 0) { + continue; + } - if (!EDBM_op_callf( - em, op, - "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", - BM_ELEM_SELECT, use_face_split, use_boundary_tear)) - { - continue; - } - EDBM_update_generic(em, true, true); - } + if (!EDBM_op_callf(em, + op, + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_SELECT, + use_face_split, + use_boundary_tear)) { + continue; + } + EDBM_update_generic(em, true, true); + } - MEM_freeN(objects); - return OPERATOR_FINISHED; + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_dissolve_verts(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Dissolve Vertices"; - ot->description = "Dissolve verts, merge edges and faces"; - ot->idname = "MESH_OT_dissolve_verts"; + /* identifiers */ + ot->name = "Dissolve Vertices"; + ot->description = "Dissolve verts, merge edges and faces"; + ot->idname = "MESH_OT_dissolve_verts"; - /* api callbacks */ - ot->exec = edbm_dissolve_verts_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_dissolve_verts_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - edbm_dissolve_prop__use_face_split(ot); - edbm_dissolve_prop__use_boundary_tear(ot); + edbm_dissolve_prop__use_face_split(ot); + edbm_dissolve_prop__use_boundary_tear(ot); } /** \} */ @@ -5145,52 +5410,54 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot) static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op) { - const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); - const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); + const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); + const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totedgesel == 0) { - continue; - } + if (em->bm->totedgesel == 0) { + continue; + } - if (!EDBM_op_callf( - em, op, - "dissolve_edges edges=%he use_verts=%b use_face_split=%b", - BM_ELEM_SELECT, use_verts, use_face_split)) - { - continue; - } + if (!EDBM_op_callf(em, + op, + "dissolve_edges edges=%he use_verts=%b use_face_split=%b", + BM_ELEM_SELECT, + use_verts, + use_face_split)) { + continue; + } - EDBM_update_generic(em, true, true); - } + EDBM_update_generic(em, true, true); + } - MEM_freeN(objects); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_dissolve_edges(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Dissolve Edges"; - ot->description = "Dissolve edges, merging faces"; - ot->idname = "MESH_OT_dissolve_edges"; + /* identifiers */ + ot->name = "Dissolve Edges"; + ot->description = "Dissolve edges, merging faces"; + ot->idname = "MESH_OT_dissolve_edges"; - /* api callbacks */ - ot->exec = edbm_dissolve_edges_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_dissolve_edges_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - edbm_dissolve_prop__use_verts(ot, true, 0); - edbm_dissolve_prop__use_face_split(ot); + edbm_dissolve_prop__use_verts(ot, true, 0); + edbm_dissolve_prop__use_face_split(ot); } /** \} */ @@ -5201,49 +5468,51 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot) static int edbm_dissolve_faces_exec(bContext *C, wmOperator *op) { - const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - if (!EDBM_op_call_and_selectf( - em, op, - "region.out", true, - "dissolve_faces faces=%hf use_verts=%b", - BM_ELEM_SELECT, use_verts)) - { - continue; - } + if (!EDBM_op_call_and_selectf(em, + op, + "region.out", + true, + "dissolve_faces faces=%hf use_verts=%b", + BM_ELEM_SELECT, + use_verts)) { + continue; + } - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_dissolve_faces(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Dissolve Faces"; - ot->description = "Dissolve faces"; - ot->idname = "MESH_OT_dissolve_faces"; + /* identifiers */ + ot->name = "Dissolve Faces"; + ot->description = "Dissolve faces"; + ot->idname = "MESH_OT_dissolve_faces"; - /* api callbacks */ - ot->exec = edbm_dissolve_faces_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_dissolve_faces_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - edbm_dissolve_prop__use_verts(ot, false, 0); + edbm_dissolve_prop__use_verts(ot, false, 0); } /** \} */ @@ -5254,46 +5523,46 @@ void MESH_OT_dissolve_faces(wmOperatorType *ot) static int edbm_dissolve_mode_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - PropertyRNA *prop; - - prop = RNA_struct_find_property(op->ptr, "use_verts"); - if (!RNA_property_is_set(op->ptr, prop)) { - /* always enable in edge-mode */ - if ((em->selectmode & SCE_SELECT_FACE) == 0) { - RNA_property_boolean_set(op->ptr, prop, true); - } - } - - if (em->selectmode & SCE_SELECT_VERTEX) { - return edbm_dissolve_verts_exec(C, op); - } - else if (em->selectmode & SCE_SELECT_EDGE) { - return edbm_dissolve_edges_exec(C, op); - } - else { - return edbm_dissolve_faces_exec(C, op); - } + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + PropertyRNA *prop; + + prop = RNA_struct_find_property(op->ptr, "use_verts"); + if (!RNA_property_is_set(op->ptr, prop)) { + /* always enable in edge-mode */ + if ((em->selectmode & SCE_SELECT_FACE) == 0) { + RNA_property_boolean_set(op->ptr, prop, true); + } + } + + if (em->selectmode & SCE_SELECT_VERTEX) { + return edbm_dissolve_verts_exec(C, op); + } + else if (em->selectmode & SCE_SELECT_EDGE) { + return edbm_dissolve_edges_exec(C, op); + } + else { + return edbm_dissolve_faces_exec(C, op); + } } void MESH_OT_dissolve_mode(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Dissolve Selection"; - ot->description = "Dissolve geometry based on the selection mode"; - ot->idname = "MESH_OT_dissolve_mode"; + /* identifiers */ + ot->name = "Dissolve Selection"; + ot->description = "Dissolve geometry based on the selection mode"; + ot->idname = "MESH_OT_dissolve_mode"; - /* api callbacks */ - ot->exec = edbm_dissolve_mode_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_dissolve_mode_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - edbm_dissolve_prop__use_verts(ot, false, PROP_SKIP_SAVE); - edbm_dissolve_prop__use_face_split(ot); - edbm_dissolve_prop__use_boundary_tear(ot); + edbm_dissolve_prop__use_verts(ot, false, PROP_SKIP_SAVE); + edbm_dissolve_prop__use_face_split(ot); + edbm_dissolve_prop__use_boundary_tear(ot); } /** \} */ @@ -5304,92 +5573,113 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot) static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op) { - const float angle_limit = RNA_float_get(op->ptr, "angle_limit"); - const bool use_dissolve_boundaries = RNA_boolean_get(op->ptr, "use_dissolve_boundaries"); - const int delimit = RNA_enum_get(op->ptr, "delimit"); - char dissolve_flag; - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if ((bm->totvertsel == 0) && - (bm->totedgesel == 0) && - (bm->totfacesel == 0)) - { - continue; - } - - if (em->selectmode == SCE_SELECT_FACE) { - /* flush selection to tags and untag edges/verts with partially selected faces */ - BMIter iter; - BMIter liter; - - BMElem *ele; - BMFace *f; - BMLoop *l; - - BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_set(ele, BM_ELEM_TAG, BM_elem_flag_test(ele, BM_ELEM_SELECT)); - } - BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(ele, BM_ELEM_TAG, BM_elem_flag_test(ele, BM_ELEM_SELECT)); - } - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BM_elem_flag_disable(l->v, BM_ELEM_TAG); - BM_elem_flag_disable(l->e, BM_ELEM_TAG); - } - } - } - - dissolve_flag = BM_ELEM_TAG; - } - else { - dissolve_flag = BM_ELEM_SELECT; - } - - EDBM_op_call_and_selectf( - em, op, "region.out", true, - "dissolve_limit edges=%he verts=%hv angle_limit=%f use_dissolve_boundaries=%b delimit=%i", - dissolve_flag, dissolve_flag, angle_limit, use_dissolve_boundaries, delimit); - - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const float angle_limit = RNA_float_get(op->ptr, "angle_limit"); + const bool use_dissolve_boundaries = RNA_boolean_get(op->ptr, "use_dissolve_boundaries"); + const int delimit = RNA_enum_get(op->ptr, "delimit"); + char dissolve_flag; + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) { + continue; + } + + if (em->selectmode == SCE_SELECT_FACE) { + /* flush selection to tags and untag edges/verts with partially selected faces */ + BMIter iter; + BMIter liter; + + BMElem *ele; + BMFace *f; + BMLoop *l; + + BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_set(ele, BM_ELEM_TAG, BM_elem_flag_test(ele, BM_ELEM_SELECT)); + } + BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(ele, BM_ELEM_TAG, BM_elem_flag_test(ele, BM_ELEM_SELECT)); + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l->v, BM_ELEM_TAG); + BM_elem_flag_disable(l->e, BM_ELEM_TAG); + } + } + } + + dissolve_flag = BM_ELEM_TAG; + } + else { + dissolve_flag = BM_ELEM_SELECT; + } + + EDBM_op_call_and_selectf( + em, + op, + "region.out", + true, + "dissolve_limit edges=%he verts=%hv angle_limit=%f use_dissolve_boundaries=%b delimit=%i", + dissolve_flag, + dissolve_flag, + angle_limit, + use_dissolve_boundaries, + delimit); + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_dissolve_limited(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Limited Dissolve"; - ot->idname = "MESH_OT_dissolve_limited"; - ot->description = "Dissolve selected edges and verts, limited by the angle of surrounding geometry"; - - /* api callbacks */ - ot->exec = edbm_dissolve_limited_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f), - "Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f)); - RNA_def_property_float_default(prop, DEG2RADF(5.0f)); - RNA_def_boolean(ot->srna, "use_dissolve_boundaries", false, "All Boundaries", - "Dissolve all vertices inbetween face boundaries"); - RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_NORMAL, "Delimit", - "Delimit dissolve operation"); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Limited Dissolve"; + ot->idname = "MESH_OT_dissolve_limited"; + ot->description = + "Dissolve selected edges and verts, limited by the angle of surrounding geometry"; + + /* api callbacks */ + ot->exec = edbm_dissolve_limited_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_float_rotation(ot->srna, + "angle_limit", + 0, + NULL, + 0.0f, + DEG2RADF(180.0f), + "Max Angle", + "Angle limit", + 0.0f, + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(5.0f)); + RNA_def_boolean(ot->srna, + "use_dissolve_boundaries", + false, + "All Boundaries", + "Dissolve all vertices inbetween face boundaries"); + RNA_def_enum_flag(ot->srna, + "delimit", + rna_enum_mesh_delimit_mode_items, + BMO_DELIM_NORMAL, + "Delimit", + "Delimit dissolve operation"); } /** \} */ @@ -5400,69 +5690,73 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot) static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - int totelem_old[3] = {0, 0, 0}; - int totelem_new[3] = {0, 0, 0}; + ViewLayer *view_layer = CTX_data_view_layer(C); + int totelem_old[3] = {0, 0, 0}; + int totelem_new[3] = {0, 0, 0}; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - totelem_old[0] += bm->totvert; - totelem_old[1] += bm->totedge; - totelem_old[2] += bm->totface; - } /* objects */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + totelem_old[0] += bm->totvert; + totelem_old[1] += bm->totedge; + totelem_old[2] += bm->totface; + } /* objects */ - const float thresh = RNA_float_get(op->ptr, "threshold"); + const float thresh = RNA_float_get(op->ptr, "threshold"); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; - if (!EDBM_op_callf( - em, op, - "dissolve_degenerate edges=%he dist=%f", - BM_ELEM_SELECT, thresh)) - { - return OPERATOR_CANCELLED; - } + if (!EDBM_op_callf(em, op, "dissolve_degenerate edges=%he dist=%f", BM_ELEM_SELECT, thresh)) { + return OPERATOR_CANCELLED; + } - /* tricky to maintain correct selection here, so just flush up from verts */ - EDBM_select_flush(em); + /* tricky to maintain correct selection here, so just flush up from verts */ + EDBM_select_flush(em); - EDBM_update_generic(em, true, true); + EDBM_update_generic(em, true, true); - totelem_new[0] += bm->totvert; - totelem_new[1] += bm->totedge; - totelem_new[2] += bm->totface; - } - MEM_freeN(objects); + totelem_new[0] += bm->totvert; + totelem_new[1] += bm->totedge; + totelem_new[2] += bm->totface; + } + MEM_freeN(objects); - edbm_report_delete_info(op->reports, totelem_old, totelem_new); + edbm_report_delete_info(op->reports, totelem_old, totelem_new); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_dissolve_degenerate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Degenerate Dissolve"; - ot->idname = "MESH_OT_dissolve_degenerate"; - ot->description = "Dissolve zero area faces and zero length edges"; + /* identifiers */ + ot->name = "Degenerate Dissolve"; + ot->idname = "MESH_OT_dissolve_degenerate"; + ot->description = "Dissolve zero area faces and zero length edges"; - /* api callbacks */ - ot->exec = edbm_dissolve_degenerate_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_dissolve_degenerate_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_float_distance(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance", - "Minimum distance between elements to merge", 1e-5f, 10.0f); + RNA_def_float_distance(ot->srna, + "threshold", + 1e-4f, + 1e-6f, + 50.0f, + "Merge Distance", + "Minimum distance between elements to merge", + 1e-5f, + 10.0f); } /** \} */ @@ -5474,71 +5768,76 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot) /* internally uses dissolve */ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op) { - const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); - ViewLayer *view_layer = CTX_data_view_layer(C); + const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); + ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totedgesel == 0) { - continue; - } + if (em->bm->totedgesel == 0) { + continue; + } - /* deal with selection */ - { - BMEdge *e; - BMIter iter; + /* deal with selection */ + { + BMEdge *e; + BMIter iter; - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) { - BMLoop *l_iter = e->l; - do { - BM_elem_flag_enable(l_iter->f, BM_ELEM_TAG); - } while ((l_iter = l_iter->radial_next) != e->l); - } - } - } + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) { + BMLoop *l_iter = e->l; + do { + BM_elem_flag_enable(l_iter->f, BM_ELEM_TAG); + } while ((l_iter = l_iter->radial_next) != e->l); + } + } + } - if (!EDBM_op_callf( - em, op, - "dissolve_edges edges=%he use_verts=%b use_face_split=%b", - BM_ELEM_SELECT, true, use_face_split)) - { - continue; - } + if (!EDBM_op_callf(em, + op, + "dissolve_edges edges=%he use_verts=%b use_face_split=%b", + BM_ELEM_SELECT, + true, + use_face_split)) { + continue; + } - BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); + BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); - EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); - EDBM_update_generic(em, true, true); - } + EDBM_update_generic(em, true, true); + } - MEM_freeN(objects); - return OPERATOR_FINISHED; + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_delete_edgeloop(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Edge Loop"; - ot->description = "Delete an edge loop by merging the faces on each side"; - ot->idname = "MESH_OT_delete_edgeloop"; + /* identifiers */ + ot->name = "Delete Edge Loop"; + ot->description = "Delete an edge loop by merging the faces on each side"; + ot->idname = "MESH_OT_delete_edgeloop"; - /* api callbacks */ - ot->exec = edbm_delete_edgeloop_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_delete_edgeloop_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "use_face_split", true, "Face Split", - "Split off face corners to maintain surrounding geometry"); + RNA_def_boolean(ot->srna, + "use_face_split", + true, + "Face Split", + "Split off face corners to maintain surrounding geometry"); } /** \} */ @@ -5549,51 +5848,50 @@ void MESH_OT_delete_edgeloop(wmOperatorType *ot) static int edbm_split_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if ((em->bm->totvertsel == 0) && - (em->bm->totedgesel == 0) && - (em->bm->totfacesel == 0)) - { - continue; - } - BMOperator bmop; - EDBM_op_init(em, &bmop, op, "split geom=%hvef use_only_faces=%b", BM_ELEM_SELECT, false); - BMO_op_exec(em->bm, &bmop); - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); - - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - - /* Geometry has changed, need to recalc normals and looptris */ - EDBM_mesh_normals_update(em); - - EDBM_update_generic(em, true, true); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) { + continue; + } + BMOperator bmop; + EDBM_op_init(em, &bmop, op, "split geom=%hvef use_only_faces=%b", BM_ELEM_SELECT, false); + BMO_op_exec(em->bm, &bmop); + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + /* Geometry has changed, need to recalc normals and looptris */ + EDBM_mesh_normals_update(em); + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_split(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Split"; - ot->idname = "MESH_OT_split"; - ot->description = "Split off selected geometry from connected unselected geometry"; + /* identifiers */ + ot->name = "Split"; + ot->idname = "MESH_OT_split"; + ot->description = "Split off selected geometry from connected unselected geometry"; - /* api callbacks */ - ot->exec = edbm_split_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_split_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -5606,603 +5904,631 @@ void MESH_OT_split(wmOperatorType *ot) * \{ */ enum { - SRT_VIEW_ZAXIS = 1, /* Use view Z (deep) axis. */ - SRT_VIEW_XAXIS, /* Use view X (left to right) axis. */ - SRT_CURSOR_DISTANCE, /* Use distance from element to 3D cursor. */ - SRT_MATERIAL, /* Face only: use mat number. */ - SRT_SELECTED, /* Move selected elements in first, without modifying - * relative order of selected and unselected elements. */ - SRT_RANDOMIZE, /* Randomize selected elements. */ - SRT_REVERSE, /* Reverse current order of selected elements. */ + SRT_VIEW_ZAXIS = 1, /* Use view Z (deep) axis. */ + SRT_VIEW_XAXIS, /* Use view X (left to right) axis. */ + SRT_CURSOR_DISTANCE, /* Use distance from element to 3D cursor. */ + SRT_MATERIAL, /* Face only: use mat number. */ + SRT_SELECTED, /* Move selected elements in first, without modifying + * relative order of selected and unselected elements. */ + SRT_RANDOMIZE, /* Randomize selected elements. */ + SRT_REVERSE, /* Reverse current order of selected elements. */ }; typedef struct BMElemSort { - float srt; /* Sort factor */ - int org_idx; /* Original index of this element _in its mempool_ */ + float srt; /* Sort factor */ + int org_idx; /* Original index of this element _in its mempool_ */ } BMElemSort; static int bmelemsort_comp(const void *v1, const void *v2) { - const BMElemSort *x1 = v1, *x2 = v2; + const BMElemSort *x1 = v1, *x2 = v2; - return (x1->srt > x2->srt) - (x1->srt < x2->srt); + return (x1->srt > x2->srt) - (x1->srt < x2->srt); } /* Reorders vertices/edges/faces using a given methods. Loops are not supported. */ -static void sort_bmelem_flag( - bContext *C, - Scene *scene, Object *ob, - RegionView3D *rv3d, - const int types, const int flag, const int action, - const int reverse, const unsigned int seed) -{ - BMEditMesh *em = BKE_editmesh_from_object(ob); - - BMVert *ve; - BMEdge *ed; - BMFace *fa; - BMIter iter; - - /* In all five elements below, 0 = vertices, 1 = edges, 2 = faces. */ - /* Just to mark protected elements. */ - char *pblock[3] = {NULL, NULL, NULL}, *pb; - BMElemSort *sblock[3] = {NULL, NULL, NULL}, *sb; - unsigned int *map[3] = {NULL, NULL, NULL}, *mp; - int totelem[3] = {0, 0, 0}; - int affected[3] = {0, 0, 0}; - int i, j; - - if (!(types && flag && action)) - return; - - if (types & BM_VERT) - totelem[0] = em->bm->totvert; - if (types & BM_EDGE) - totelem[1] = em->bm->totedge; - if (types & BM_FACE) - totelem[2] = em->bm->totface; - - if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) { - float mat[4][4]; - float fact = reverse ? -1.0 : 1.0; - int coidx = (action == SRT_VIEW_ZAXIS) ? 2 : 0; - - /* Apply the view matrix to the object matrix. */ - mul_m4_m4m4(mat, rv3d->viewmat, ob->obmat); - - if (totelem[0]) { - pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); - sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock"); - - BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(ve, flag)) { - float co[3]; - mul_v3_m4v3(co, mat, ve->co); - - pb[i] = false; - sb[affected[0]].org_idx = i; - sb[affected[0]++].srt = co[coidx] * fact; - } - else { - pb[i] = true; - } - } - } - - if (totelem[1]) { - pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock"); - sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock"); - - BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { - if (BM_elem_flag_test(ed, flag)) { - float co[3]; - mid_v3_v3v3(co, ed->v1->co, ed->v2->co); - mul_m4_v3(mat, co); - - pb[i] = false; - sb[affected[1]].org_idx = i; - sb[affected[1]++].srt = co[coidx] * fact; - } - else { - pb[i] = true; - } - } - } - - if (totelem[2]) { - pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); - sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); - - BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { - if (BM_elem_flag_test(fa, flag)) { - float co[3]; - BM_face_calc_center_median(fa, co); - mul_m4_v3(mat, co); - - pb[i] = false; - sb[affected[2]].org_idx = i; - sb[affected[2]++].srt = co[coidx] * fact; - } - else { - pb[i] = true; - } - } - } - } - - else if (action == SRT_CURSOR_DISTANCE) { - float cur[3]; - float mat[4][4]; - float fact = reverse ? -1.0 : 1.0; - - copy_v3_v3(cur, scene->cursor.location); - - invert_m4_m4(mat, ob->obmat); - mul_m4_v3(mat, cur); - - if (totelem[0]) { - pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); - sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock"); - - BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(ve, flag)) { - pb[i] = false; - sb[affected[0]].org_idx = i; - sb[affected[0]++].srt = len_squared_v3v3(cur, ve->co) * fact; - } - else { - pb[i] = true; - } - } - } - - if (totelem[1]) { - pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock"); - sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock"); - - BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { - if (BM_elem_flag_test(ed, flag)) { - float co[3]; - mid_v3_v3v3(co, ed->v1->co, ed->v2->co); - - pb[i] = false; - sb[affected[1]].org_idx = i; - sb[affected[1]++].srt = len_squared_v3v3(cur, co) * fact; - } - else { - pb[i] = true; - } - } - } - - if (totelem[2]) { - pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); - sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); - - BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { - if (BM_elem_flag_test(fa, flag)) { - float co[3]; - BM_face_calc_center_median(fa, co); - - pb[i] = false; - sb[affected[2]].org_idx = i; - sb[affected[2]++].srt = len_squared_v3v3(cur, co) * fact; - } - else { - pb[i] = true; - } - } - } - } - - /* Faces only! */ - else if (action == SRT_MATERIAL && totelem[2]) { - pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); - sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); - - BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { - if (BM_elem_flag_test(fa, flag)) { - /* Reverse materials' order, not order of faces inside each mat! */ - /* Note: cannot use totcol, as mat_nr may sometimes be greater... */ - float srt = reverse ? (float)(MAXMAT - fa->mat_nr) : (float)fa->mat_nr; - pb[i] = false; - sb[affected[2]].org_idx = i; - /* Multiplying with totface and adding i ensures us - * we keep current order for all faces of same mat. */ - sb[affected[2]++].srt = srt * ((float)totelem[2]) + ((float)i); - // printf("e: %d; srt: %f; final: %f\n", - // i, srt, srt * ((float)totface) + ((float)i)); - } - else { - pb[i] = true; - } - } - } - - else if (action == SRT_SELECTED) { - unsigned int *tbuf[3] = {NULL, NULL, NULL}, *tb; - - if (totelem[0]) { - tb = tbuf[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert tbuf"); - mp = map[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert map"); - - BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(ve, flag)) { - mp[affected[0]++] = i; - } - else { - *tb = i; - tb++; - } - } - } - - if (totelem[1]) { - tb = tbuf[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge tbuf"); - mp = map[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge map"); - - BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { - if (BM_elem_flag_test(ed, flag)) { - mp[affected[1]++] = i; - } - else { - *tb = i; - tb++; - } - } - } - - if (totelem[2]) { - tb = tbuf[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face tbuf"); - mp = map[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face map"); - - BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { - if (BM_elem_flag_test(fa, flag)) { - mp[affected[2]++] = i; - } - else { - *tb = i; - tb++; - } - } - } - - for (j = 3; j--; ) { - int tot = totelem[j]; - int aff = affected[j]; - tb = tbuf[j]; - mp = map[j]; - if (!(tb && mp)) - continue; - if (ELEM(aff, 0, tot)) { - MEM_freeN(tb); - MEM_freeN(mp); - map[j] = NULL; - continue; - } - if (reverse) { - memcpy(tb + (tot - aff), mp, aff * sizeof(int)); - } - else { - memcpy(mp + aff, tb, (tot - aff) * sizeof(int)); - tb = mp; - mp = map[j] = tbuf[j]; - tbuf[j] = tb; - } - - /* Reverse mapping, we want an org2new one! */ - for (i = tot, tb = tbuf[j] + tot - 1; i--; tb--) { - mp[*tb] = i; - } - MEM_freeN(tbuf[j]); - } - } - - else if (action == SRT_RANDOMIZE) { - if (totelem[0]) { - /* Re-init random generator for each element type, to get consistent random when - * enabling/disabling an element type. */ - RNG *rng = BLI_rng_new_srandom(seed); - pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); - sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock"); - - BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(ve, flag)) { - pb[i] = false; - sb[affected[0]].org_idx = i; - sb[affected[0]++].srt = BLI_rng_get_float(rng); - } - else { - pb[i] = true; - } - } - - BLI_rng_free(rng); - } - - if (totelem[1]) { - RNG *rng = BLI_rng_new_srandom(seed); - pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock"); - sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock"); - - BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { - if (BM_elem_flag_test(ed, flag)) { - pb[i] = false; - sb[affected[1]].org_idx = i; - sb[affected[1]++].srt = BLI_rng_get_float(rng); - } - else { - pb[i] = true; - } - } - - BLI_rng_free(rng); - } - - if (totelem[2]) { - RNG *rng = BLI_rng_new_srandom(seed); - pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); - sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); - - BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { - if (BM_elem_flag_test(fa, flag)) { - pb[i] = false; - sb[affected[2]].org_idx = i; - sb[affected[2]++].srt = BLI_rng_get_float(rng); - } - else { - pb[i] = true; - } - } - - BLI_rng_free(rng); - } - } - - else if (action == SRT_REVERSE) { - if (totelem[0]) { - pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); - sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock"); - - BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(ve, flag)) { - pb[i] = false; - sb[affected[0]].org_idx = i; - sb[affected[0]++].srt = (float)-i; - } - else { - pb[i] = true; - } - } - } - - if (totelem[1]) { - pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock"); - sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock"); - - BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { - if (BM_elem_flag_test(ed, flag)) { - pb[i] = false; - sb[affected[1]].org_idx = i; - sb[affected[1]++].srt = (float)-i; - } - else { - pb[i] = true; - } - } - } - - if (totelem[2]) { - pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); - sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); - - BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { - if (BM_elem_flag_test(fa, flag)) { - pb[i] = false; - sb[affected[2]].org_idx = i; - sb[affected[2]++].srt = (float)-i; - } - else { - pb[i] = true; - } - } - } - } - -/* printf("%d vertices: %d to be affected...\n", totelem[0], affected[0]);*/ -/* printf("%d edges: %d to be affected...\n", totelem[1], affected[1]);*/ -/* printf("%d faces: %d to be affected...\n", totelem[2], affected[2]);*/ - if (affected[0] == 0 && affected[1] == 0 && affected[2] == 0) { - for (j = 3; j--; ) { - if (pblock[j]) - MEM_freeN(pblock[j]); - if (sblock[j]) - MEM_freeN(sblock[j]); - if (map[j]) - MEM_freeN(map[j]); - } - return; - } - - /* Sort affected elements, and populate mapping arrays, if needed. */ - for (j = 3; j--; ) { - pb = pblock[j]; - sb = sblock[j]; - if (pb && sb && !map[j]) { - const char *p_blk; - BMElemSort *s_blk; - int tot = totelem[j]; - int aff = affected[j]; - - qsort(sb, aff, sizeof(BMElemSort), bmelemsort_comp); - - mp = map[j] = MEM_mallocN(sizeof(int) * tot, "sort_bmelem map"); - p_blk = pb + tot - 1; - s_blk = sb + aff - 1; - for (i = tot; i--; p_blk--) { - if (*p_blk) { /* Protected! */ - mp[i] = i; - } - else { - mp[s_blk->org_idx] = i; - s_blk--; - } - } - } - if (pb) - MEM_freeN(pb); - if (sb) - MEM_freeN(sb); - } - - BM_mesh_remap(em->bm, map[0], map[1], map[2]); - DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - for (j = 3; j--; ) { - if (map[j]) - MEM_freeN(map[j]); - } +static void sort_bmelem_flag(bContext *C, + Scene *scene, + Object *ob, + RegionView3D *rv3d, + const int types, + const int flag, + const int action, + const int reverse, + const unsigned int seed) +{ + BMEditMesh *em = BKE_editmesh_from_object(ob); + + BMVert *ve; + BMEdge *ed; + BMFace *fa; + BMIter iter; + + /* In all five elements below, 0 = vertices, 1 = edges, 2 = faces. */ + /* Just to mark protected elements. */ + char *pblock[3] = {NULL, NULL, NULL}, *pb; + BMElemSort *sblock[3] = {NULL, NULL, NULL}, *sb; + unsigned int *map[3] = {NULL, NULL, NULL}, *mp; + int totelem[3] = {0, 0, 0}; + int affected[3] = {0, 0, 0}; + int i, j; + + if (!(types && flag && action)) + return; + + if (types & BM_VERT) + totelem[0] = em->bm->totvert; + if (types & BM_EDGE) + totelem[1] = em->bm->totedge; + if (types & BM_FACE) + totelem[2] = em->bm->totface; + + if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) { + float mat[4][4]; + float fact = reverse ? -1.0 : 1.0; + int coidx = (action == SRT_VIEW_ZAXIS) ? 2 : 0; + + /* Apply the view matrix to the object matrix. */ + mul_m4_m4m4(mat, rv3d->viewmat, ob->obmat); + + if (totelem[0]) { + pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); + sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock"); + + BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(ve, flag)) { + float co[3]; + mul_v3_m4v3(co, mat, ve->co); + + pb[i] = false; + sb[affected[0]].org_idx = i; + sb[affected[0]++].srt = co[coidx] * fact; + } + else { + pb[i] = true; + } + } + } + + if (totelem[1]) { + pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock"); + sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock"); + + BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { + if (BM_elem_flag_test(ed, flag)) { + float co[3]; + mid_v3_v3v3(co, ed->v1->co, ed->v2->co); + mul_m4_v3(mat, co); + + pb[i] = false; + sb[affected[1]].org_idx = i; + sb[affected[1]++].srt = co[coidx] * fact; + } + else { + pb[i] = true; + } + } + } + + if (totelem[2]) { + pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); + sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); + + BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(fa, flag)) { + float co[3]; + BM_face_calc_center_median(fa, co); + mul_m4_v3(mat, co); + + pb[i] = false; + sb[affected[2]].org_idx = i; + sb[affected[2]++].srt = co[coidx] * fact; + } + else { + pb[i] = true; + } + } + } + } + + else if (action == SRT_CURSOR_DISTANCE) { + float cur[3]; + float mat[4][4]; + float fact = reverse ? -1.0 : 1.0; + + copy_v3_v3(cur, scene->cursor.location); + + invert_m4_m4(mat, ob->obmat); + mul_m4_v3(mat, cur); + + if (totelem[0]) { + pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); + sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock"); + + BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(ve, flag)) { + pb[i] = false; + sb[affected[0]].org_idx = i; + sb[affected[0]++].srt = len_squared_v3v3(cur, ve->co) * fact; + } + else { + pb[i] = true; + } + } + } + + if (totelem[1]) { + pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock"); + sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock"); + + BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { + if (BM_elem_flag_test(ed, flag)) { + float co[3]; + mid_v3_v3v3(co, ed->v1->co, ed->v2->co); + + pb[i] = false; + sb[affected[1]].org_idx = i; + sb[affected[1]++].srt = len_squared_v3v3(cur, co) * fact; + } + else { + pb[i] = true; + } + } + } + + if (totelem[2]) { + pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); + sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); + + BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(fa, flag)) { + float co[3]; + BM_face_calc_center_median(fa, co); + + pb[i] = false; + sb[affected[2]].org_idx = i; + sb[affected[2]++].srt = len_squared_v3v3(cur, co) * fact; + } + else { + pb[i] = true; + } + } + } + } + + /* Faces only! */ + else if (action == SRT_MATERIAL && totelem[2]) { + pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); + sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); + + BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(fa, flag)) { + /* Reverse materials' order, not order of faces inside each mat! */ + /* Note: cannot use totcol, as mat_nr may sometimes be greater... */ + float srt = reverse ? (float)(MAXMAT - fa->mat_nr) : (float)fa->mat_nr; + pb[i] = false; + sb[affected[2]].org_idx = i; + /* Multiplying with totface and adding i ensures us + * we keep current order for all faces of same mat. */ + sb[affected[2]++].srt = srt * ((float)totelem[2]) + ((float)i); + // printf("e: %d; srt: %f; final: %f\n", + // i, srt, srt * ((float)totface) + ((float)i)); + } + else { + pb[i] = true; + } + } + } + + else if (action == SRT_SELECTED) { + unsigned int *tbuf[3] = {NULL, NULL, NULL}, *tb; + + if (totelem[0]) { + tb = tbuf[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert tbuf"); + mp = map[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert map"); + + BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(ve, flag)) { + mp[affected[0]++] = i; + } + else { + *tb = i; + tb++; + } + } + } + + if (totelem[1]) { + tb = tbuf[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge tbuf"); + mp = map[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge map"); + + BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { + if (BM_elem_flag_test(ed, flag)) { + mp[affected[1]++] = i; + } + else { + *tb = i; + tb++; + } + } + } + + if (totelem[2]) { + tb = tbuf[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face tbuf"); + mp = map[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face map"); + + BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(fa, flag)) { + mp[affected[2]++] = i; + } + else { + *tb = i; + tb++; + } + } + } + + for (j = 3; j--;) { + int tot = totelem[j]; + int aff = affected[j]; + tb = tbuf[j]; + mp = map[j]; + if (!(tb && mp)) + continue; + if (ELEM(aff, 0, tot)) { + MEM_freeN(tb); + MEM_freeN(mp); + map[j] = NULL; + continue; + } + if (reverse) { + memcpy(tb + (tot - aff), mp, aff * sizeof(int)); + } + else { + memcpy(mp + aff, tb, (tot - aff) * sizeof(int)); + tb = mp; + mp = map[j] = tbuf[j]; + tbuf[j] = tb; + } + + /* Reverse mapping, we want an org2new one! */ + for (i = tot, tb = tbuf[j] + tot - 1; i--; tb--) { + mp[*tb] = i; + } + MEM_freeN(tbuf[j]); + } + } + + else if (action == SRT_RANDOMIZE) { + if (totelem[0]) { + /* Re-init random generator for each element type, to get consistent random when + * enabling/disabling an element type. */ + RNG *rng = BLI_rng_new_srandom(seed); + pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); + sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock"); + + BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(ve, flag)) { + pb[i] = false; + sb[affected[0]].org_idx = i; + sb[affected[0]++].srt = BLI_rng_get_float(rng); + } + else { + pb[i] = true; + } + } + + BLI_rng_free(rng); + } + + if (totelem[1]) { + RNG *rng = BLI_rng_new_srandom(seed); + pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock"); + sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock"); + + BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { + if (BM_elem_flag_test(ed, flag)) { + pb[i] = false; + sb[affected[1]].org_idx = i; + sb[affected[1]++].srt = BLI_rng_get_float(rng); + } + else { + pb[i] = true; + } + } + + BLI_rng_free(rng); + } + + if (totelem[2]) { + RNG *rng = BLI_rng_new_srandom(seed); + pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); + sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); + + BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(fa, flag)) { + pb[i] = false; + sb[affected[2]].org_idx = i; + sb[affected[2]++].srt = BLI_rng_get_float(rng); + } + else { + pb[i] = true; + } + } + + BLI_rng_free(rng); + } + } + + else if (action == SRT_REVERSE) { + if (totelem[0]) { + pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); + sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock"); + + BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(ve, flag)) { + pb[i] = false; + sb[affected[0]].org_idx = i; + sb[affected[0]++].srt = (float)-i; + } + else { + pb[i] = true; + } + } + } + + if (totelem[1]) { + pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock"); + sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock"); + + BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) { + if (BM_elem_flag_test(ed, flag)) { + pb[i] = false; + sb[affected[1]].org_idx = i; + sb[affected[1]++].srt = (float)-i; + } + else { + pb[i] = true; + } + } + } + + if (totelem[2]) { + pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock"); + sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock"); + + BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(fa, flag)) { + pb[i] = false; + sb[affected[2]].org_idx = i; + sb[affected[2]++].srt = (float)-i; + } + else { + pb[i] = true; + } + } + } + } + + /* printf("%d vertices: %d to be affected...\n", totelem[0], affected[0]);*/ + /* printf("%d edges: %d to be affected...\n", totelem[1], affected[1]);*/ + /* printf("%d faces: %d to be affected...\n", totelem[2], affected[2]);*/ + if (affected[0] == 0 && affected[1] == 0 && affected[2] == 0) { + for (j = 3; j--;) { + if (pblock[j]) + MEM_freeN(pblock[j]); + if (sblock[j]) + MEM_freeN(sblock[j]); + if (map[j]) + MEM_freeN(map[j]); + } + return; + } + + /* Sort affected elements, and populate mapping arrays, if needed. */ + for (j = 3; j--;) { + pb = pblock[j]; + sb = sblock[j]; + if (pb && sb && !map[j]) { + const char *p_blk; + BMElemSort *s_blk; + int tot = totelem[j]; + int aff = affected[j]; + + qsort(sb, aff, sizeof(BMElemSort), bmelemsort_comp); + + mp = map[j] = MEM_mallocN(sizeof(int) * tot, "sort_bmelem map"); + p_blk = pb + tot - 1; + s_blk = sb + aff - 1; + for (i = tot; i--; p_blk--) { + if (*p_blk) { /* Protected! */ + mp[i] = i; + } + else { + mp[s_blk->org_idx] = i; + s_blk--; + } + } + } + if (pb) + MEM_freeN(pb); + if (sb) + MEM_freeN(sb); + } + + BM_mesh_remap(em->bm, map[0], map[1], map[2]); + DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + for (j = 3; j--;) { + if (map[j]) + MEM_freeN(map[j]); + } } static int edbm_sort_elements_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob_active = CTX_data_edit_object(C); - - /* may be NULL */ - RegionView3D *rv3d = ED_view3d_context_rv3d(C); - - const int action = RNA_enum_get(op->ptr, "type"); - PropertyRNA *prop_elem_types = RNA_struct_find_property(op->ptr, "elements"); - const bool use_reverse = RNA_boolean_get(op->ptr, "reverse"); - unsigned int seed = RNA_int_get(op->ptr, "seed"); - int elem_types = 0; - - if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) { - if (rv3d == NULL) { - BKE_report(op->reports, RPT_ERROR, "View not found, cannot sort by view axis"); - return OPERATOR_CANCELLED; - } - } - - /* If no elem_types set, use current selection mode to set it! */ - if (RNA_property_is_set(op->ptr, prop_elem_types)) { - elem_types = RNA_property_enum_get(op->ptr, prop_elem_types); - } - else { - BMEditMesh *em = BKE_editmesh_from_object(ob_active); - if (em->selectmode & SCE_SELECT_VERTEX) - elem_types |= BM_VERT; - if (em->selectmode & SCE_SELECT_EDGE) - elem_types |= BM_EDGE; - if (em->selectmode & SCE_SELECT_FACE) - elem_types |= BM_FACE; - RNA_enum_set(op->ptr, "elements", elem_types); - } - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - - if (!((elem_types & BM_VERT && bm->totvertsel > 0) || - (elem_types & BM_EDGE && bm->totedgesel > 0) || - (elem_types & BM_FACE && bm->totfacesel > 0))) - { - continue; - } - - int seed_iter = seed; - - /* This gives a consistent result regardless of object order */ - if (ob_index) { - seed_iter += BLI_ghashutil_strhash_p(ob->id.name); - } - - sort_bmelem_flag( - C, scene, ob, rv3d, - elem_types, BM_ELEM_SELECT, action, use_reverse, seed_iter); - } - MEM_freeN(objects); - return OPERATOR_FINISHED; -} - -static bool edbm_sort_elements_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) -{ - const char *prop_id = RNA_property_identifier(prop); - const int action = RNA_enum_get(op->ptr, "type"); - - /* Only show seed for randomize action! */ - if (STREQ(prop_id, "seed")) { - if (action == SRT_RANDOMIZE) - return true; - else - return false; - } - - /* Hide seed for reverse and randomize actions! */ - if (STREQ(prop_id, "reverse")) { - if (ELEM(action, SRT_RANDOMIZE, SRT_REVERSE)) - return false; - else - return true; - } - - return true; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob_active = CTX_data_edit_object(C); + + /* may be NULL */ + RegionView3D *rv3d = ED_view3d_context_rv3d(C); + + const int action = RNA_enum_get(op->ptr, "type"); + PropertyRNA *prop_elem_types = RNA_struct_find_property(op->ptr, "elements"); + const bool use_reverse = RNA_boolean_get(op->ptr, "reverse"); + unsigned int seed = RNA_int_get(op->ptr, "seed"); + int elem_types = 0; + + if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) { + if (rv3d == NULL) { + BKE_report(op->reports, RPT_ERROR, "View not found, cannot sort by view axis"); + return OPERATOR_CANCELLED; + } + } + + /* If no elem_types set, use current selection mode to set it! */ + if (RNA_property_is_set(op->ptr, prop_elem_types)) { + elem_types = RNA_property_enum_get(op->ptr, prop_elem_types); + } + else { + BMEditMesh *em = BKE_editmesh_from_object(ob_active); + if (em->selectmode & SCE_SELECT_VERTEX) + elem_types |= BM_VERT; + if (em->selectmode & SCE_SELECT_EDGE) + elem_types |= BM_EDGE; + if (em->selectmode & SCE_SELECT_FACE) + elem_types |= BM_FACE; + RNA_enum_set(op->ptr, "elements", elem_types); + } + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + + if (!((elem_types & BM_VERT && bm->totvertsel > 0) || + (elem_types & BM_EDGE && bm->totedgesel > 0) || + (elem_types & BM_FACE && bm->totfacesel > 0))) { + continue; + } + + int seed_iter = seed; + + /* This gives a consistent result regardless of object order */ + if (ob_index) { + seed_iter += BLI_ghashutil_strhash_p(ob->id.name); + } + + sort_bmelem_flag( + C, scene, ob, rv3d, elem_types, BM_ELEM_SELECT, action, use_reverse, seed_iter); + } + MEM_freeN(objects); + return OPERATOR_FINISHED; +} + +static bool edbm_sort_elements_poll_property(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + const int action = RNA_enum_get(op->ptr, "type"); + + /* Only show seed for randomize action! */ + if (STREQ(prop_id, "seed")) { + if (action == SRT_RANDOMIZE) + return true; + else + return false; + } + + /* Hide seed for reverse and randomize actions! */ + if (STREQ(prop_id, "reverse")) { + if (ELEM(action, SRT_RANDOMIZE, SRT_REVERSE)) + return false; + else + return true; + } + + return true; } void MESH_OT_sort_elements(wmOperatorType *ot) { - static const EnumPropertyItem type_items[] = { - {SRT_VIEW_ZAXIS, "VIEW_ZAXIS", 0, "View Z Axis", - "Sort selected elements from farthest to nearest one in current view"}, - {SRT_VIEW_XAXIS, "VIEW_XAXIS", 0, "View X Axis", - "Sort selected elements from left to right one in current view"}, - {SRT_CURSOR_DISTANCE, "CURSOR_DISTANCE", 0, "Cursor Distance", - "Sort selected elements from nearest to farthest from 3D cursor"}, - {SRT_MATERIAL, "MATERIAL", 0, "Material", - "Sort selected elements from smallest to greatest material index (faces only!)"}, - {SRT_SELECTED, "SELECTED", 0, "Selected", - "Move all selected elements in first places, preserving their relative order " - "(WARNING: this will affect unselected elements' indices as well!)"}, - {SRT_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Randomize order of selected elements"}, - {SRT_REVERSE, "REVERSE", 0, "Reverse", "Reverse current order of selected elements"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem elem_items[] = { - {BM_VERT, "VERT", 0, "Vertices", ""}, - {BM_EDGE, "EDGE", 0, "Edges", ""}, - {BM_FACE, "FACE", 0, "Faces", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Sort Mesh Elements"; - ot->description = "The order of selected vertices/edges/faces is modified, based on a given method"; - ot->idname = "MESH_OT_sort_elements"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = edbm_sort_elements_exec; - ot->poll = ED_operator_editmesh; - ot->poll_property = edbm_sort_elements_poll_property; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", type_items, SRT_VIEW_ZAXIS, - "Type", "Type of re-ordering operation to apply"); - RNA_def_enum_flag(ot->srna, "elements", elem_items, BM_VERT, "Elements", - "Which elements to affect (vertices, edges and/or faces)"); - RNA_def_boolean(ot->srna, "reverse", false, "Reverse", "Reverse the sorting effect"); - RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255); + static const EnumPropertyItem type_items[] = { + {SRT_VIEW_ZAXIS, + "VIEW_ZAXIS", + 0, + "View Z Axis", + "Sort selected elements from farthest to nearest one in current view"}, + {SRT_VIEW_XAXIS, + "VIEW_XAXIS", + 0, + "View X Axis", + "Sort selected elements from left to right one in current view"}, + {SRT_CURSOR_DISTANCE, + "CURSOR_DISTANCE", + 0, + "Cursor Distance", + "Sort selected elements from nearest to farthest from 3D cursor"}, + {SRT_MATERIAL, + "MATERIAL", + 0, + "Material", + "Sort selected elements from smallest to greatest material index (faces only!)"}, + {SRT_SELECTED, + "SELECTED", + 0, + "Selected", + "Move all selected elements in first places, preserving their relative order " + "(WARNING: this will affect unselected elements' indices as well!)"}, + {SRT_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Randomize order of selected elements"}, + {SRT_REVERSE, "REVERSE", 0, "Reverse", "Reverse current order of selected elements"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem elem_items[] = { + {BM_VERT, "VERT", 0, "Vertices", ""}, + {BM_EDGE, "EDGE", 0, "Edges", ""}, + {BM_FACE, "FACE", 0, "Faces", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Sort Mesh Elements"; + ot->description = + "The order of selected vertices/edges/faces is modified, based on a given method"; + ot->idname = "MESH_OT_sort_elements"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = edbm_sort_elements_exec; + ot->poll = ED_operator_editmesh; + ot->poll_property = edbm_sort_elements_poll_property; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, + "type", + type_items, + SRT_VIEW_ZAXIS, + "Type", + "Type of re-ordering operation to apply"); + RNA_def_enum_flag(ot->srna, + "elements", + elem_items, + BM_VERT, + "Elements", + "Which elements to affect (vertices, edges and/or faces)"); + RNA_def_boolean(ot->srna, "reverse", false, "Reverse", "Reverse the sorting effect"); + RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255); } /** \} */ @@ -6212,210 +6538,232 @@ void MESH_OT_sort_elements(wmOperatorType *ot) * \{ */ enum { - MESH_BRIDGELOOP_SINGLE = 0, - MESH_BRIDGELOOP_CLOSED = 1, - MESH_BRIDGELOOP_PAIRS = 2, + MESH_BRIDGELOOP_SINGLE = 0, + MESH_BRIDGELOOP_CLOSED = 1, + MESH_BRIDGELOOP_PAIRS = 2, }; static int edbm_bridge_tag_boundary_edges(BMesh *bm) { - /* tags boundary edges from a face selection */ - BMIter iter; - BMFace *f; - BMEdge *e; - int totface_del = 0; - - BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - if (BM_edge_is_wire(e) || BM_edge_is_boundary(e)) { - BM_elem_flag_enable(e, BM_ELEM_TAG); - } - else { - BMIter fiter; - bool is_all_sel = true; - /* check if its only used by selected faces */ - BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - /* tag face for removal*/ - if (!BM_elem_flag_test(f, BM_ELEM_TAG)) { - BM_elem_flag_enable(f, BM_ELEM_TAG); - totface_del++; - } - } - else { - is_all_sel = false; - } - } - - if (is_all_sel == false) { - BM_elem_flag_enable(e, BM_ELEM_TAG); - } - } - } - } - - return totface_del; -} - -static int edbm_bridge_edge_loops_for_single_editmesh( - wmOperator *op, - BMEditMesh *em, - const bool use_pairs, - const bool use_cyclic, - const bool use_merge, - const float merge_factor, - const int twist_offset) -{ - BMOperator bmop; - char edge_hflag; - int totface_del = 0; - BMFace **totface_del_arr = NULL; - const bool use_faces = (em->bm->totfacesel != 0); - - if (use_faces) { - BMIter iter; - BMFace *f; - int i; - - totface_del = edbm_bridge_tag_boundary_edges(em->bm); - totface_del_arr = MEM_mallocN(sizeof(*totface_del_arr) * totface_del, __func__); - - i = 0; - BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_TAG)) { - totface_del_arr[i++] = f; - } - } - edge_hflag = BM_ELEM_TAG; - } - else { - edge_hflag = BM_ELEM_SELECT; - } - - EDBM_op_init( - em, &bmop, op, - "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i", - edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset); - - if (use_faces && totface_del) { - int i; - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - for (i = 0; i < totface_del; i++) { - BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG); - } - BMO_op_callf( - em->bm, BMO_FLAG_DEFAULTS, - "delete geom=%hf context=%i", - BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY); - } - - BMO_op_exec(em->bm, &bmop); - - if (!BMO_error_occurred(em->bm)) { - /* when merge is used the edges are joined and remain selected */ - if (use_merge == false) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - } - - if (use_merge == false) { - struct EdgeRingOpSubdProps op_props; - mesh_operator_edgering_props_get(op, &op_props); - - if (op_props.cuts) { - BMOperator bmop_subd; - /* we only need face normals updated */ - EDBM_mesh_normals_update(em); - - BMO_op_initf( - em->bm, &bmop_subd, 0, - "subdivide_edgering edges=%S interp_mode=%i cuts=%i smooth=%f " - "profile_shape=%i profile_shape_factor=%f", - &bmop, "edges.out", op_props.interp_mode, op_props.cuts, op_props.smooth, - op_props.profile_shape, op_props.profile_shape_factor - ); - BMO_op_exec(em->bm, &bmop_subd); - BMO_slot_buffer_hflag_enable(em->bm, bmop_subd.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - BMO_op_finish(em->bm, &bmop_subd); - } - } - } - - if (totface_del_arr) { - MEM_freeN(totface_del_arr); - } - - if (EDBM_op_finish(em, &bmop, op, true)) { - EDBM_update_generic(em, true, true); - } - - /* Always return finished so the user can select different options. */ - return OPERATOR_FINISHED; + /* tags boundary edges from a face selection */ + BMIter iter; + BMFace *f; + BMEdge *e; + int totface_del = 0; + + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + if (BM_edge_is_wire(e) || BM_edge_is_boundary(e)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + else { + BMIter fiter; + bool is_all_sel = true; + /* check if its only used by selected faces */ + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + /* tag face for removal*/ + if (!BM_elem_flag_test(f, BM_ELEM_TAG)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + totface_del++; + } + } + else { + is_all_sel = false; + } + } + + if (is_all_sel == false) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + } + } + } + + return totface_del; +} + +static int edbm_bridge_edge_loops_for_single_editmesh(wmOperator *op, + BMEditMesh *em, + const bool use_pairs, + const bool use_cyclic, + const bool use_merge, + const float merge_factor, + const int twist_offset) +{ + BMOperator bmop; + char edge_hflag; + int totface_del = 0; + BMFace **totface_del_arr = NULL; + const bool use_faces = (em->bm->totfacesel != 0); + + if (use_faces) { + BMIter iter; + BMFace *f; + int i; + + totface_del = edbm_bridge_tag_boundary_edges(em->bm); + totface_del_arr = MEM_mallocN(sizeof(*totface_del_arr) * totface_del, __func__); + + i = 0; + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG)) { + totface_del_arr[i++] = f; + } + } + edge_hflag = BM_ELEM_TAG; + } + else { + edge_hflag = BM_ELEM_SELECT; + } + + EDBM_op_init(em, + &bmop, + op, + "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f " + "twist_offset=%i", + edge_hflag, + use_pairs, + use_cyclic, + use_merge, + merge_factor, + twist_offset); + + if (use_faces && totface_del) { + int i; + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + for (i = 0; i < totface_del; i++) { + BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG); + } + BMO_op_callf(em->bm, + BMO_FLAG_DEFAULTS, + "delete geom=%hf context=%i", + BM_ELEM_TAG, + DEL_FACES_KEEP_BOUNDARY); + } + + BMO_op_exec(em->bm, &bmop); + + if (!BMO_error_occurred(em->bm)) { + /* when merge is used the edges are joined and remain selected */ + if (use_merge == false) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + } + + if (use_merge == false) { + struct EdgeRingOpSubdProps op_props; + mesh_operator_edgering_props_get(op, &op_props); + + if (op_props.cuts) { + BMOperator bmop_subd; + /* we only need face normals updated */ + EDBM_mesh_normals_update(em); + + BMO_op_initf(em->bm, + &bmop_subd, + 0, + "subdivide_edgering edges=%S interp_mode=%i cuts=%i smooth=%f " + "profile_shape=%i profile_shape_factor=%f", + &bmop, + "edges.out", + op_props.interp_mode, + op_props.cuts, + op_props.smooth, + op_props.profile_shape, + op_props.profile_shape_factor); + BMO_op_exec(em->bm, &bmop_subd); + BMO_slot_buffer_hflag_enable( + em->bm, bmop_subd.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + BMO_op_finish(em->bm, &bmop_subd); + } + } + } + + if (totface_del_arr) { + MEM_freeN(totface_del_arr); + } + + if (EDBM_op_finish(em, &bmop, op, true)) { + EDBM_update_generic(em, true, true); + } + + /* Always return finished so the user can select different options. */ + return OPERATOR_FINISHED; } static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op) { - const int type = RNA_enum_get(op->ptr, "type"); - const bool use_pairs = (type == MESH_BRIDGELOOP_PAIRS); - const bool use_cyclic = (type == MESH_BRIDGELOOP_CLOSED); - const bool use_merge = RNA_boolean_get(op->ptr, "use_merge"); - const float merge_factor = RNA_float_get(op->ptr, "merge_factor"); - const int twist_offset = RNA_int_get(op->ptr, "twist_offset"); - ViewLayer *view_layer = CTX_data_view_layer(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totvertsel == 0) { - continue; - } - - edbm_bridge_edge_loops_for_single_editmesh(op, - em, - use_pairs, - use_cyclic, - use_merge, - merge_factor, - twist_offset); - } - MEM_freeN(objects); - return OPERATOR_FINISHED; -} - -void MESH_OT_bridge_edge_loops(wmOperatorType *ot) -{ - static const EnumPropertyItem type_items[] = { - {MESH_BRIDGELOOP_SINGLE, "SINGLE", 0, "Open Loop", ""}, - {MESH_BRIDGELOOP_CLOSED, "CLOSED", 0, "Closed Loop", ""}, - {MESH_BRIDGELOOP_PAIRS, "PAIRS", 0, "Loop Pairs", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Bridge Edge Loops"; - ot->description = "Make faces between two or more edge loops"; - ot->idname = "MESH_OT_bridge_edge_loops"; + const int type = RNA_enum_get(op->ptr, "type"); + const bool use_pairs = (type == MESH_BRIDGELOOP_PAIRS); + const bool use_cyclic = (type == MESH_BRIDGELOOP_CLOSED); + const bool use_merge = RNA_boolean_get(op->ptr, "use_merge"); + const float merge_factor = RNA_float_get(op->ptr, "merge_factor"); + const int twist_offset = RNA_int_get(op->ptr, "twist_offset"); + ViewLayer *view_layer = CTX_data_view_layer(C); - /* api callbacks */ - ot->exec = edbm_bridge_edge_loops_exec; - ot->poll = ED_operator_editmesh; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + if (em->bm->totvertsel == 0) { + continue; + } - ot->prop = RNA_def_enum(ot->srna, "type", type_items, MESH_BRIDGELOOP_SINGLE, - "Connect Loops", "Method of bridging multiple loops"); - - RNA_def_boolean(ot->srna, "use_merge", false, "Merge", "Merge rather than creating faces"); - RNA_def_float(ot->srna, "merge_factor", 0.5f, 0.0f, 1.0f, "Merge Factor", "", 0.0f, 1.0f); - RNA_def_int(ot->srna, "twist_offset", 0, -1000, 1000, "Twist", "Twist offset for closed loops", -1000, 1000); + edbm_bridge_edge_loops_for_single_editmesh( + op, em, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset); + } + MEM_freeN(objects); + return OPERATOR_FINISHED; +} - mesh_operator_edgering_props(ot, 0, 0); +void MESH_OT_bridge_edge_loops(wmOperatorType *ot) +{ + static const EnumPropertyItem type_items[] = { + {MESH_BRIDGELOOP_SINGLE, "SINGLE", 0, "Open Loop", ""}, + {MESH_BRIDGELOOP_CLOSED, "CLOSED", 0, "Closed Loop", ""}, + {MESH_BRIDGELOOP_PAIRS, "PAIRS", 0, "Loop Pairs", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Bridge Edge Loops"; + ot->description = "Make faces between two or more edge loops"; + ot->idname = "MESH_OT_bridge_edge_loops"; + + /* api callbacks */ + ot->exec = edbm_bridge_edge_loops_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "type", + type_items, + MESH_BRIDGELOOP_SINGLE, + "Connect Loops", + "Method of bridging multiple loops"); + + RNA_def_boolean(ot->srna, "use_merge", false, "Merge", "Merge rather than creating faces"); + RNA_def_float(ot->srna, "merge_factor", 0.5f, 0.0f, 1.0f, "Merge Factor", "", 0.0f, 1.0f); + RNA_def_int(ot->srna, + "twist_offset", + 0, + -1000, + 1000, + "Twist", + "Twist offset for closed loops", + -1000, + 1000); + + mesh_operator_edgering_props(ot, 0, 0); } /** \} */ @@ -6426,80 +6774,102 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot) static int edbm_wireframe_exec(bContext *C, wmOperator *op) { - const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); - const bool use_even_offset = RNA_boolean_get(op->ptr, "use_even_offset"); - const bool use_replace = RNA_boolean_get(op->ptr, "use_replace"); - const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset"); - const bool use_crease = RNA_boolean_get(op->ptr, "use_crease"); - const float crease_weight = RNA_float_get(op->ptr, "crease_weight"); - const float thickness = RNA_float_get(op->ptr, "thickness"); - const float offset = RNA_float_get(op->ptr, "offset"); - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totfacesel == 0) { - continue; - } - - BMOperator bmop; - - EDBM_op_init( - em, &bmop, op, - "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b use_relative_offset=%b " - "use_crease=%b crease_weight=%f thickness=%f offset=%f", - BM_ELEM_SELECT, use_replace, use_boundary, use_even_offset, use_relative_offset, - use_crease, crease_weight, thickness, offset); - - BMO_op_exec(em->bm, &bmop); - - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - - EDBM_update_generic(em, true, true); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); + const bool use_even_offset = RNA_boolean_get(op->ptr, "use_even_offset"); + const bool use_replace = RNA_boolean_get(op->ptr, "use_replace"); + const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset"); + const bool use_crease = RNA_boolean_get(op->ptr, "use_crease"); + const float crease_weight = RNA_float_get(op->ptr, "crease_weight"); + const float thickness = RNA_float_get(op->ptr, "thickness"); + const float offset = RNA_float_get(op->ptr, "offset"); + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totfacesel == 0) { + continue; + } + + BMOperator bmop; + + EDBM_op_init(em, + &bmop, + op, + "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b " + "use_relative_offset=%b " + "use_crease=%b crease_weight=%f thickness=%f offset=%f", + BM_ELEM_SELECT, + use_replace, + use_boundary, + use_even_offset, + use_relative_offset, + use_crease, + crease_weight, + thickness, + offset); + + BMO_op_exec(em->bm, &bmop); + + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_update_generic(em, true, true); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_wireframe(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Wire Frame"; - ot->idname = "MESH_OT_wireframe"; - ot->description = "Create a solid wire-frame from faces"; - - /* api callbacks */ - ot->exec = edbm_wireframe_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries"); - RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness"); - RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry"); - RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces"); - prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f); - /* use 1 rather then 10 for max else dragging the button moves too far */ - RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4); - RNA_def_float_distance(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f); - RNA_def_boolean(ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf"); - prop = RNA_def_float(ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease weight", "", 0.0f, 1.0f); - RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Wire Frame"; + ot->idname = "MESH_OT_wireframe"; + ot->description = "Create a solid wire-frame from faces"; + + /* api callbacks */ + ot->exec = edbm_wireframe_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries"); + RNA_def_boolean(ot->srna, + "use_even_offset", + true, + "Offset Even", + "Scale the offset to give more even thickness"); + RNA_def_boolean(ot->srna, + "use_relative_offset", + false, + "Offset Relative", + "Scale the offset by surrounding geometry"); + RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces"); + prop = RNA_def_float_distance( + ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f); + /* use 1 rather then 10 for max else dragging the button moves too far */ + RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4); + RNA_def_float_distance(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f); + RNA_def_boolean( + ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf"); + prop = RNA_def_float( + ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease weight", "", 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2); } /** \} */ @@ -6510,81 +6880,86 @@ void MESH_OT_wireframe(wmOperatorType *ot) static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op) { - bool mode_change = false; - const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint"); - int ret = OPERATOR_CANCELLED; - - { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->selectmode == SCE_SELECT_FACE) { - EDBM_selectmode_to_scene(C); - mode_change = true; - } - } - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - /** If in face-only select mode, switch to edge select mode so that - * an edge-only selection is not inconsistent state. - * - * We need to run this for all objects, even when nothing is selected. - * This way we keep them in sync. */ - if (mode_change) { - em->selectmode = SCE_SELECT_EDGE; - EDBM_selectmode_set(em); - } - - if (em->bm->totedgesel == 0) { - continue; - } - - BMOperator bmop; - EDBM_op_init( - em, &bmop, op, - "offset_edgeloops edges=%he use_cap_endpoint=%b", - BM_ELEM_SELECT, use_cap_endpoint); - - BMO_op_exec(em->bm, &bmop); - - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); - - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - else { - EDBM_update_generic(em, true, true); - ret = OPERATOR_FINISHED; - } - } - MEM_freeN(objects); - return ret; + bool mode_change = false; + const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint"); + int ret = OPERATOR_CANCELLED; + + { + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->selectmode == SCE_SELECT_FACE) { + EDBM_selectmode_to_scene(C); + mode_change = true; + } + } + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + /** If in face-only select mode, switch to edge select mode so that + * an edge-only selection is not inconsistent state. + * + * We need to run this for all objects, even when nothing is selected. + * This way we keep them in sync. */ + if (mode_change) { + em->selectmode = SCE_SELECT_EDGE; + EDBM_selectmode_set(em); + } + + if (em->bm->totedgesel == 0) { + continue; + } + + BMOperator bmop; + EDBM_op_init(em, + &bmop, + op, + "offset_edgeloops edges=%he use_cap_endpoint=%b", + BM_ELEM_SELECT, + use_cap_endpoint); + + BMO_op_exec(em->bm, &bmop); + + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + else { + EDBM_update_generic(em, true, true); + ret = OPERATOR_FINISHED; + } + } + MEM_freeN(objects); + return ret; } void MESH_OT_offset_edge_loops(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Offset Edge Loop"; - ot->idname = "MESH_OT_offset_edge_loops"; - ot->description = "Create offset edge loop from the current selection"; + /* identifiers */ + ot->name = "Offset Edge Loop"; + ot->idname = "MESH_OT_offset_edge_loops"; + ot->description = "Create offset edge loop from the current selection"; - /* api callbacks */ - ot->exec = edbm_offset_edgeloop_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_offset_edgeloop_exec; + ot->poll = ED_operator_editmesh; - /* Keep internal, since this is only meant to be accessed via 'MESH_OT_offset_edge_loops_slide' */ + /* Keep internal, since this is only meant to be accessed via 'MESH_OT_offset_edge_loops_slide' */ - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - RNA_def_boolean(ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points"); + RNA_def_boolean( + ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points"); } /** \} */ @@ -6596,125 +6971,132 @@ void MESH_OT_offset_edge_loops(wmOperatorType *ot) #ifdef WITH_BULLET static int edbm_convex_hull_exec(bContext *C, wmOperator *op) { - const bool use_existing_faces = RNA_boolean_get(op->ptr, "use_existing_faces"); - const bool delete_unused = RNA_boolean_get(op->ptr, "delete_unused"); - const bool make_holes = RNA_boolean_get(op->ptr, "make_holes"); - const bool join_triangles = RNA_boolean_get(op->ptr, "join_triangles"); - - float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold"); - float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold"); - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totvertsel == 0) { - continue; - } - - BMOperator bmop; - - EDBM_op_init( - em, &bmop, op, "convex_hull input=%hvef " - "use_existing_faces=%b", - BM_ELEM_SELECT, - use_existing_faces); - BMO_op_exec(em->bm, &bmop); - - /* Hull fails if input is coplanar */ - if (BMO_error_occurred(em->bm)) { - EDBM_op_finish(em, &bmop, op, true); - continue; - } - - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); - - /* Delete unused vertices, edges, and faces */ - if (delete_unused) { - if (!EDBM_op_callf( - em, op, "delete geom=%S context=%i", - &bmop, "geom_unused.out", DEL_ONLYTAGGED)) - { - EDBM_op_finish(em, &bmop, op, true); - continue; - } - } - - /* Delete hole edges/faces */ - if (make_holes) { - if (!EDBM_op_callf( - em, op, "delete geom=%S context=%i", - &bmop, "geom_holes.out", DEL_ONLYTAGGED)) - { - EDBM_op_finish(em, &bmop, op, true); - continue; - } - } - - /* Merge adjacent triangles */ - if (join_triangles) { - if (!EDBM_op_call_and_selectf( - em, op, - "faces.out", true, - "join_triangles faces=%S " - "angle_face_threshold=%f angle_shape_threshold=%f", - &bmop, "geom.out", - angle_face_threshold, angle_shape_threshold)) - { - EDBM_op_finish(em, &bmop, op, true); - continue; - } - } - - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - - EDBM_update_generic(em, true, true); - EDBM_selectmode_flush(em); - } - - MEM_freeN(objects); - return OPERATOR_FINISHED; + const bool use_existing_faces = RNA_boolean_get(op->ptr, "use_existing_faces"); + const bool delete_unused = RNA_boolean_get(op->ptr, "delete_unused"); + const bool make_holes = RNA_boolean_get(op->ptr, "make_holes"); + const bool join_triangles = RNA_boolean_get(op->ptr, "join_triangles"); + + float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold"); + float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold"); + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totvertsel == 0) { + continue; + } + + BMOperator bmop; + + EDBM_op_init(em, + &bmop, + op, + "convex_hull input=%hvef " + "use_existing_faces=%b", + BM_ELEM_SELECT, + use_existing_faces); + BMO_op_exec(em->bm, &bmop); + + /* Hull fails if input is coplanar */ + if (BMO_error_occurred(em->bm)) { + EDBM_op_finish(em, &bmop, op, true); + continue; + } + + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); + + /* Delete unused vertices, edges, and faces */ + if (delete_unused) { + if (!EDBM_op_callf( + em, op, "delete geom=%S context=%i", &bmop, "geom_unused.out", DEL_ONLYTAGGED)) { + EDBM_op_finish(em, &bmop, op, true); + continue; + } + } + + /* Delete hole edges/faces */ + if (make_holes) { + if (!EDBM_op_callf( + em, op, "delete geom=%S context=%i", &bmop, "geom_holes.out", DEL_ONLYTAGGED)) { + EDBM_op_finish(em, &bmop, op, true); + continue; + } + } + + /* Merge adjacent triangles */ + if (join_triangles) { + if (!EDBM_op_call_and_selectf(em, + op, + "faces.out", + true, + "join_triangles faces=%S " + "angle_face_threshold=%f angle_shape_threshold=%f", + &bmop, + "geom.out", + angle_face_threshold, + angle_shape_threshold)) { + EDBM_op_finish(em, &bmop, op, true); + continue; + } + } + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_update_generic(em, true, true); + EDBM_selectmode_flush(em); + } + + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_convex_hull(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Convex Hull"; - ot->description = "Enclose selected vertices in a convex polyhedron"; - ot->idname = "MESH_OT_convex_hull"; + /* identifiers */ + ot->name = "Convex Hull"; + ot->description = "Enclose selected vertices in a convex polyhedron"; + ot->idname = "MESH_OT_convex_hull"; - /* api callbacks */ - ot->exec = edbm_convex_hull_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_convex_hull_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - RNA_def_boolean(ot->srna, "delete_unused", true, - "Delete Unused", - "Delete selected elements that are not used by the hull"); + /* props */ + RNA_def_boolean(ot->srna, + "delete_unused", + true, + "Delete Unused", + "Delete selected elements that are not used by the hull"); - RNA_def_boolean(ot->srna, "use_existing_faces", true, - "Use Existing Faces", - "Skip hull triangles that are covered by a pre-existing face"); + RNA_def_boolean(ot->srna, + "use_existing_faces", + true, + "Use Existing Faces", + "Skip hull triangles that are covered by a pre-existing face"); - RNA_def_boolean(ot->srna, "make_holes", false, - "Make Holes", - "Delete selected faces that are used by the hull"); + RNA_def_boolean(ot->srna, + "make_holes", + false, + "Make Holes", + "Delete selected faces that are used by the hull"); - RNA_def_boolean(ot->srna, "join_triangles", true, - "Join Triangles", - "Merge adjacent triangles into quads"); + RNA_def_boolean( + ot->srna, "join_triangles", true, "Join Triangles", "Merge adjacent triangles into quads"); - join_triangle_props(ot); + join_triangle_props(ot); } -#endif /* WITH_BULLET */ +#endif /* WITH_BULLET */ /** \} */ @@ -6724,63 +7106,77 @@ void MESH_OT_convex_hull(wmOperatorType *ot) static int mesh_symmetrize_exec(bContext *C, wmOperator *op) { - const float thresh = RNA_float_get(op->ptr, "threshold"); - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + const float thresh = RNA_float_get(op->ptr, "threshold"); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel == 0 ) { - continue; - } + if (em->bm->totvertsel == 0) { + continue; + } - BMOperator bmop; - EDBM_op_init( - em, &bmop, op, - "symmetrize input=%hvef direction=%i dist=%f", - BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh); - BMO_op_exec(em->bm, &bmop); + BMOperator bmop; + EDBM_op_init(em, + &bmop, + op, + "symmetrize input=%hvef direction=%i dist=%f", + BM_ELEM_SELECT, + RNA_enum_get(op->ptr, "direction"), + thresh); + BMO_op_exec(em->bm, &bmop); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - else { - EDBM_update_generic(em, true, true); - EDBM_selectmode_flush(em); - } - } - MEM_freeN(objects); + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + else { + EDBM_update_generic(em, true, true); + EDBM_selectmode_flush(em); + } + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_symmetrize(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Symmetrize"; - ot->description = "Enforce symmetry (both form and topological) across an axis"; - ot->idname = "MESH_OT_symmetrize"; - - /* api callbacks */ - ot->exec = mesh_symmetrize_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum( - ot->srna, "direction", rna_enum_symmetrize_direction_items, - BMO_SYMMETRIZE_NEGATIVE_X, - "Direction", "Which sides to copy from and to"); - RNA_def_float(ot->srna, "threshold", 1e-4f, 0.0f, 10.0f, "Threshold", - "Limit for snap middle vertices to the axis center", 1e-5f, 0.1f); + /* identifiers */ + ot->name = "Symmetrize"; + ot->description = "Enforce symmetry (both form and topological) across an axis"; + ot->idname = "MESH_OT_symmetrize"; + + /* api callbacks */ + ot->exec = mesh_symmetrize_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "direction", + rna_enum_symmetrize_direction_items, + BMO_SYMMETRIZE_NEGATIVE_X, + "Direction", + "Which sides to copy from and to"); + RNA_def_float(ot->srna, + "threshold", + 1e-4f, + 0.0f, + 10.0f, + "Threshold", + "Limit for snap middle vertices to the axis center", + 1e-5f, + 0.1f); } /** \} */ @@ -6791,142 +7187,166 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot) static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op) { - const float eps = 0.00001f; - const float eps_sq = eps * eps; - const bool use_topology = false; - - const float thresh = RNA_float_get(op->ptr, "threshold"); - const float fac = RNA_float_get(op->ptr, "factor"); - const bool use_center = RNA_boolean_get(op->ptr, "use_center"); - const int axis_dir = RNA_enum_get(op->ptr, "direction"); - - /* Vertices stats (total over all selected objects). */ - int totvertfound = 0, totvertmirr = 0, totvertfail = 0; - - /* Axis. */ - int axis = axis_dir % 3; - bool axis_sign = axis != axis_dir; - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if (em->bm->totvertsel == 0) { - continue; - } - - /* Only allocate memory after checking whether to skip object. */ - int *index = MEM_mallocN(bm->totvert * sizeof(*index), __func__); - - /* Vertex iter. */ - BMIter iter; - BMVert *v; - int i; - - EDBM_verts_mirror_cache_begin_ex(em, axis, true, true, use_topology, thresh, index); - - BM_mesh_elem_table_ensure(bm, BM_VERT); - - BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); - - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - if ((BM_elem_flag_test(v, BM_ELEM_SELECT) != false) && - (BM_elem_flag_test(v, BM_ELEM_TAG) == false)) - { - int i_mirr = index[i]; - if (i_mirr != -1) { - - BMVert *v_mirr = BM_vert_at_index(bm, index[i]); - - if (v != v_mirr) { - float co[3], co_mirr[3]; - - if ((v->co[axis] > v_mirr->co[axis]) == axis_sign) { - SWAP(BMVert *, v, v_mirr); - } - - copy_v3_v3(co_mirr, v_mirr->co); - co_mirr[axis] *= -1.0f; - - if (len_squared_v3v3(v->co, co_mirr) > eps_sq) { - totvertmirr++; - } - - interp_v3_v3v3(co, v->co, co_mirr, fac); + const float eps = 0.00001f; + const float eps_sq = eps * eps; + const bool use_topology = false; - copy_v3_v3(v->co, co); - - co[axis] *= -1.0f; - copy_v3_v3(v_mirr->co, co); - - BM_elem_flag_enable(v, BM_ELEM_TAG); - BM_elem_flag_enable(v_mirr, BM_ELEM_TAG); - totvertfound++; - } - else { - if (use_center) { - - if (fabsf(v->co[axis]) > eps) { - totvertmirr++; - } - - v->co[axis] = 0.0f; - } - BM_elem_flag_enable(v, BM_ELEM_TAG); - totvertfound++; - } - } - else { - totvertfail++; - } - } - } - - /* No need to end cache, just free the array. */ - MEM_freeN(index); - } - MEM_freeN(objects); - - if (totvertfail) { - BKE_reportf(op->reports, RPT_WARNING, "%d already symmetrical, %d pairs mirrored, %d failed", - totvertfound - totvertmirr, totvertmirr, totvertfail); - } - else { - BKE_reportf(op->reports, RPT_INFO, "%d already symmetrical, %d pairs mirrored", - totvertfound - totvertmirr, totvertmirr); - } - - return OPERATOR_FINISHED; + const float thresh = RNA_float_get(op->ptr, "threshold"); + const float fac = RNA_float_get(op->ptr, "factor"); + const bool use_center = RNA_boolean_get(op->ptr, "use_center"); + const int axis_dir = RNA_enum_get(op->ptr, "direction"); + + /* Vertices stats (total over all selected objects). */ + int totvertfound = 0, totvertmirr = 0, totvertfail = 0; + + /* Axis. */ + int axis = axis_dir % 3; + bool axis_sign = axis != axis_dir; + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if (em->bm->totvertsel == 0) { + continue; + } + + /* Only allocate memory after checking whether to skip object. */ + int *index = MEM_mallocN(bm->totvert * sizeof(*index), __func__); + + /* Vertex iter. */ + BMIter iter; + BMVert *v; + int i; + + EDBM_verts_mirror_cache_begin_ex(em, axis, true, true, use_topology, thresh, index); + + BM_mesh_elem_table_ensure(bm, BM_VERT); + + BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + if ((BM_elem_flag_test(v, BM_ELEM_SELECT) != false) && + (BM_elem_flag_test(v, BM_ELEM_TAG) == false)) { + int i_mirr = index[i]; + if (i_mirr != -1) { + + BMVert *v_mirr = BM_vert_at_index(bm, index[i]); + + if (v != v_mirr) { + float co[3], co_mirr[3]; + + if ((v->co[axis] > v_mirr->co[axis]) == axis_sign) { + SWAP(BMVert *, v, v_mirr); + } + + copy_v3_v3(co_mirr, v_mirr->co); + co_mirr[axis] *= -1.0f; + + if (len_squared_v3v3(v->co, co_mirr) > eps_sq) { + totvertmirr++; + } + + interp_v3_v3v3(co, v->co, co_mirr, fac); + + copy_v3_v3(v->co, co); + + co[axis] *= -1.0f; + copy_v3_v3(v_mirr->co, co); + + BM_elem_flag_enable(v, BM_ELEM_TAG); + BM_elem_flag_enable(v_mirr, BM_ELEM_TAG); + totvertfound++; + } + else { + if (use_center) { + + if (fabsf(v->co[axis]) > eps) { + totvertmirr++; + } + + v->co[axis] = 0.0f; + } + BM_elem_flag_enable(v, BM_ELEM_TAG); + totvertfound++; + } + } + else { + totvertfail++; + } + } + } + + /* No need to end cache, just free the array. */ + MEM_freeN(index); + } + MEM_freeN(objects); + + if (totvertfail) { + BKE_reportf(op->reports, + RPT_WARNING, + "%d already symmetrical, %d pairs mirrored, %d failed", + totvertfound - totvertmirr, + totvertmirr, + totvertfail); + } + else { + BKE_reportf(op->reports, + RPT_INFO, + "%d already symmetrical, %d pairs mirrored", + totvertfound - totvertmirr, + totvertmirr); + } + + return OPERATOR_FINISHED; } void MESH_OT_symmetry_snap(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Snap to Symmetry"; - ot->description = "Snap vertex pairs to their mirrored locations"; - ot->idname = "MESH_OT_symmetry_snap"; - - /* api callbacks */ - ot->exec = mesh_symmetry_snap_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum( - ot->srna, "direction", rna_enum_symmetrize_direction_items, - BMO_SYMMETRIZE_NEGATIVE_X, - "Direction", "Which sides to copy from and to"); - RNA_def_float_distance(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", - "Distance within which matching vertices are searched", 1e-4f, 1.0f); - RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", - "Mix factor of the locations of the vertices", 0.0f, 1.0f); - RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap middle vertices to the axis center"); + /* identifiers */ + ot->name = "Snap to Symmetry"; + ot->description = "Snap vertex pairs to their mirrored locations"; + ot->idname = "MESH_OT_symmetry_snap"; + + /* api callbacks */ + ot->exec = mesh_symmetry_snap_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "direction", + rna_enum_symmetrize_direction_items, + BMO_SYMMETRIZE_NEGATIVE_X, + "Direction", + "Which sides to copy from and to"); + RNA_def_float_distance(ot->srna, + "threshold", + 0.05f, + 0.0f, + 10.0f, + "Threshold", + "Distance within which matching vertices are searched", + 1e-4f, + 1.0f); + RNA_def_float(ot->srna, + "factor", + 0.5f, + 0.0f, + 1.0f, + "Factor", + "Mix factor of the locations of the vertices", + 0.0f, + 1.0f); + RNA_def_boolean( + ot->srna, "use_center", true, "Center", "Snap middle vertices to the axis center"); } /** \} */ @@ -6939,75 +7359,76 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot) static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op) { - BMEdge *eed; - BMIter iter; - FreestyleEdge *fed; - const bool clear = RNA_boolean_get(op->ptr, "clear"); - ViewLayer *view_layer = CTX_data_view_layer(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em == NULL) { - continue; - } - - BMesh *bm = em->bm; - - if (bm->totedgesel == 0) { - continue; - } - - if (!CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) { - BM_data_layer_add(em->bm, &em->bm->edata, CD_FREESTYLE_EDGE); - } - - if (clear) { - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE); - fed->flag &= ~FREESTYLE_EDGE_MARK; - } - } - } - else { - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE); - fed->flag |= FREESTYLE_EDGE_MARK; - } - } - } - - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + BMEdge *eed; + BMIter iter; + FreestyleEdge *fed; + const bool clear = RNA_boolean_get(op->ptr, "clear"); + ViewLayer *view_layer = CTX_data_view_layer(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em == NULL) { + continue; + } + + BMesh *bm = em->bm; + + if (bm->totedgesel == 0) { + continue; + } + + if (!CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) { + BM_data_layer_add(em->bm, &em->bm->edata, CD_FREESTYLE_EDGE); + } + + if (clear) { + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE); + fed->flag &= ~FREESTYLE_EDGE_MARK; + } + } + } + else { + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE); + fed->flag |= FREESTYLE_EDGE_MARK; + } + } + } + + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_mark_freestyle_edge(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Mark Freestyle Edge"; - ot->description = "(Un)mark selected edges as Freestyle feature edges"; - ot->idname = "MESH_OT_mark_freestyle_edge"; + /* identifiers */ + ot->name = "Mark Freestyle Edge"; + ot->description = "(Un)mark selected edges as Freestyle feature edges"; + ot->idname = "MESH_OT_mark_freestyle_edge"; - /* api callbacks */ - ot->exec = edbm_mark_freestyle_edge_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_mark_freestyle_edge_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /** \} */ @@ -7018,78 +7439,79 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot) static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op) { - BMFace *efa; - BMIter iter; - FreestyleFace *ffa; - const bool clear = RNA_boolean_get(op->ptr, "clear"); - ViewLayer *view_layer = CTX_data_view_layer(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em == NULL) { - continue; - } - - if (em->bm->totfacesel == 0) { - continue; - } - - if (!CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE)) { - BM_data_layer_add(em->bm, &em->bm->pdata, CD_FREESTYLE_FACE); - } - - if (clear) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE); - ffa->flag &= ~FREESTYLE_FACE_MARK; - } - } - } - else { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE); - ffa->flag |= FREESTYLE_FACE_MARK; - } - } - } - - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + BMFace *efa; + BMIter iter; + FreestyleFace *ffa; + const bool clear = RNA_boolean_get(op->ptr, "clear"); + ViewLayer *view_layer = CTX_data_view_layer(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em == NULL) { + continue; + } + + if (em->bm->totfacesel == 0) { + continue; + } + + if (!CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE)) { + BM_data_layer_add(em->bm, &em->bm->pdata, CD_FREESTYLE_FACE); + } + + if (clear) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE); + ffa->flag &= ~FREESTYLE_FACE_MARK; + } + } + } + else { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE); + ffa->flag |= FREESTYLE_FACE_MARK; + } + } + } + + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_mark_freestyle_face(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Mark Freestyle Face"; - ot->description = "(Un)mark selected faces for exclusion from Freestyle feature edge detection"; - ot->idname = "MESH_OT_mark_freestyle_face"; + /* identifiers */ + ot->name = "Mark Freestyle Face"; + ot->description = "(Un)mark selected faces for exclusion from Freestyle feature edge detection"; + ot->idname = "MESH_OT_mark_freestyle_face"; - /* api callbacks */ - ot->exec = edbm_mark_freestyle_face_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_mark_freestyle_face_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /** \} */ -#endif /* WITH_FREESTYLE */ +#endif /* WITH_FREESTYLE */ /********************** Loop normals editing tools modal map. **********************/ @@ -7097,59 +7519,84 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot) /* NOTE: We could add more here, like e.g. a switch between local or global coordinates of target, * use numinput to type in explicit vector values... */ enum { - /* Generic commands. */ - EDBM_CLNOR_MODAL_CANCEL = 1, - EDBM_CLNOR_MODAL_CONFIRM = 2, - - /* Point To operator. */ - EDBM_CLNOR_MODAL_POINTTO_RESET = 101, - EDBM_CLNOR_MODAL_POINTTO_INVERT = 102, - EDBM_CLNOR_MODAL_POINTTO_SPHERIZE = 103, - EDBM_CLNOR_MODAL_POINTTO_ALIGN = 104, - - EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE = 110, - EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT = 111, - EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT = 112, - EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR = 113, - EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED = 114, + /* Generic commands. */ + EDBM_CLNOR_MODAL_CANCEL = 1, + EDBM_CLNOR_MODAL_CONFIRM = 2, + + /* Point To operator. */ + EDBM_CLNOR_MODAL_POINTTO_RESET = 101, + EDBM_CLNOR_MODAL_POINTTO_INVERT = 102, + EDBM_CLNOR_MODAL_POINTTO_SPHERIZE = 103, + EDBM_CLNOR_MODAL_POINTTO_ALIGN = 104, + + EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE = 110, + EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT = 111, + EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT = 112, + EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR = 113, + EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED = 114, }; /* called in transform_ops.c, on each regeneration of keymaps */ wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf) { - static const EnumPropertyItem modal_items[] = { - {EDBM_CLNOR_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, - {EDBM_CLNOR_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - - /* Point To operator. */ - {EDBM_CLNOR_MODAL_POINTTO_RESET, "RESET", 0, "Reset", "Reset normals to initial ones"}, - {EDBM_CLNOR_MODAL_POINTTO_INVERT, "INVERT", 0, "Invert", "Toggle inversion of affected normals"}, - {EDBM_CLNOR_MODAL_POINTTO_SPHERIZE, "SPHERIZE", 0, "Spherize", "Interpolate between new and original normals"}, - {EDBM_CLNOR_MODAL_POINTTO_ALIGN, "ALIGN", 0, "Align", "Make all affected normals parallel"}, - - {EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE, "USE_MOUSE", 0, "Use Mouse", "Follow mouse cursor position"}, - {EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT, "USE_PIVOT", 0, "Use Pivot", - "Use current rotation/scaling pivot point coordinates"}, - {EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT, "USE_OBJECT", 0, "Use Object", "Use current edited object's location"}, - {EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR, "SET_USE_3DCURSOR", 0, "Set and Use 3D Cursor", - "Set new 3D cursor position and use it"}, - {EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED, "SET_USE_SELECTED", 0, "Select and Use Mesh Item", - "Select new active mesh element and use its location"}, - {0, NULL, 0, NULL, NULL}, - }; - static const char *keymap_name = "Custom Normals Modal Map"; - - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, keymap_name); - - /* We only need to add map once */ - if (keymap && keymap->modal_items) - return NULL; - - keymap = WM_modalkeymap_add(keyconf, keymap_name, modal_items); - - WM_modalkeymap_assign(keymap, "MESH_OT_point_normals"); - - return keymap; + static const EnumPropertyItem modal_items[] = { + {EDBM_CLNOR_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {EDBM_CLNOR_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + /* Point To operator. */ + {EDBM_CLNOR_MODAL_POINTTO_RESET, "RESET", 0, "Reset", "Reset normals to initial ones"}, + {EDBM_CLNOR_MODAL_POINTTO_INVERT, + "INVERT", + 0, + "Invert", + "Toggle inversion of affected normals"}, + {EDBM_CLNOR_MODAL_POINTTO_SPHERIZE, + "SPHERIZE", + 0, + "Spherize", + "Interpolate between new and original normals"}, + {EDBM_CLNOR_MODAL_POINTTO_ALIGN, "ALIGN", 0, "Align", "Make all affected normals parallel"}, + + {EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE, + "USE_MOUSE", + 0, + "Use Mouse", + "Follow mouse cursor position"}, + {EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT, + "USE_PIVOT", + 0, + "Use Pivot", + "Use current rotation/scaling pivot point coordinates"}, + {EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT, + "USE_OBJECT", + 0, + "Use Object", + "Use current edited object's location"}, + {EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR, + "SET_USE_3DCURSOR", + 0, + "Set and Use 3D Cursor", + "Set new 3D cursor position and use it"}, + {EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED, + "SET_USE_SELECTED", + 0, + "Select and Use Mesh Item", + "Select new active mesh element and use its location"}, + {0, NULL, 0, NULL, NULL}, + }; + static const char *keymap_name = "Custom Normals Modal Map"; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, keymap_name); + + /* We only need to add map once */ + if (keymap && keymap->modal_items) + return NULL; + + keymap = WM_modalkeymap_add(keyconf, keymap_name, modal_items); + + WM_modalkeymap_assign(keymap, "MESH_OT_point_normals"); + + return keymap; } #define CLNORS_VALID_VEC_LEN (1e-4f) @@ -7157,1260 +7604,1354 @@ wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf) /********************** 'Point to' Loop Normals **********************/ enum { - EDBM_CLNOR_POINTTO_MODE_COORDINATES = 1, - EDBM_CLNOR_POINTTO_MODE_MOUSE = 2, + EDBM_CLNOR_POINTTO_MODE_COORDINATES = 1, + EDBM_CLNOR_POINTTO_MODE_MOUSE = 2, }; static EnumPropertyItem clnors_pointto_mode_items[] = { - {EDBM_CLNOR_POINTTO_MODE_COORDINATES, "COORDINATES", 0, "Coordinates", - "Use static coordinates (defined by various means)"}, - {EDBM_CLNOR_POINTTO_MODE_MOUSE, "MOUSE", 0, "Mouse", "Follow mouse cursor"}, - {0, NULL, 0, NULL, NULL}, + {EDBM_CLNOR_POINTTO_MODE_COORDINATES, + "COORDINATES", + 0, + "Coordinates", + "Use static coordinates (defined by various means)"}, + {EDBM_CLNOR_POINTTO_MODE_MOUSE, "MOUSE", 0, "Mouse", "Follow mouse cursor"}, + {0, NULL, 0, NULL, NULL}, }; /* Initialize loop normal data */ static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; - BKE_editmesh_lnorspace_update(em); - BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); - op->customdata = lnors_ed_arr; + op->customdata = lnors_ed_arr; - return lnors_ed_arr->totloop; + return lnors_ed_arr->totloop; } static void point_normals_free(bContext *C, wmOperator *op) { - BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; - BM_loop_normal_editdata_array_free(lnors_ed_arr); - op->customdata = NULL; - ED_area_status_text(CTX_wm_area(C), NULL); + BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; + BM_loop_normal_editdata_array_free(lnors_ed_arr); + op->customdata = NULL; + ED_area_status_text(CTX_wm_area(C), NULL); } static void point_normals_update_header(bContext *C, wmOperator *op) { - char header[UI_MAX_DRAW_STR]; - char buf[UI_MAX_DRAW_STR]; + char header[UI_MAX_DRAW_STR]; + char buf[UI_MAX_DRAW_STR]; - char *p = buf; - int available_len = sizeof(buf); + char *p = buf; + int available_len = sizeof(buf); #define WM_MODALKEY(_id) \ - WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) - - BLI_snprintf(header, sizeof(header), IFACE_("%s: confirm, %s: cancel, " - "%s: point to mouse (%s), %s: point to Pivot, " - "%s: point to object origin, %s: reset normals, " - "%s: set & point to 3D cursor, %s: select & point to mesh item, " - "%s: invert normals (%s), %s: spherize (%s), %s: align (%s)"), - WM_MODALKEY(EDBM_CLNOR_MODAL_CONFIRM), WM_MODALKEY(EDBM_CLNOR_MODAL_CANCEL), - WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE), - WM_bool_as_string(RNA_enum_get(op->ptr, "mode") == EDBM_CLNOR_POINTTO_MODE_MOUSE), - WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT), - WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_RESET), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR), - WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED), - WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_INVERT), WM_bool_as_string(RNA_boolean_get(op->ptr, "invert")), - WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SPHERIZE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")), - WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_ALIGN), WM_bool_as_string(RNA_boolean_get(op->ptr, "align"))); + WM_modalkeymap_operator_items_to_string_buf( \ + op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) + + BLI_snprintf(header, + sizeof(header), + IFACE_("%s: confirm, %s: cancel, " + "%s: point to mouse (%s), %s: point to Pivot, " + "%s: point to object origin, %s: reset normals, " + "%s: set & point to 3D cursor, %s: select & point to mesh item, " + "%s: invert normals (%s), %s: spherize (%s), %s: align (%s)"), + WM_MODALKEY(EDBM_CLNOR_MODAL_CONFIRM), + WM_MODALKEY(EDBM_CLNOR_MODAL_CANCEL), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE), + WM_bool_as_string(RNA_enum_get(op->ptr, "mode") == EDBM_CLNOR_POINTTO_MODE_MOUSE), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_RESET), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_INVERT), + WM_bool_as_string(RNA_boolean_get(op->ptr, "invert")), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SPHERIZE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_ALIGN), + WM_bool_as_string(RNA_boolean_get(op->ptr, "align"))); #undef WM_MODALKEY - ED_area_status_text(CTX_wm_area(C), header); + ED_area_status_text(CTX_wm_area(C), header); } /* TODO move that to generic function in BMesh? */ static void bmesh_selected_verts_center_calc(BMesh *bm, float *r_center) { - BMVert *v; - BMIter viter; - int i = 0; + BMVert *v; + BMIter viter; + int i = 0; - zero_v3(r_center); - BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - add_v3_v3(r_center, v->co); - i++; - } - } - mul_v3_fl(r_center, 1.0f / (float)i); + zero_v3(r_center); + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + add_v3_v3(r_center, v->co); + i++; + } + } + mul_v3_fl(r_center, 1.0f / (float)i); } static void point_normals_apply(bContext *C, wmOperator *op, float target[3], const bool do_reset) { - Object *obedit = CTX_data_edit_object(C); - BMesh *bm = BKE_editmesh_from_object(obedit)->bm; - BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; - - const bool do_invert = RNA_boolean_get(op->ptr, "invert"); - const bool do_spherize = RNA_boolean_get(op->ptr, "spherize"); - const bool do_align = RNA_boolean_get(op->ptr, "align"); - float center[3]; - - if (do_align && !do_reset) { - bmesh_selected_verts_center_calc(bm, center); - } - - sub_v3_v3(target, obedit->loc); /* Move target to local coordinates. */ - - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - if (do_reset) { - copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); - } - else if (do_spherize) { - /* Note that this is *not* real spherical interpolation. Probably good enough in this case though? */ - const float strength = RNA_float_get(op->ptr, "spherize_strength"); - float spherized_normal[3]; - - sub_v3_v3v3(spherized_normal, target, lnor_ed->loc); - - /* otherwise, multiplication by strength is meaningless... */ - normalize_v3(spherized_normal); - - mul_v3_fl(spherized_normal, strength); - mul_v3_v3fl(lnor_ed->nloc, lnor_ed->niloc, 1.0f - strength); - add_v3_v3(lnor_ed->nloc, spherized_normal); - } - else if (do_align) { - sub_v3_v3v3(lnor_ed->nloc, target, center); - } - else { - sub_v3_v3v3(lnor_ed->nloc, target, lnor_ed->loc); - } - - if (do_invert && !do_reset) { - negate_v3(lnor_ed->nloc); - } - if (normalize_v3(lnor_ed->nloc) >= CLNORS_VALID_VEC_LEN) { - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); - } - } + Object *obedit = CTX_data_edit_object(C); + BMesh *bm = BKE_editmesh_from_object(obedit)->bm; + BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; + + const bool do_invert = RNA_boolean_get(op->ptr, "invert"); + const bool do_spherize = RNA_boolean_get(op->ptr, "spherize"); + const bool do_align = RNA_boolean_get(op->ptr, "align"); + float center[3]; + + if (do_align && !do_reset) { + bmesh_selected_verts_center_calc(bm, center); + } + + sub_v3_v3(target, obedit->loc); /* Move target to local coordinates. */ + + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (do_reset) { + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + else if (do_spherize) { + /* Note that this is *not* real spherical interpolation. Probably good enough in this case though? */ + const float strength = RNA_float_get(op->ptr, "spherize_strength"); + float spherized_normal[3]; + + sub_v3_v3v3(spherized_normal, target, lnor_ed->loc); + + /* otherwise, multiplication by strength is meaningless... */ + normalize_v3(spherized_normal); + + mul_v3_fl(spherized_normal, strength); + mul_v3_v3fl(lnor_ed->nloc, lnor_ed->niloc, 1.0f - strength); + add_v3_v3(lnor_ed->nloc, spherized_normal); + } + else if (do_align) { + sub_v3_v3v3(lnor_ed->nloc, target, center); + } + else { + sub_v3_v3v3(lnor_ed->nloc, target, lnor_ed->loc); + } + + if (do_invert && !do_reset) { + negate_v3(lnor_ed->nloc); + } + if (normalize_v3(lnor_ed->nloc) >= CLNORS_VALID_VEC_LEN) { + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + } } static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - float target[3]; - - int ret = OPERATOR_PASS_THROUGH; - int mode = RNA_enum_get(op->ptr, "mode"); - int new_mode = mode; - bool force_mousemove = false; - bool do_reset = false; - - PropertyRNA *prop_target = RNA_struct_find_property(op->ptr, "target_location"); - - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case EDBM_CLNOR_MODAL_CONFIRM: - RNA_property_float_get_array(op->ptr, prop_target, target); - ret = OPERATOR_FINISHED; - break; - - case EDBM_CLNOR_MODAL_CANCEL: - do_reset = true; - ret = OPERATOR_CANCELLED; - break; - - case EDBM_CLNOR_MODAL_POINTTO_RESET: - do_reset = true; - ret = OPERATOR_RUNNING_MODAL; - break; - - case EDBM_CLNOR_MODAL_POINTTO_INVERT: - { - PropertyRNA *prop_invert = RNA_struct_find_property(op->ptr, "invert"); - RNA_property_boolean_set(op->ptr, prop_invert, !RNA_property_boolean_get(op->ptr, prop_invert)); - RNA_property_float_get_array(op->ptr, prop_target, target); - ret = OPERATOR_RUNNING_MODAL; - break; - } - - case EDBM_CLNOR_MODAL_POINTTO_SPHERIZE: - { - PropertyRNA *prop_spherize = RNA_struct_find_property(op->ptr, "spherize"); - RNA_property_boolean_set(op->ptr, prop_spherize, !RNA_property_boolean_get(op->ptr, prop_spherize)); - RNA_property_float_get_array(op->ptr, prop_target, target); - ret = OPERATOR_RUNNING_MODAL; - break; - } - - case EDBM_CLNOR_MODAL_POINTTO_ALIGN: - { - PropertyRNA *prop_align = RNA_struct_find_property(op->ptr, "align"); - RNA_property_boolean_set(op->ptr, prop_align, !RNA_property_boolean_get(op->ptr, prop_align)); - RNA_property_float_get_array(op->ptr, prop_target, target); - ret = OPERATOR_RUNNING_MODAL; - break; - } - - case EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE: - new_mode = EDBM_CLNOR_POINTTO_MODE_MOUSE; - /* We want to immediately update to mouse cursor position... */ - force_mousemove = true; - ret = OPERATOR_RUNNING_MODAL; - break; - - case EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT: - new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; - copy_v3_v3(target, obedit->loc); - ret = OPERATOR_RUNNING_MODAL; - break; - - case EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR: - new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; - ED_view3d_cursor3d_update(C, event->mval, false, V3D_CURSOR_ORIENT_NONE); - copy_v3_v3(target, scene->cursor.location); - ret = OPERATOR_RUNNING_MODAL; - break; - - case EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED: - new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; - view3d_operator_needs_opengl(C); - if (EDBM_select_pick(C, event->mval, false, false, false)) { - /* Point to newly selected active. */ - ED_object_calc_active_center_for_editmode(obedit, false, target); - - add_v3_v3(target, obedit->loc); - ret = OPERATOR_RUNNING_MODAL; - } - break; - - case EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT: - new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; - switch (scene->toolsettings->transform_pivot_point) { - case V3D_AROUND_CENTER_BOUNDS: /* calculateCenterBound */ - { - BMVert *v; - BMIter viter; - float min[3], max[3]; - int i = 0; - - BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - if (i) { - minmax_v3v3_v3(min, max, v->co); - } - else { - copy_v3_v3(min, v->co); - copy_v3_v3(max, v->co); - } - i++; - } - } - mid_v3_v3v3(target, min, max); - add_v3_v3(target, obedit->loc); - break; - } - - case V3D_AROUND_CENTER_MEDIAN: - { - bmesh_selected_verts_center_calc(bm, target); - add_v3_v3(target, obedit->loc); - break; - } - - case V3D_AROUND_CURSOR: - copy_v3_v3(target, scene->cursor.location); - break; - - case V3D_AROUND_ACTIVE: - if (!ED_object_calc_active_center_for_editmode(obedit, false, target)) { - zero_v3(target); - } - add_v3_v3(target, obedit->loc); - break; - - default: - BKE_report(op->reports, RPT_WARNING, "Does not support Individual Origin as pivot"); - copy_v3_v3(target, obedit->loc); - } - ret = OPERATOR_RUNNING_MODAL; - break; - default: - break; - } - } - - if (new_mode != mode) { - mode = new_mode; - RNA_enum_set(op->ptr, "mode", mode); - } - - /* Only handle mousemove event in case we are in mouse mode. */ - if (event->type == MOUSEMOVE || force_mousemove) { - if (mode == EDBM_CLNOR_POINTTO_MODE_MOUSE) { - ARegion *ar = CTX_wm_region(C); - float center[3]; - - bmesh_selected_verts_center_calc(bm, center); - - ED_view3d_win_to_3d_int(v3d, ar, center, event->mval, target); - - ret = OPERATOR_RUNNING_MODAL; - } - } - - if (ret != OPERATOR_PASS_THROUGH) { - if (!ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { - RNA_property_float_set_array(op->ptr, prop_target, target); - } - point_normals_apply(C, op, target, do_reset); - EDBM_update_generic(em, true, false); /* Recheck bools. */ - - point_normals_update_header(C, op); - } - - if (ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { - point_normals_free(C, op); - } - - return ret; + View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + float target[3]; + + int ret = OPERATOR_PASS_THROUGH; + int mode = RNA_enum_get(op->ptr, "mode"); + int new_mode = mode; + bool force_mousemove = false; + bool do_reset = false; + + PropertyRNA *prop_target = RNA_struct_find_property(op->ptr, "target_location"); + + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EDBM_CLNOR_MODAL_CONFIRM: + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_FINISHED; + break; + + case EDBM_CLNOR_MODAL_CANCEL: + do_reset = true; + ret = OPERATOR_CANCELLED; + break; + + case EDBM_CLNOR_MODAL_POINTTO_RESET: + do_reset = true; + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_INVERT: { + PropertyRNA *prop_invert = RNA_struct_find_property(op->ptr, "invert"); + RNA_property_boolean_set( + op->ptr, prop_invert, !RNA_property_boolean_get(op->ptr, prop_invert)); + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_RUNNING_MODAL; + break; + } + + case EDBM_CLNOR_MODAL_POINTTO_SPHERIZE: { + PropertyRNA *prop_spherize = RNA_struct_find_property(op->ptr, "spherize"); + RNA_property_boolean_set( + op->ptr, prop_spherize, !RNA_property_boolean_get(op->ptr, prop_spherize)); + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_RUNNING_MODAL; + break; + } + + case EDBM_CLNOR_MODAL_POINTTO_ALIGN: { + PropertyRNA *prop_align = RNA_struct_find_property(op->ptr, "align"); + RNA_property_boolean_set( + op->ptr, prop_align, !RNA_property_boolean_get(op->ptr, prop_align)); + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_RUNNING_MODAL; + break; + } + + case EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE: + new_mode = EDBM_CLNOR_POINTTO_MODE_MOUSE; + /* We want to immediately update to mouse cursor position... */ + force_mousemove = true; + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + copy_v3_v3(target, obedit->loc); + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + ED_view3d_cursor3d_update(C, event->mval, false, V3D_CURSOR_ORIENT_NONE); + copy_v3_v3(target, scene->cursor.location); + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + view3d_operator_needs_opengl(C); + if (EDBM_select_pick(C, event->mval, false, false, false)) { + /* Point to newly selected active. */ + ED_object_calc_active_center_for_editmode(obedit, false, target); + + add_v3_v3(target, obedit->loc); + ret = OPERATOR_RUNNING_MODAL; + } + break; + + case EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + switch (scene->toolsettings->transform_pivot_point) { + case V3D_AROUND_CENTER_BOUNDS: /* calculateCenterBound */ + { + BMVert *v; + BMIter viter; + float min[3], max[3]; + int i = 0; + + BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + if (i) { + minmax_v3v3_v3(min, max, v->co); + } + else { + copy_v3_v3(min, v->co); + copy_v3_v3(max, v->co); + } + i++; + } + } + mid_v3_v3v3(target, min, max); + add_v3_v3(target, obedit->loc); + break; + } + + case V3D_AROUND_CENTER_MEDIAN: { + bmesh_selected_verts_center_calc(bm, target); + add_v3_v3(target, obedit->loc); + break; + } + + case V3D_AROUND_CURSOR: + copy_v3_v3(target, scene->cursor.location); + break; + + case V3D_AROUND_ACTIVE: + if (!ED_object_calc_active_center_for_editmode(obedit, false, target)) { + zero_v3(target); + } + add_v3_v3(target, obedit->loc); + break; + + default: + BKE_report(op->reports, RPT_WARNING, "Does not support Individual Origin as pivot"); + copy_v3_v3(target, obedit->loc); + } + ret = OPERATOR_RUNNING_MODAL; + break; + default: + break; + } + } + + if (new_mode != mode) { + mode = new_mode; + RNA_enum_set(op->ptr, "mode", mode); + } + + /* Only handle mousemove event in case we are in mouse mode. */ + if (event->type == MOUSEMOVE || force_mousemove) { + if (mode == EDBM_CLNOR_POINTTO_MODE_MOUSE) { + ARegion *ar = CTX_wm_region(C); + float center[3]; + + bmesh_selected_verts_center_calc(bm, center); + + ED_view3d_win_to_3d_int(v3d, ar, center, event->mval, target); + + ret = OPERATOR_RUNNING_MODAL; + } + } + + if (ret != OPERATOR_PASS_THROUGH) { + if (!ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { + RNA_property_float_set_array(op->ptr, prop_target, target); + } + point_normals_apply(C, op, target, do_reset); + EDBM_update_generic(em, true, false); /* Recheck bools. */ + + point_normals_update_header(C, op); + } + + if (ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { + point_normals_free(C, op); + } + + return ret; } static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (!point_normals_init(C, op, event)) { - point_normals_free(C, op); - return OPERATOR_CANCELLED; - } + if (!point_normals_init(C, op, event)) { + point_normals_free(C, op); + return OPERATOR_CANCELLED; + } - WM_event_add_modal_handler(C, op); + WM_event_add_modal_handler(C, op); - point_normals_update_header(C, op); + point_normals_update_header(C, op); - op->flag |= OP_IS_MODAL_GRAB_CURSOR; - return OPERATOR_RUNNING_MODAL; + op->flag |= OP_IS_MODAL_GRAB_CURSOR; + return OPERATOR_RUNNING_MODAL; } static int edbm_point_normals_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (!point_normals_init(C, op, NULL)) { - point_normals_free(C, op); - return OPERATOR_CANCELLED; - } + if (!point_normals_init(C, op, NULL)) { + point_normals_free(C, op); + return OPERATOR_CANCELLED; + } - /* Note that 'mode' is ignored in exec case, - * we directly use vector stored in target_location, whatever that is. */ + /* Note that 'mode' is ignored in exec case, + * we directly use vector stored in target_location, whatever that is. */ - float target[3]; - RNA_float_get_array(op->ptr, "target_location", target); + float target[3]; + RNA_float_get_array(op->ptr, "target_location", target); - point_normals_apply(C, op, target, false); + point_normals_apply(C, op, target, false); - EDBM_update_generic(em, true, false); - point_normals_free(C, op); + EDBM_update_generic(em, true, false); + point_normals_free(C, op); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static bool point_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) +static bool point_normals_draw_check_prop(PointerRNA *ptr, + PropertyRNA *prop, + void *UNUSED(user_data)) { - const char *prop_id = RNA_property_identifier(prop); + const char *prop_id = RNA_property_identifier(prop); - /* Only show strength option if spherize is enabled. */ - if (STREQ(prop_id, "spherize_strength")) { - return (bool)RNA_boolean_get(ptr, "spherize"); - } + /* Only show strength option if spherize is enabled. */ + if (STREQ(prop_id, "spherize_strength")) { + return (bool)RNA_boolean_get(ptr, "spherize"); + } - /* Else, show it! */ - return true; + /* Else, show it! */ + return true; } static void edbm_point_normals_ui(bContext *C, wmOperator *op) { - uiLayout *layout = op->layout; - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, point_normals_draw_check_prop, NULL, NULL, '\0', false); + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, point_normals_draw_check_prop, NULL, NULL, '\0', false); } void MESH_OT_point_normals(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Point Normals to Target"; - ot->description = "Point selected custom normals to specified Target"; - ot->idname = "MESH_OT_point_normals"; - - /* api callbacks */ - ot->exec = edbm_point_normals_exec; - ot->invoke = edbm_point_normals_invoke; - ot->modal = edbm_point_normals_modal; - ot->poll = ED_operator_editmesh_auto_smooth; - ot->ui = edbm_point_normals_ui; - ot->cancel = point_normals_free; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum(ot->srna, "mode", clnors_pointto_mode_items, EDBM_CLNOR_POINTTO_MODE_COORDINATES, - "Mode", "How to define coordinates to point custom normals to"); - RNA_def_property_flag(ot->prop, PROP_HIDDEN); - - RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert affected normals"); - - RNA_def_boolean(ot->srna, "align", false, "Align", "Make all affected normals parallel"); - - RNA_def_float_vector_xyz(ot->srna, "target_location", 3, NULL, -FLT_MAX, FLT_MAX, - "Target", "Target location to which normals will point", -1000.0f, 1000.0f); - - RNA_def_boolean(ot->srna, "spherize", false, - "Spherize", "Interpolate between original and new normals"); - - RNA_def_float(ot->srna, "spherize_strength", 0.1, 0.0f, 1.0f, - "Spherize Strength", "Ratio of spherized normal to original normal", 0.0f, 1.0f); + /* identifiers */ + ot->name = "Point Normals to Target"; + ot->description = "Point selected custom normals to specified Target"; + ot->idname = "MESH_OT_point_normals"; + + /* api callbacks */ + ot->exec = edbm_point_normals_exec; + ot->invoke = edbm_point_normals_invoke; + ot->modal = edbm_point_normals_modal; + ot->poll = ED_operator_editmesh_auto_smooth; + ot->ui = edbm_point_normals_ui; + ot->cancel = point_normals_free; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "mode", + clnors_pointto_mode_items, + EDBM_CLNOR_POINTTO_MODE_COORDINATES, + "Mode", + "How to define coordinates to point custom normals to"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); + + RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert affected normals"); + + RNA_def_boolean(ot->srna, "align", false, "Align", "Make all affected normals parallel"); + + RNA_def_float_vector_xyz(ot->srna, + "target_location", + 3, + NULL, + -FLT_MAX, + FLT_MAX, + "Target", + "Target location to which normals will point", + -1000.0f, + 1000.0f); + + RNA_def_boolean( + ot->srna, "spherize", false, "Spherize", "Interpolate between original and new normals"); + + RNA_def_float(ot->srna, + "spherize_strength", + 0.1, + 0.0f, + 1.0f, + "Spherize Strength", + "Ratio of spherized normal to original normal", + 0.0f, + 1.0f); } /********************** Split/Merge Loop Normals **********************/ static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr) { - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - BLI_SMALLSTACK_DECLARE(clnors, short *); + BLI_SMALLSTACK_DECLARE(clnors, short *); - BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); + BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); - BM_normals_loops_edges_tag(bm, false); + BM_normals_loops_edges_tag(bm, false); - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) { - continue; - } + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) { + continue; + } - MLoopNorSpace *lnor_space = bm->lnor_spacearr->lspacearr[lnor_ed->loop_index]; + MLoopNorSpace *lnor_space = bm->lnor_spacearr->lspacearr[lnor_ed->loop_index]; - if ((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0) { - LinkNode *loops = lnor_space->loops; - float avg_normal[3] = {0.0f, 0.0f, 0.0f}; - short *clnors_data; + if ((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0) { + LinkNode *loops = lnor_space->loops; + float avg_normal[3] = {0.0f, 0.0f, 0.0f}; + short *clnors_data; - for (; loops; loops = loops->next) { - BMLoop *l = loops->link; - const int loop_index = BM_elem_index_get(l); + for (; loops; loops = loops->next) { + BMLoop *l = loops->link; + const int loop_index = BM_elem_index_get(l); - BMLoopNorEditData *lnor_ed_tmp = lnors_ed_arr->lidx_to_lnor_editdata[loop_index]; - BLI_assert(lnor_ed_tmp->loop_index == loop_index && lnor_ed_tmp->loop == l); - add_v3_v3(avg_normal, lnor_ed_tmp->nloc); - BLI_SMALLSTACK_PUSH(clnors, lnor_ed_tmp->clnors_data); - BM_elem_flag_enable(l, BM_ELEM_TAG); - } - if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { - /* If avg normal is nearly 0, set clnor to default value. */ - zero_v3(avg_normal); - } - while ((clnors_data = BLI_SMALLSTACK_POP(clnors))) { - BKE_lnor_space_custom_normal_to_data(lnor_space, avg_normal, clnors_data); - } - } - } + BMLoopNorEditData *lnor_ed_tmp = lnors_ed_arr->lidx_to_lnor_editdata[loop_index]; + BLI_assert(lnor_ed_tmp->loop_index == loop_index && lnor_ed_tmp->loop == l); + add_v3_v3(avg_normal, lnor_ed_tmp->nloc); + BLI_SMALLSTACK_PUSH(clnors, lnor_ed_tmp->clnors_data); + BM_elem_flag_enable(l, BM_ELEM_TAG); + } + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + while ((clnors_data = BLI_SMALLSTACK_POP(clnors))) { + BKE_lnor_space_custom_normal_to_data(lnor_space, avg_normal, clnors_data); + } + } + } } static void normals_split(BMesh *bm) { - BMFace *f; - BMLoop *l, *l_curr, *l_first; - BMIter fiter; - - BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); - - BM_normals_loops_edges_tag(bm, true); - - const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); - BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { - l_curr = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || - (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) - { - if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { - const int loop_index = BM_elem_index_get(l_curr); - short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); - } - else { - BMVert *v_pivot = l_curr->v; - UNUSED_VARS_NDEBUG(v_pivot); - BMEdge *e_next; - const BMEdge *e_org = l_curr->e; - BMLoop *lfan_pivot, *lfan_pivot_next; - - lfan_pivot = l_curr; - e_next = lfan_pivot->e; - BLI_SMALLSTACK_DECLARE(loops, BMLoop *); - float avg_normal[3] = { 0.0f }; - - while (true) { - lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); - if (lfan_pivot_next) { - BLI_assert(lfan_pivot_next->v == v_pivot); - } - else { - e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; - } - - BLI_SMALLSTACK_PUSH(loops, lfan_pivot); - add_v3_v3(avg_normal, lfan_pivot->f->no); - - if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { - break; - } - lfan_pivot = lfan_pivot_next; - } - if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { - /* If avg normal is nearly 0, set clnor to default value. */ - zero_v3(avg_normal); - } - while ((l = BLI_SMALLSTACK_POP(loops))) { - const int l_index = BM_elem_index_get(l); - short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); - } - } - } - } while ((l_curr = l_curr->next) != l_first); - } + BMFace *f; + BMLoop *l, *l_curr, *l_first; + BMIter fiter; + + BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); + + BM_normals_loops_edges_tag(bm, true); + + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + l_curr = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && + (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || + (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) { + if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && + !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { + const int loop_index = BM_elem_index_get(l_curr); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); + } + else { + BMVert *v_pivot = l_curr->v; + UNUSED_VARS_NDEBUG(v_pivot); + BMEdge *e_next; + const BMEdge *e_org = l_curr->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + + lfan_pivot = l_curr; + e_next = lfan_pivot->e; + BLI_SMALLSTACK_DECLARE(loops, BMLoop *); + float avg_normal[3] = {0.0f}; + + while (true) { + lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); + if (lfan_pivot_next) { + BLI_assert(lfan_pivot_next->v == v_pivot); + } + else { + e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; + } + + BLI_SMALLSTACK_PUSH(loops, lfan_pivot); + add_v3_v3(avg_normal, lfan_pivot->f->no); + + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; + } + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + while ((l = BLI_SMALLSTACK_POP(loops))) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); + } + } + } + } while ((l_curr = l_curr->next) != l_first); + } } static int normals_split_merge(bContext *C, const bool do_merge) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMEdge *e; - BMIter eiter; + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMEdge *e; + BMIter eiter; - BKE_editmesh_lnorspace_update(em); + BKE_editmesh_lnorspace_update(em); - BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm) : NULL; + BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm) : NULL; - mesh_set_smooth_faces(em, do_merge); + mesh_set_smooth_faces(em, do_merge); - BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge); - } - } + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge); + } + } - bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; - BKE_editmesh_lnorspace_update(em); + bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; + BKE_editmesh_lnorspace_update(em); - if (do_merge) { - normals_merge(bm, lnors_ed_arr); - } - else { - normals_split(bm); - } + if (do_merge) { + normals_merge(bm, lnors_ed_arr); + } + else { + normals_split(bm); + } - if (lnors_ed_arr) { - BM_loop_normal_editdata_array_free(lnors_ed_arr); - } + if (lnors_ed_arr) { + BM_loop_normal_editdata_array_free(lnors_ed_arr); + } - EDBM_update_generic(em, true, false); + EDBM_update_generic(em, true, false); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int edbm_merge_normals_exec(bContext *C, wmOperator *UNUSED(op)) { - return normals_split_merge(C, true); + return normals_split_merge(C, true); } void MESH_OT_merge_normals(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Merge Normals"; - ot->description = "Merge custom normals of selected vertices"; - ot->idname = "MESH_OT_merge_normals"; + /* identifiers */ + ot->name = "Merge Normals"; + ot->description = "Merge custom normals of selected vertices"; + ot->idname = "MESH_OT_merge_normals"; - /* api callbacks */ - ot->exec = edbm_merge_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + /* api callbacks */ + ot->exec = edbm_merge_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int edbm_split_normals_exec(bContext *C, wmOperator *UNUSED(op)) { - return normals_split_merge(C, false); + return normals_split_merge(C, false); } void MESH_OT_split_normals(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Split Normals"; - ot->description = "Split custom normals of selected vertices"; - ot->idname = "MESH_OT_split_normals"; + /* identifiers */ + ot->name = "Split Normals"; + ot->description = "Split custom normals of selected vertices"; + ot->idname = "MESH_OT_split_normals"; - /* api callbacks */ - ot->exec = edbm_split_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + /* api callbacks */ + ot->exec = edbm_split_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /********************** Average Loop Normals **********************/ enum { - EDBM_CLNOR_AVERAGE_LOOP = 1, - EDBM_CLNOR_AVERAGE_FACE_AREA = 2, - EDBM_CLNOR_AVERAGE_ANGLE = 3, + EDBM_CLNOR_AVERAGE_LOOP = 1, + EDBM_CLNOR_AVERAGE_FACE_AREA = 2, + EDBM_CLNOR_AVERAGE_ANGLE = 3, }; static EnumPropertyItem average_method_items[] = { - {EDBM_CLNOR_AVERAGE_LOOP, "CUSTOM_NORMAL", 0, "Custom Normal", "Take Average of vert Normals"}, - {EDBM_CLNOR_AVERAGE_FACE_AREA, "FACE_AREA", 0, "Face Area", "Set all vert normals by Face Area"}, - {EDBM_CLNOR_AVERAGE_ANGLE, "CORNER_ANGLE", 0, "Corner Angle", "Set all vert normals by Corner Angle"}, - {0, NULL, 0, NULL, NULL}, + {EDBM_CLNOR_AVERAGE_LOOP, "CUSTOM_NORMAL", 0, "Custom Normal", "Take Average of vert Normals"}, + {EDBM_CLNOR_AVERAGE_FACE_AREA, + "FACE_AREA", + 0, + "Face Area", + "Set all vert normals by Face Area"}, + {EDBM_CLNOR_AVERAGE_ANGLE, + "CORNER_ANGLE", + 0, + "Corner Angle", + "Set all vert normals by Corner Angle"}, + {0, NULL, 0, NULL, NULL}, }; static int edbm_average_normals_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMFace *f; - BMLoop *l, *l_curr, *l_first; - BMIter fiter; - - bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; - BKE_editmesh_lnorspace_update(em); - - const int average_type = RNA_enum_get(op->ptr, "average_type"); - const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); - const float absweight = (float) RNA_int_get(op->ptr, "weight"); - const float threshold = RNA_float_get(op->ptr, "threshold"); - - float weight = absweight / 50.0f; - if (absweight == 100.0f) { - weight = (float)SHRT_MAX; - } - else if (absweight == 1.0f) { - weight = 1 / (float)SHRT_MAX; - } - else if ((weight - 1) * 25 > 1) { - weight = (weight - 1) * 25; - } - - BM_normals_loops_edges_tag(bm, true); - - HeapSimple *loop_weight = BLI_heapsimple_new(); - - BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { - l_curr = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || - (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) - { - if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { - const int loop_index = BM_elem_index_get(l_curr); - short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); - } - else { - BMVert *v_pivot = l_curr->v; - UNUSED_VARS_NDEBUG(v_pivot); - BMEdge *e_next; - const BMEdge *e_org = l_curr->e; - BMLoop *lfan_pivot, *lfan_pivot_next; - - lfan_pivot = l_curr; - e_next = lfan_pivot->e; - - while (true) { - lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); - if (lfan_pivot_next) { - BLI_assert(lfan_pivot_next->v == v_pivot); - } - else { - e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; - } - - float val = 1.0f; - if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) { - val = 1.0f / BM_face_calc_area(lfan_pivot->f); - } - else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) { - val = 1.0f / BM_loop_calc_face_angle(lfan_pivot); - } - - BLI_heapsimple_insert(loop_weight, val, lfan_pivot); - - if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { - break; - } - lfan_pivot = lfan_pivot_next; - } - - BLI_SMALLSTACK_DECLARE(loops, BMLoop *); - float wnor[3], avg_normal[3] = { 0.0f }, count = 0; - float val = BLI_heapsimple_top_value(loop_weight); - - while (!BLI_heapsimple_is_empty(loop_weight)) { - const float cur_val = BLI_heapsimple_top_value(loop_weight); - if (!compare_ff(val, cur_val, threshold)) { - count++; - val = cur_val; - } - l = BLI_heapsimple_pop_min(loop_weight); - BLI_SMALLSTACK_PUSH(loops, l); - - const float n_weight = pow(weight, count); - - if (average_type == EDBM_CLNOR_AVERAGE_LOOP) { - const int l_index = BM_elem_index_get(l); - short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], clnors, wnor); - } - else { - copy_v3_v3(wnor, l->f->no); - } - mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight)); - add_v3_v3(avg_normal, wnor); - } - - if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { - /* If avg normal is nearly 0, set clnor to default value. */ - zero_v3(avg_normal); - } - while ((l = BLI_SMALLSTACK_POP(loops))) { - const int l_index = BM_elem_index_get(l); - short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); - } - } - } - } while ((l_curr = l_curr->next) != l_first); - } - - BLI_heapsimple_free(loop_weight, NULL); - EDBM_update_generic(em, true, false); - - return OPERATOR_FINISHED; -} - -static bool average_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) -{ - const char *prop_id = RNA_property_identifier(prop); - const int average_type = RNA_enum_get(ptr, "average_type"); - - /* Only show weight/threshold options in loop average type. */ - if (STREQ(prop_id, "weight")) { - return (average_type == EDBM_CLNOR_AVERAGE_LOOP); - } - else if (STREQ(prop_id, "threshold")) { - return (average_type == EDBM_CLNOR_AVERAGE_LOOP); - } - - /* Else, show it! */ - return true; + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l, *l_curr, *l_first; + BMIter fiter; + + bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; + BKE_editmesh_lnorspace_update(em); + + const int average_type = RNA_enum_get(op->ptr, "average_type"); + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + const float absweight = (float)RNA_int_get(op->ptr, "weight"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + + float weight = absweight / 50.0f; + if (absweight == 100.0f) { + weight = (float)SHRT_MAX; + } + else if (absweight == 1.0f) { + weight = 1 / (float)SHRT_MAX; + } + else if ((weight - 1) * 25 > 1) { + weight = (weight - 1) * 25; + } + + BM_normals_loops_edges_tag(bm, true); + + HeapSimple *loop_weight = BLI_heapsimple_new(); + + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + l_curr = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && + (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || + (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) { + if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && + !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { + const int loop_index = BM_elem_index_get(l_curr); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); + } + else { + BMVert *v_pivot = l_curr->v; + UNUSED_VARS_NDEBUG(v_pivot); + BMEdge *e_next; + const BMEdge *e_org = l_curr->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + + lfan_pivot = l_curr; + e_next = lfan_pivot->e; + + while (true) { + lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); + if (lfan_pivot_next) { + BLI_assert(lfan_pivot_next->v == v_pivot); + } + else { + e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; + } + + float val = 1.0f; + if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) { + val = 1.0f / BM_face_calc_area(lfan_pivot->f); + } + else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) { + val = 1.0f / BM_loop_calc_face_angle(lfan_pivot); + } + + BLI_heapsimple_insert(loop_weight, val, lfan_pivot); + + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; + } + + BLI_SMALLSTACK_DECLARE(loops, BMLoop *); + float wnor[3], avg_normal[3] = {0.0f}, count = 0; + float val = BLI_heapsimple_top_value(loop_weight); + + while (!BLI_heapsimple_is_empty(loop_weight)) { + const float cur_val = BLI_heapsimple_top_value(loop_weight); + if (!compare_ff(val, cur_val, threshold)) { + count++; + val = cur_val; + } + l = BLI_heapsimple_pop_min(loop_weight); + BLI_SMALLSTACK_PUSH(loops, l); + + const float n_weight = pow(weight, count); + + if (average_type == EDBM_CLNOR_AVERAGE_LOOP) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_data_to_normal( + bm->lnor_spacearr->lspacearr[l_index], clnors, wnor); + } + else { + copy_v3_v3(wnor, l->f->no); + } + mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight)); + add_v3_v3(avg_normal, wnor); + } + + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + while ((l = BLI_SMALLSTACK_POP(loops))) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); + } + } + } + } while ((l_curr = l_curr->next) != l_first); + } + + BLI_heapsimple_free(loop_weight, NULL); + EDBM_update_generic(em, true, false); + + return OPERATOR_FINISHED; +} + +static bool average_normals_draw_check_prop(PointerRNA *ptr, + PropertyRNA *prop, + void *UNUSED(user_data)) +{ + const char *prop_id = RNA_property_identifier(prop); + const int average_type = RNA_enum_get(ptr, "average_type"); + + /* Only show weight/threshold options in loop average type. */ + if (STREQ(prop_id, "weight")) { + return (average_type == EDBM_CLNOR_AVERAGE_LOOP); + } + else if (STREQ(prop_id, "threshold")) { + return (average_type == EDBM_CLNOR_AVERAGE_LOOP); + } + + /* Else, show it! */ + return true; } static void edbm_average_normals_ui(bContext *C, wmOperator *op) { - uiLayout *layout = op->layout; - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, average_normals_draw_check_prop, NULL, NULL, '\0', false); + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, average_normals_draw_check_prop, NULL, NULL, '\0', false); } void MESH_OT_average_normals(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Average Normals"; - ot->description = "Average custom normals of selected vertices"; - ot->idname = "MESH_OT_average_normals"; + /* identifiers */ + ot->name = "Average Normals"; + ot->description = "Average custom normals of selected vertices"; + ot->idname = "MESH_OT_average_normals"; - /* api callbacks */ - ot->exec = edbm_average_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; - ot->ui = edbm_average_normals_ui; + /* api callbacks */ + ot->exec = edbm_average_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + ot->ui = edbm_average_normals_ui; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "average_type", average_method_items, EDBM_CLNOR_AVERAGE_LOOP, - "Type", "Averaging method"); + ot->prop = RNA_def_enum(ot->srna, + "average_type", + average_method_items, + EDBM_CLNOR_AVERAGE_LOOP, + "Type", + "Averaging method"); - RNA_def_int(ot->srna, "weight", 50, 1, 100, "Weight", "Weight applied per face", 1, 100); + RNA_def_int(ot->srna, "weight", 50, 1, 100, "Weight", "Weight applied per face", 1, 100); - RNA_def_float(ot->srna, "threshold", 0.01f, 0, 10, "Threshold", - "Threshold value for different weights to be considered equal", 0, 5); + RNA_def_float(ot->srna, + "threshold", + 0.01f, + 0, + 10, + "Threshold", + "Threshold value for different weights to be considered equal", + 0, + 5); } /********************** Custom Normal Interface Tools **********************/ enum { - EDBM_CLNOR_TOOLS_COPY = 1, - EDBM_CLNOR_TOOLS_PASTE = 2, - EDBM_CLNOR_TOOLS_MULTIPLY = 3, - EDBM_CLNOR_TOOLS_ADD = 4, - EDBM_CLNOR_TOOLS_RESET = 5, + EDBM_CLNOR_TOOLS_COPY = 1, + EDBM_CLNOR_TOOLS_PASTE = 2, + EDBM_CLNOR_TOOLS_MULTIPLY = 3, + EDBM_CLNOR_TOOLS_ADD = 4, + EDBM_CLNOR_TOOLS_RESET = 5, }; static EnumPropertyItem normal_vector_tool_items[] = { - {EDBM_CLNOR_TOOLS_COPY, "COPY", 0, "Copy Normal", "Copy normal to buffer"}, - {EDBM_CLNOR_TOOLS_PASTE, "PASTE", 0, "Paste Normal", "Paste normal from buffer"}, - {EDBM_CLNOR_TOOLS_ADD, "ADD", 0, "Add Normal", "Add normal vector with selection"}, - {EDBM_CLNOR_TOOLS_MULTIPLY, "MULTIPLY", 0, "Multiply Normal", "Multiply normal vector with selection"}, - {EDBM_CLNOR_TOOLS_RESET, "RESET", 0, "Reset Normal", "Reset buffer and/or normal of selected element"}, - {0, NULL, 0, NULL, NULL}, + {EDBM_CLNOR_TOOLS_COPY, "COPY", 0, "Copy Normal", "Copy normal to buffer"}, + {EDBM_CLNOR_TOOLS_PASTE, "PASTE", 0, "Paste Normal", "Paste normal from buffer"}, + {EDBM_CLNOR_TOOLS_ADD, "ADD", 0, "Add Normal", "Add normal vector with selection"}, + {EDBM_CLNOR_TOOLS_MULTIPLY, + "MULTIPLY", + 0, + "Multiply Normal", + "Multiply normal vector with selection"}, + {EDBM_CLNOR_TOOLS_RESET, + "RESET", + 0, + "Reset Normal", + "Reset buffer and/or normal of selected element"}, + {0, NULL, 0, NULL, NULL}, }; static int edbm_normals_tools_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - Scene *scene = CTX_data_scene(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - const int mode = RNA_enum_get(op->ptr, "mode"); - const bool absolute = RNA_boolean_get(op->ptr, "absolute"); - - BKE_editmesh_lnorspace_update(em); - BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - - float *normal_vector = scene->toolsettings->normal_vector; - - switch (mode) { - case EDBM_CLNOR_TOOLS_COPY: - if (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1) { - BKE_report(op->reports, RPT_ERROR, "Can only copy one custom normal, vertex normal or face normal"); - BM_loop_normal_editdata_array_free(lnors_ed_arr); - return OPERATOR_CANCELLED; - } - if (lnors_ed_arr->totloop == 1) { - copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); - } - else if (bm->totfacesel == 1) { - BMFace *f; - BMIter fiter; - BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - copy_v3_v3(scene->toolsettings->normal_vector, f->no); - } - } - } - else { - /* 'Vertex' normal, i.e. common set of loop normals on the same vertex, - * only if they are all the same. */ - bool are_same_lnors = true; - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) { - are_same_lnors = false; - } - } - if (are_same_lnors) { - copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); - } - } - break; - - case EDBM_CLNOR_TOOLS_PASTE: - if (!absolute) { - if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) { - /* If normal is nearly 0, do nothing. */ - break; - } - } - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - if (absolute) { - float abs_normal[3]; - copy_v3_v3(abs_normal, lnor_ed->loc); - negate_v3(abs_normal); - add_v3_v3(abs_normal, normal_vector); - - if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) { - /* If abs normal is nearly 0, set clnor to initial value. */ - copy_v3_v3(abs_normal, lnor_ed->niloc); - } - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], abs_normal, lnor_ed->clnors_data); - } - else { - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], normal_vector, lnor_ed->clnors_data); - } - } - break; - - case EDBM_CLNOR_TOOLS_MULTIPLY: - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - mul_v3_v3(lnor_ed->nloc, normal_vector); - - if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { - /* If abs normal is nearly 0, set clnor to initial value. */ - copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); - } - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); - } - break; - - case EDBM_CLNOR_TOOLS_ADD: - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - add_v3_v3(lnor_ed->nloc, normal_vector); - - if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { - /* If abs normal is nearly 0, set clnor to initial value. */ - copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); - } - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); - } - break; - - case EDBM_CLNOR_TOOLS_RESET: - zero_v3(normal_vector); - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], normal_vector, lnor_ed->clnors_data); - } - break; - - default: - BLI_assert(0); - break; - } - - BM_loop_normal_editdata_array_free(lnors_ed_arr); - - EDBM_update_generic(em, true, false); - return OPERATOR_FINISHED; -} - -static bool normals_tools_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) -{ - const char *prop_id = RNA_property_identifier(prop); - const int mode = RNA_enum_get(ptr, "mode"); - - /* Only show absolute option in paste mode. */ - if (STREQ(prop_id, "absolute")) { - return (mode == EDBM_CLNOR_TOOLS_PASTE); - } - - /* Else, show it! */ - return true; + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + const int mode = RNA_enum_get(op->ptr, "mode"); + const bool absolute = RNA_boolean_get(op->ptr, "absolute"); + + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + float *normal_vector = scene->toolsettings->normal_vector; + + switch (mode) { + case EDBM_CLNOR_TOOLS_COPY: + if (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1) { + BKE_report(op->reports, + RPT_ERROR, + "Can only copy one custom normal, vertex normal or face normal"); + BM_loop_normal_editdata_array_free(lnors_ed_arr); + return OPERATOR_CANCELLED; + } + if (lnors_ed_arr->totloop == 1) { + copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); + } + else if (bm->totfacesel == 1) { + BMFace *f; + BMIter fiter; + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + copy_v3_v3(scene->toolsettings->normal_vector, f->no); + } + } + } + else { + /* 'Vertex' normal, i.e. common set of loop normals on the same vertex, + * only if they are all the same. */ + bool are_same_lnors = true; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) { + are_same_lnors = false; + } + } + if (are_same_lnors) { + copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); + } + } + break; + + case EDBM_CLNOR_TOOLS_PASTE: + if (!absolute) { + if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) { + /* If normal is nearly 0, do nothing. */ + break; + } + } + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (absolute) { + float abs_normal[3]; + copy_v3_v3(abs_normal, lnor_ed->loc); + negate_v3(abs_normal); + add_v3_v3(abs_normal, normal_vector); + + if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(abs_normal, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], abs_normal, lnor_ed->clnors_data); + } + else { + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], + normal_vector, + lnor_ed->clnors_data); + } + } + break; + + case EDBM_CLNOR_TOOLS_MULTIPLY: + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + mul_v3_v3(lnor_ed->nloc, normal_vector); + + if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], + lnor_ed->nloc, + lnor_ed->clnors_data); + } + break; + + case EDBM_CLNOR_TOOLS_ADD: + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + add_v3_v3(lnor_ed->nloc, normal_vector); + + if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], + lnor_ed->nloc, + lnor_ed->clnors_data); + } + break; + + case EDBM_CLNOR_TOOLS_RESET: + zero_v3(normal_vector); + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], + normal_vector, + lnor_ed->clnors_data); + } + break; + + default: + BLI_assert(0); + break; + } + + BM_loop_normal_editdata_array_free(lnors_ed_arr); + + EDBM_update_generic(em, true, false); + return OPERATOR_FINISHED; +} + +static bool normals_tools_draw_check_prop(PointerRNA *ptr, + PropertyRNA *prop, + void *UNUSED(user_data)) +{ + const char *prop_id = RNA_property_identifier(prop); + const int mode = RNA_enum_get(ptr, "mode"); + + /* Only show absolute option in paste mode. */ + if (STREQ(prop_id, "absolute")) { + return (mode == EDBM_CLNOR_TOOLS_PASTE); + } + + /* Else, show it! */ + return true; } static void edbm_normals_tools_ui(bContext *C, wmOperator *op) { - uiLayout *layout = op->layout; - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, normals_tools_draw_check_prop, NULL, NULL, '\0', false); + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, normals_tools_draw_check_prop, NULL, NULL, '\0', false); } void MESH_OT_normals_tools(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Normals Vector Tools"; - ot->description = "Custom normals tools using Normal Vector of UI"; - ot->idname = "MESH_OT_normals_tools"; + /* identifiers */ + ot->name = "Normals Vector Tools"; + ot->description = "Custom normals tools using Normal Vector of UI"; + ot->idname = "MESH_OT_normals_tools"; - /* api callbacks */ - ot->exec = edbm_normals_tools_exec; - ot->poll = ED_operator_editmesh_auto_smooth; - ot->ui = edbm_normals_tools_ui; + /* api callbacks */ + ot->exec = edbm_normals_tools_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + ot->ui = edbm_normals_tools_ui; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "mode", normal_vector_tool_items, EDBM_CLNOR_TOOLS_COPY, - "Mode", "Mode of tools taking input from Interface"); - RNA_def_property_flag(ot->prop, PROP_HIDDEN); + ot->prop = RNA_def_enum(ot->srna, + "mode", + normal_vector_tool_items, + EDBM_CLNOR_TOOLS_COPY, + "Mode", + "Mode of tools taking input from Interface"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); - RNA_def_boolean(ot->srna, "absolute", false, "Absolute Coordinates", "Copy Absolute coordinates or Normal vector"); + RNA_def_boolean(ot->srna, + "absolute", + false, + "Absolute Coordinates", + "Copy Absolute coordinates or Normal vector"); } static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMFace *f; - BMVert *v; - BMEdge *e; - BMLoop *l; - BMIter fiter, viter, eiter, liter; - - const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp"); - - BKE_editmesh_lnorspace_update(em); - - float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bm->totvert, __func__); - BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_ITER_ELEM(v, &viter, f, BM_VERTS_OF_FACE) { - const int v_index = BM_elem_index_get(v); - add_v3_v3(vnors[v_index], f->no); - } - } - } - for (int i = 0; i < bm->totvert; i++) { - if (!is_zero_v3(vnors[i]) && normalize_v3(vnors[i]) < CLNORS_VALID_VEC_LEN) { - zero_v3(vnors[i]); - } - } - - BLI_bitmap *loop_set = BLI_BITMAP_NEW(bm->totloop, __func__); - const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); - - BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM(e, &eiter, f, BM_EDGES_OF_FACE) { - if (!keep_sharp || (BM_elem_flag_test(e, BM_ELEM_SMOOTH) && BM_elem_flag_test(e, BM_ELEM_SELECT))) { - BM_ITER_ELEM(v, &viter, e, BM_VERTS_OF_EDGE) { - l = BM_face_vert_share_loop(f, v); - const int l_index = BM_elem_index_get(l); - const int v_index = BM_elem_index_get(l->v); - - if (!is_zero_v3(vnors[v_index])) { - short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[l_index], vnors[v_index], clnors); - - if (bm->lnor_spacearr->lspacearr[l_index]->flags & MLNOR_SPACE_IS_SINGLE) { - BLI_BITMAP_ENABLE(loop_set, l_index); - } - else { - LinkNode *loops = bm->lnor_spacearr->lspacearr[l_index]->loops; - for (; loops; loops = loops->next) { - BLI_BITMAP_ENABLE(loop_set, BM_elem_index_get((BMLoop *)loops->link)); - } - } - } - } - } - } - } - - int v_index; - BM_ITER_MESH_INDEX(v, &viter, bm, BM_VERTS_OF_MESH, v_index) { - BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { - if (BLI_BITMAP_TEST(loop_set, BM_elem_index_get(l))) { - const int loop_index = BM_elem_index_get(l); - short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[loop_index], vnors[v_index], clnors); - } - } - } - - MEM_freeN(loop_set); - MEM_freeN(vnors); - EDBM_update_generic(em, true, false); - } - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMVert *v; + BMEdge *e; + BMLoop *l; + BMIter fiter, viter, eiter, liter; + + const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp"); + + BKE_editmesh_lnorspace_update(em); + + float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bm->totvert, __func__); + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) { + const int v_index = BM_elem_index_get(v); + add_v3_v3(vnors[v_index], f->no); + } + } + } + for (int i = 0; i < bm->totvert; i++) { + if (!is_zero_v3(vnors[i]) && normalize_v3(vnors[i]) < CLNORS_VALID_VEC_LEN) { + zero_v3(vnors[i]); + } + } + + BLI_bitmap *loop_set = BLI_BITMAP_NEW(bm->totloop, __func__); + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) { + if (!keep_sharp || + (BM_elem_flag_test(e, BM_ELEM_SMOOTH) && BM_elem_flag_test(e, BM_ELEM_SELECT))) { + BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { + l = BM_face_vert_share_loop(f, v); + const int l_index = BM_elem_index_get(l); + const int v_index = BM_elem_index_get(l->v); + + if (!is_zero_v3(vnors[v_index])) { + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[l_index], vnors[v_index], clnors); + + if (bm->lnor_spacearr->lspacearr[l_index]->flags & MLNOR_SPACE_IS_SINGLE) { + BLI_BITMAP_ENABLE(loop_set, l_index); + } + else { + LinkNode *loops = bm->lnor_spacearr->lspacearr[l_index]->loops; + for (; loops; loops = loops->next) { + BLI_BITMAP_ENABLE(loop_set, BM_elem_index_get((BMLoop *)loops->link)); + } + } + } + } + } + } + } + + int v_index; + BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, v_index) { + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (BLI_BITMAP_TEST(loop_set, BM_elem_index_get(l))) { + const int loop_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[loop_index], vnors[v_index], clnors); + } + } + } + + MEM_freeN(loop_set); + MEM_freeN(vnors); + EDBM_update_generic(em, true, false); + } + + return OPERATOR_FINISHED; } void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Normals From Faces"; - ot->description = "Set the custom normals from the selected faces ones"; - ot->idname = "MESH_OT_set_normals_from_faces"; + /* identifiers */ + ot->name = "Set Normals From Faces"; + ot->description = "Set the custom normals from the selected faces ones"; + ot->idname = "MESH_OT_set_normals_from_faces"; - /* api callbacks */ - ot->exec = edbm_set_normals_from_faces_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + /* api callbacks */ + ot->exec = edbm_set_normals_from_faces_exec; + ot->poll = ED_operator_editmesh_auto_smooth; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face"); + RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face"); } static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMFace *f; - BMLoop *l; - BMIter fiter, liter; - - BKE_editmesh_lnorspace_update(em); - BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); - - float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, __func__); - - /* This is weird choice of operation, taking all loops of faces of current vertex... Could lead to some rather - * far away loops weighting as much as very close ones (topologically speaking), with complex polygons. - * Using topological distance here (rather than geometrical one) makes sense imho, but would rather go with - * a more consistent and flexible code, we could even add max topological distance to take into account, - * and a weighting curve... - * Would do that later though, think for now we can live with that choice. --mont29 */ - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - l = lnor_ed->loop; - float loop_normal[3]; - - BM_ITER_ELEM(f, &fiter, l->v, BM_FACES_OF_VERT) { - BMLoop *l_other; - BM_ITER_ELEM(l_other, &liter, f, BM_LOOPS_OF_FACE) { - const int l_index_other = BM_elem_index_get(l_other); - short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset); - BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal); - add_v3_v3(smooth_normal[i], loop_normal); - } - } - } - - const float factor = RNA_float_get(op->ptr, "factor"); - - lnor_ed = lnors_ed_arr->lnor_editdata; - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - float current_normal[3]; - - if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) { - /* Skip in case smoothen normal is invalid... */ - continue; - } - - BKE_lnor_space_custom_data_to_normal( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal); - - /* Note: again, this is not true spherical interpolation that normals would need... - * But it's probably good enough for now. */ - mul_v3_fl(current_normal, 1.0f - factor); - mul_v3_fl(smooth_normal[i], factor); - add_v3_v3(current_normal, smooth_normal[i]); - - if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) { - /* Skip in case smoothen normal is invalid... */ - continue; - } - - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data); - } - - BM_loop_normal_editdata_array_free(lnors_ed_arr); - MEM_freeN(smooth_normal); - - EDBM_update_generic(em, true, false); - - return OPERATOR_FINISHED; + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + + float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, __func__); + + /* This is weird choice of operation, taking all loops of faces of current vertex... Could lead to some rather + * far away loops weighting as much as very close ones (topologically speaking), with complex polygons. + * Using topological distance here (rather than geometrical one) makes sense imho, but would rather go with + * a more consistent and flexible code, we could even add max topological distance to take into account, + * and a weighting curve... + * Would do that later though, think for now we can live with that choice. --mont29 */ + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + l = lnor_ed->loop; + float loop_normal[3]; + + BM_ITER_ELEM (f, &fiter, l->v, BM_FACES_OF_VERT) { + BMLoop *l_other; + BM_ITER_ELEM (l_other, &liter, f, BM_LOOPS_OF_FACE) { + const int l_index_other = BM_elem_index_get(l_other); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset); + BKE_lnor_space_custom_data_to_normal( + bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal); + add_v3_v3(smooth_normal[i], loop_normal); + } + } + } + + const float factor = RNA_float_get(op->ptr, "factor"); + + lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + float current_normal[3]; + + if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) { + /* Skip in case smoothen normal is invalid... */ + continue; + } + + BKE_lnor_space_custom_data_to_normal( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal); + + /* Note: again, this is not true spherical interpolation that normals would need... + * But it's probably good enough for now. */ + mul_v3_fl(current_normal, 1.0f - factor); + mul_v3_fl(smooth_normal[i], factor); + add_v3_v3(current_normal, smooth_normal[i]); + + if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) { + /* Skip in case smoothen normal is invalid... */ + continue; + } + + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data); + } + + BM_loop_normal_editdata_array_free(lnors_ed_arr); + MEM_freeN(smooth_normal); + + EDBM_update_generic(em, true, false); + + return OPERATOR_FINISHED; } void MESH_OT_smoothen_normals(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Smoothen Normals"; - ot->description = "Smoothen custom normals based on adjacent vertex normals"; - ot->idname = "MESH_OT_smoothen_normals"; + /* identifiers */ + ot->name = "Smoothen Normals"; + ot->description = "Smoothen custom normals based on adjacent vertex normals"; + ot->idname = "MESH_OT_smoothen_normals"; - /* api callbacks */ - ot->exec = edbm_smoothen_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + /* api callbacks */ + ot->exec = edbm_smoothen_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", - "Specifies weight of smooth vs original normal", 0.0f, 1.0f); + RNA_def_float(ot->srna, + "factor", + 0.5f, + 0.0f, + 1.0f, + "Factor", + "Specifies weight of smooth vs original normal", + 0.0f, + 1.0f); } /********************** Weighted Normal Modifier Face Strength **********************/ static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMFace *f; - BMIter fiter; - - BM_select_history_clear(bm); - - const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID; - int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); - if (cd_prop_int_index == -1) { - BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id); - cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); - } - cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT); - const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_index); - - const int face_strength = scene->toolsettings->face_strength; - const bool set = RNA_boolean_get(op->ptr, "set"); - BM_mesh_elem_index_ensure(bm, BM_FACE); - - if (set) { - BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); - *strength = face_strength; - } - } - } - else { - BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { - int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); - if (*strength == face_strength) { - BM_face_select_set(bm, f, true); - BM_select_history_store(bm, f); - } - else { - BM_face_select_set(bm, f, false); - } - } - } - - EDBM_update_generic(em, false, false); - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMIter fiter; + + BM_select_history_clear(bm); + + const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID; + int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); + if (cd_prop_int_index == -1) { + BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id); + cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); + } + cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT); + const int cd_prop_int_offset = CustomData_get_n_offset( + &bm->pdata, CD_PROP_INT, cd_prop_int_index); + + const int face_strength = scene->toolsettings->face_strength; + const bool set = RNA_boolean_get(op->ptr, "set"); + BM_mesh_elem_index_ensure(bm, BM_FACE); + + if (set) { + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); + *strength = face_strength; + } + } + } + else { + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); + if (*strength == face_strength) { + BM_face_select_set(bm, f, true); + BM_select_history_store(bm, f); + } + else { + BM_face_select_set(bm, f, false); + } + } + } + + EDBM_update_generic(em, false, false); + return OPERATOR_FINISHED; } void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Face Strength"; - ot->description = "Set/Get strength of face (used in Weighted Normal modifier)"; - ot->idname = "MESH_OT_mod_weighted_strength"; + /* identifiers */ + ot->name = "Face Strength"; + ot->description = "Set/Get strength of face (used in Weighted Normal modifier)"; + ot->idname = "MESH_OT_mod_weighted_strength"; - /* api callbacks */ - ot->exec = edbm_mod_weighted_strength_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + /* api callbacks */ + ot->exec = edbm_mod_weighted_strength_exec; + ot->poll = ED_operator_editmesh_auto_smooth; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set value", "Set Value of faces"); - RNA_def_property_flag(ot->prop, PROP_HIDDEN); + ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set value", "Set Value of faces"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); } diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 5ea3fa784a5..2e855d9c5de 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -59,7 +59,7 @@ # include "BLI_array_store.h" # include "BLI_array_store_utils.h" - /* check on best size later... */ +/* check on best size later... */ # define ARRAY_CHUNK_SIZE 256 # define USE_ARRAY_STORE_THREAD @@ -80,198 +80,199 @@ static CLG_LogRef LOG = {"ed.undo.mesh"}; /* Single linked list of layers stored per type */ typedef struct BArrayCustomData { - struct BArrayCustomData *next; - CustomDataType type; - int states_len; /* number of layers for each type */ - BArrayState *states[0]; + struct BArrayCustomData *next; + CustomDataType type; + int states_len; /* number of layers for each type */ + BArrayState *states[0]; } BArrayCustomData; #endif typedef struct UndoMesh { - Mesh me; - int selectmode; - - /** \note - * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]), - * but editing shape keys, going into object mode, removing or changing their order, - * then go back into editmode and undo will give issues - where the old index will be out of sync - * with the new object index. - * - * There are a few ways this could be made to work but for now its a known limitation with mixing - * object and editmode operations - Campbell */ - int shapenr; + Mesh me; + int selectmode; + + /** \note + * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]), + * but editing shape keys, going into object mode, removing or changing their order, + * then go back into editmode and undo will give issues - where the old index will be out of sync + * with the new object index. + * + * There are a few ways this could be made to work but for now its a known limitation with mixing + * object and editmode operations - Campbell */ + int shapenr; #ifdef USE_ARRAY_STORE - /* NULL arrays are considered empty */ - struct { /* most data is stored as 'custom' data */ - BArrayCustomData *vdata, *edata, *ldata, *pdata; - BArrayState **keyblocks; - BArrayState *mselect; - } store; -#endif /* USE_ARRAY_STORE */ - - size_t undo_size; + /* NULL arrays are considered empty */ + struct { /* most data is stored as 'custom' data */ + BArrayCustomData *vdata, *edata, *ldata, *pdata; + BArrayState **keyblocks; + BArrayState *mselect; + } store; +#endif /* USE_ARRAY_STORE */ + + size_t undo_size; } UndoMesh; - #ifdef USE_ARRAY_STORE /** \name Array Store * \{ */ static struct { - struct BArrayStore_AtSize bs_stride; - int users; + struct BArrayStore_AtSize bs_stride; + int users; - /* We could have the undo API pass in the previous state, for now store a local list */ - ListBase local_links; + /* We could have the undo API pass in the previous state, for now store a local list */ + ListBase local_links; -#ifdef USE_ARRAY_STORE_THREAD - TaskPool *task_pool; -#endif +# ifdef USE_ARRAY_STORE_THREAD + TaskPool *task_pool; +# endif } um_arraystore = {{NULL}}; -static void um_arraystore_cd_compact( - struct CustomData *cdata, const size_t data_len, - bool create, - const BArrayCustomData *bcd_reference, - BArrayCustomData **r_bcd_first) +static void um_arraystore_cd_compact(struct CustomData *cdata, + const size_t data_len, + bool create, + const BArrayCustomData *bcd_reference, + BArrayCustomData **r_bcd_first) { - if (data_len == 0) { - if (create) { - *r_bcd_first = NULL; - } - } - - const BArrayCustomData *bcd_reference_current = bcd_reference; - BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL; - for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) { - const CustomDataType type = cdata->layers[layer_start].type; - - layer_end = layer_start + 1; - while ((layer_end < cdata->totlayer) && - (type == cdata->layers[layer_end].type)) - { - layer_end++; - } - - const int stride = CustomData_sizeof(type); - BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL; - const int layer_len = layer_end - layer_start; - - if (create) { - if (bcd_reference_current && (bcd_reference_current->type == type)) { - /* common case, the reference is aligned */ - } - else { - bcd_reference_current = NULL; - - /* do a full lookup when un-alligned */ - if (bcd_reference) { - const BArrayCustomData *bcd_iter = bcd_reference; - while (bcd_iter) { - if (bcd_iter->type == type) { - bcd_reference_current = bcd_iter; - break; - } - bcd_iter = bcd_iter->next; - } - } - } - } - - if (create) { - bcd = MEM_callocN(sizeof(BArrayCustomData) + (layer_len * sizeof(BArrayState *)), __func__); - bcd->next = NULL; - bcd->type = type; - bcd->states_len = layer_end - layer_start; - - if (bcd_prev) { - bcd_prev->next = bcd; - bcd_prev = bcd; - } - else { - bcd_first = bcd; - bcd_prev = bcd; - } - } - - CustomDataLayer *layer = &cdata->layers[layer_start]; - for (int i = 0; i < layer_len; i++, layer++) { - if (create) { - if (layer->data) { - BArrayState *state_reference = - (bcd_reference_current && i < bcd_reference_current->states_len) ? - bcd_reference_current->states[i] : NULL; - bcd->states[i] = BLI_array_store_state_add( - bs, layer->data, (size_t)data_len * stride, state_reference); - } - else { - bcd->states[i] = NULL; - } - } - - if (layer->data) { - MEM_freeN(layer->data); - layer->data = NULL; - } - } - - if (create) { - if (bcd_reference_current) { - bcd_reference_current = bcd_reference_current->next; - } - } - } - - if (create) { - *r_bcd_first = bcd_first; - } + if (data_len == 0) { + if (create) { + *r_bcd_first = NULL; + } + } + + const BArrayCustomData *bcd_reference_current = bcd_reference; + BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL; + for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) { + const CustomDataType type = cdata->layers[layer_start].type; + + layer_end = layer_start + 1; + while ((layer_end < cdata->totlayer) && (type == cdata->layers[layer_end].type)) { + layer_end++; + } + + const int stride = CustomData_sizeof(type); + BArrayStore *bs = create ? BLI_array_store_at_size_ensure( + &um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : + NULL; + const int layer_len = layer_end - layer_start; + + if (create) { + if (bcd_reference_current && (bcd_reference_current->type == type)) { + /* common case, the reference is aligned */ + } + else { + bcd_reference_current = NULL; + + /* do a full lookup when un-alligned */ + if (bcd_reference) { + const BArrayCustomData *bcd_iter = bcd_reference; + while (bcd_iter) { + if (bcd_iter->type == type) { + bcd_reference_current = bcd_iter; + break; + } + bcd_iter = bcd_iter->next; + } + } + } + } + + if (create) { + bcd = MEM_callocN(sizeof(BArrayCustomData) + (layer_len * sizeof(BArrayState *)), __func__); + bcd->next = NULL; + bcd->type = type; + bcd->states_len = layer_end - layer_start; + + if (bcd_prev) { + bcd_prev->next = bcd; + bcd_prev = bcd; + } + else { + bcd_first = bcd; + bcd_prev = bcd; + } + } + + CustomDataLayer *layer = &cdata->layers[layer_start]; + for (int i = 0; i < layer_len; i++, layer++) { + if (create) { + if (layer->data) { + BArrayState *state_reference = (bcd_reference_current && + i < bcd_reference_current->states_len) ? + bcd_reference_current->states[i] : + NULL; + bcd->states[i] = BLI_array_store_state_add( + bs, layer->data, (size_t)data_len * stride, state_reference); + } + else { + bcd->states[i] = NULL; + } + } + + if (layer->data) { + MEM_freeN(layer->data); + layer->data = NULL; + } + } + + if (create) { + if (bcd_reference_current) { + bcd_reference_current = bcd_reference_current->next; + } + } + } + + if (create) { + *r_bcd_first = bcd_first; + } } /** * \note There is no room for data going out of sync here. * The layers and the states are stored together so this can be kept working. */ -static void um_arraystore_cd_expand( - const BArrayCustomData *bcd, struct CustomData *cdata, const size_t data_len) +static void um_arraystore_cd_expand(const BArrayCustomData *bcd, + struct CustomData *cdata, + const size_t data_len) { - CustomDataLayer *layer = cdata->layers; - while (bcd) { - const int stride = CustomData_sizeof(bcd->type); - for (int i = 0; i < bcd->states_len; i++) { - BLI_assert(bcd->type == layer->type); - if (bcd->states[i]) { - size_t state_len; - layer->data = BLI_array_store_state_data_get_alloc(bcd->states[i], &state_len); - BLI_assert(stride * data_len == state_len); - UNUSED_VARS_NDEBUG(stride, data_len); - } - else { - layer->data = NULL; - } - layer++; - } - bcd = bcd->next; - } + CustomDataLayer *layer = cdata->layers; + while (bcd) { + const int stride = CustomData_sizeof(bcd->type); + for (int i = 0; i < bcd->states_len; i++) { + BLI_assert(bcd->type == layer->type); + if (bcd->states[i]) { + size_t state_len; + layer->data = BLI_array_store_state_data_get_alloc(bcd->states[i], &state_len); + BLI_assert(stride * data_len == state_len); + UNUSED_VARS_NDEBUG(stride, data_len); + } + else { + layer->data = NULL; + } + layer++; + } + bcd = bcd->next; + } } static void um_arraystore_cd_free(BArrayCustomData *bcd) { - while (bcd) { - BArrayCustomData *bcd_next = bcd->next; - const int stride = CustomData_sizeof(bcd->type); - BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); - for (int i = 0; i < bcd->states_len; i++) { - if (bcd->states[i]) { - BLI_array_store_state_remove(bs, bcd->states[i]); - } - } - MEM_freeN(bcd); - bcd = bcd_next; - } + while (bcd) { + BArrayCustomData *bcd_next = bcd->next; + const int stride = CustomData_sizeof(bcd->type); + BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); + for (int i = 0; i < bcd->states_len; i++) { + if (bcd->states[i]) { + BLI_array_store_state_remove(bs, bcd->states[i]); + } + } + MEM_freeN(bcd); + bcd = bcd_next; + } } /** @@ -279,61 +280,65 @@ static void um_arraystore_cd_free(BArrayCustomData *bcd) * This is done since when reading from an undo state, they must be temporarily expanded. * then discarded afterwards, having this argument avoids having 2x code paths. */ -static void um_arraystore_compact_ex( - UndoMesh *um, const UndoMesh *um_ref, - bool create) +static void um_arraystore_compact_ex(UndoMesh *um, const UndoMesh *um_ref, bool create) { - Mesh *me = &um->me; - - um_arraystore_cd_compact(&me->vdata, me->totvert, create, um_ref ? um_ref->store.vdata : NULL, &um->store.vdata); - um_arraystore_cd_compact(&me->edata, me->totedge, create, um_ref ? um_ref->store.edata : NULL, &um->store.edata); - um_arraystore_cd_compact(&me->ldata, me->totloop, create, um_ref ? um_ref->store.ldata : NULL, &um->store.ldata); - um_arraystore_cd_compact(&me->pdata, me->totpoly, create, um_ref ? um_ref->store.pdata : NULL, &um->store.pdata); - - if (me->key && me->key->totkey) { - const size_t stride = me->key->elemsize; - BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL; - if (create) { - um->store.keyblocks = MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__); - } - KeyBlock *keyblock = me->key->block.first; - for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) { - if (create) { - BArrayState *state_reference = - (um_ref && um_ref->me.key && (i < um_ref->me.key->totkey)) ? - um_ref->store.keyblocks[i] : NULL; - um->store.keyblocks[i] = BLI_array_store_state_add( - bs, keyblock->data, (size_t)keyblock->totelem * stride, - state_reference); - } - - if (keyblock->data) { - MEM_freeN(keyblock->data); - keyblock->data = NULL; - } - } - } - - if (me->mselect && me->totselect) { - BLI_assert(create == (um->store.mselect == NULL)); - if (create) { - BArrayState *state_reference = um_ref ? um_ref->store.mselect : NULL; - const size_t stride = sizeof(*me->mselect); - BArrayStore *bs = BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); - um->store.mselect = BLI_array_store_state_add( - bs, me->mselect, (size_t)me->totselect * stride, state_reference); - } - - /* keep me->totselect for validation */ - MEM_freeN(me->mselect); - me->mselect = NULL; - } - - if (create) { - um_arraystore.users += 1; - } - - BKE_mesh_update_customdata_pointers(me, false); + Mesh *me = &um->me; + + um_arraystore_cd_compact( + &me->vdata, me->totvert, create, um_ref ? um_ref->store.vdata : NULL, &um->store.vdata); + um_arraystore_cd_compact( + &me->edata, me->totedge, create, um_ref ? um_ref->store.edata : NULL, &um->store.edata); + um_arraystore_cd_compact( + &me->ldata, me->totloop, create, um_ref ? um_ref->store.ldata : NULL, &um->store.ldata); + um_arraystore_cd_compact( + &me->pdata, me->totpoly, create, um_ref ? um_ref->store.pdata : NULL, &um->store.pdata); + + if (me->key && me->key->totkey) { + const size_t stride = me->key->elemsize; + BArrayStore *bs = create ? BLI_array_store_at_size_ensure( + &um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : + NULL; + if (create) { + um->store.keyblocks = MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__); + } + KeyBlock *keyblock = me->key->block.first; + for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) { + if (create) { + BArrayState *state_reference = (um_ref && um_ref->me.key && (i < um_ref->me.key->totkey)) ? + um_ref->store.keyblocks[i] : + NULL; + um->store.keyblocks[i] = BLI_array_store_state_add( + bs, keyblock->data, (size_t)keyblock->totelem * stride, state_reference); + } + + if (keyblock->data) { + MEM_freeN(keyblock->data); + keyblock->data = NULL; + } + } + } + + if (me->mselect && me->totselect) { + BLI_assert(create == (um->store.mselect == NULL)); + if (create) { + BArrayState *state_reference = um_ref ? um_ref->store.mselect : NULL; + const size_t stride = sizeof(*me->mselect); + BArrayStore *bs = BLI_array_store_at_size_ensure( + &um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); + um->store.mselect = BLI_array_store_state_add( + bs, me->mselect, (size_t)me->totselect * stride, state_reference); + } + + /* keep me->totselect for validation */ + MEM_freeN(me->mselect); + me->mselect = NULL; + } + + if (create) { + um_arraystore.users += 1; + } + + BKE_mesh_update_customdata_pointers(me, false); } /** @@ -341,332 +346,341 @@ static void um_arraystore_compact_ex( */ static void um_arraystore_compact(UndoMesh *um, const UndoMesh *um_ref) { - um_arraystore_compact_ex(um, um_ref, true); + um_arraystore_compact_ex(um, um_ref, true); } static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref) { -#ifdef DEBUG_PRINT - size_t size_expanded_prev, size_compacted_prev; - BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev); -#endif - -#ifdef DEBUG_TIME - TIMEIT_START(mesh_undo_compact); -#endif - - um_arraystore_compact(um, um_ref); - -#ifdef DEBUG_TIME - TIMEIT_END(mesh_undo_compact); -#endif +# ifdef DEBUG_PRINT + size_t size_expanded_prev, size_compacted_prev; + BLI_array_store_at_size_calc_memory_usage( + &um_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev); +# endif -#ifdef DEBUG_PRINT - { - size_t size_expanded, size_compacted; - BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded, &size_compacted); +# ifdef DEBUG_TIME + TIMEIT_START(mesh_undo_compact); +# endif - const double percent_total = size_expanded ? - (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0; + um_arraystore_compact(um, um_ref); - size_t size_expanded_step = size_expanded - size_expanded_prev; - size_t size_compacted_step = size_compacted - size_compacted_prev; - const double percent_step = size_expanded_step ? - (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0; +# ifdef DEBUG_TIME + TIMEIT_END(mesh_undo_compact); +# endif - printf("overall memory use: %.8f%% of expanded size\n", percent_total); - printf("step memory use: %.8f%% of expanded size\n", percent_step); - } -#endif +# ifdef DEBUG_PRINT + { + size_t size_expanded, size_compacted; + BLI_array_store_at_size_calc_memory_usage( + &um_arraystore.bs_stride, &size_expanded, &size_compacted); + + const double percent_total = size_expanded ? + (((double)size_compacted / (double)size_expanded) * 100.0) : + -1.0; + + size_t size_expanded_step = size_expanded - size_expanded_prev; + size_t size_compacted_step = size_compacted - size_compacted_prev; + const double percent_step = size_expanded_step ? + (((double)size_compacted_step / (double)size_expanded_step) * + 100.0) : + -1.0; + + printf("overall memory use: %.8f%% of expanded size\n", percent_total); + printf("step memory use: %.8f%% of expanded size\n", percent_step); + } +# endif } -#ifdef USE_ARRAY_STORE_THREAD +# ifdef USE_ARRAY_STORE_THREAD struct UMArrayData { - UndoMesh *um; - const UndoMesh *um_ref; /* can be NULL */ + UndoMesh *um; + const UndoMesh *um_ref; /* can be NULL */ }; static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) { - struct UMArrayData *um_data = taskdata; - um_arraystore_compact_with_info(um_data->um, um_data->um_ref); + struct UMArrayData *um_data = taskdata; + um_arraystore_compact_with_info(um_data->um, um_data->um_ref); } -#endif /* USE_ARRAY_STORE_THREAD */ +# endif /* USE_ARRAY_STORE_THREAD */ /** * Remove data we only expanded for temporary use. */ static void um_arraystore_expand_clear(UndoMesh *um) { - um_arraystore_compact_ex(um, NULL, false); + um_arraystore_compact_ex(um, NULL, false); } static void um_arraystore_expand(UndoMesh *um) { - Mesh *me = &um->me; - - um_arraystore_cd_expand(um->store.vdata, &me->vdata, me->totvert); - um_arraystore_cd_expand(um->store.edata, &me->edata, me->totedge); - um_arraystore_cd_expand(um->store.ldata, &me->ldata, me->totloop); - um_arraystore_cd_expand(um->store.pdata, &me->pdata, me->totpoly); - - if (um->store.keyblocks) { - const size_t stride = me->key->elemsize; - KeyBlock *keyblock = me->key->block.first; - for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) { - BArrayState *state = um->store.keyblocks[i]; - size_t state_len; - keyblock->data = BLI_array_store_state_data_get_alloc(state, &state_len); - BLI_assert(keyblock->totelem == (state_len / stride)); - UNUSED_VARS_NDEBUG(stride); - } - } - - if (um->store.mselect) { - const size_t stride = sizeof(*me->mselect); - BArrayState *state = um->store.mselect; - size_t state_len; - me->mselect = BLI_array_store_state_data_get_alloc(state, &state_len); - BLI_assert(me->totselect == (state_len / stride)); - UNUSED_VARS_NDEBUG(stride); - } - - /* not essential, but prevents accidental dangling pointer access */ - BKE_mesh_update_customdata_pointers(me, false); + Mesh *me = &um->me; + + um_arraystore_cd_expand(um->store.vdata, &me->vdata, me->totvert); + um_arraystore_cd_expand(um->store.edata, &me->edata, me->totedge); + um_arraystore_cd_expand(um->store.ldata, &me->ldata, me->totloop); + um_arraystore_cd_expand(um->store.pdata, &me->pdata, me->totpoly); + + if (um->store.keyblocks) { + const size_t stride = me->key->elemsize; + KeyBlock *keyblock = me->key->block.first; + for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) { + BArrayState *state = um->store.keyblocks[i]; + size_t state_len; + keyblock->data = BLI_array_store_state_data_get_alloc(state, &state_len); + BLI_assert(keyblock->totelem == (state_len / stride)); + UNUSED_VARS_NDEBUG(stride); + } + } + + if (um->store.mselect) { + const size_t stride = sizeof(*me->mselect); + BArrayState *state = um->store.mselect; + size_t state_len; + me->mselect = BLI_array_store_state_data_get_alloc(state, &state_len); + BLI_assert(me->totselect == (state_len / stride)); + UNUSED_VARS_NDEBUG(stride); + } + + /* not essential, but prevents accidental dangling pointer access */ + BKE_mesh_update_customdata_pointers(me, false); } static void um_arraystore_free(UndoMesh *um) { - Mesh *me = &um->me; - - um_arraystore_cd_free(um->store.vdata); - um_arraystore_cd_free(um->store.edata); - um_arraystore_cd_free(um->store.ldata); - um_arraystore_cd_free(um->store.pdata); - - if (um->store.keyblocks) { - const size_t stride = me->key->elemsize; - BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); - for (int i = 0; i < me->key->totkey; i++) { - BArrayState *state = um->store.keyblocks[i]; - BLI_array_store_state_remove(bs, state); - } - MEM_freeN(um->store.keyblocks); - um->store.keyblocks = NULL; - } - - if (um->store.mselect) { - const size_t stride = sizeof(*me->mselect); - BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); - BArrayState *state = um->store.mselect; - BLI_array_store_state_remove(bs, state); - um->store.mselect = NULL; - } - - um_arraystore.users -= 1; - - BLI_assert(um_arraystore.users >= 0); - - if (um_arraystore.users == 0) { -#ifdef DEBUG_PRINT - printf("mesh undo store: freeing all data!\n"); -#endif - BLI_array_store_at_size_clear(&um_arraystore.bs_stride); - -#ifdef USE_ARRAY_STORE_THREAD - BLI_task_pool_free(um_arraystore.task_pool); - um_arraystore.task_pool = NULL; -#endif - } + Mesh *me = &um->me; + + um_arraystore_cd_free(um->store.vdata); + um_arraystore_cd_free(um->store.edata); + um_arraystore_cd_free(um->store.ldata); + um_arraystore_cd_free(um->store.pdata); + + if (um->store.keyblocks) { + const size_t stride = me->key->elemsize; + BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); + for (int i = 0; i < me->key->totkey; i++) { + BArrayState *state = um->store.keyblocks[i]; + BLI_array_store_state_remove(bs, state); + } + MEM_freeN(um->store.keyblocks); + um->store.keyblocks = NULL; + } + + if (um->store.mselect) { + const size_t stride = sizeof(*me->mselect); + BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); + BArrayState *state = um->store.mselect; + BLI_array_store_state_remove(bs, state); + um->store.mselect = NULL; + } + + um_arraystore.users -= 1; + + BLI_assert(um_arraystore.users >= 0); + + if (um_arraystore.users == 0) { +# ifdef DEBUG_PRINT + printf("mesh undo store: freeing all data!\n"); +# endif + BLI_array_store_at_size_clear(&um_arraystore.bs_stride); +# ifdef USE_ARRAY_STORE_THREAD + BLI_task_pool_free(um_arraystore.task_pool); + um_arraystore.task_pool = NULL; +# endif + } } /** \} */ -#endif /* USE_ARRAY_STORE */ - +#endif /* USE_ARRAY_STORE */ /* for callbacks */ /* undo simply makes copies of a bmesh */ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key) { - BLI_assert(BLI_array_is_zeroed(um, 1)); + BLI_assert(BLI_array_is_zeroed(um, 1)); #ifdef USE_ARRAY_STORE_THREAD - /* changes this waits is low, but must have finished */ - if (um_arraystore.task_pool) { - BLI_task_pool_work_and_wait(um_arraystore.task_pool); - } + /* changes this waits is low, but must have finished */ + if (um_arraystore.task_pool) { + BLI_task_pool_work_and_wait(um_arraystore.task_pool); + } #endif - /* make sure shape keys work */ - um->me.key = key ? BKE_key_copy_nolib(key) : NULL; + /* make sure shape keys work */ + um->me.key = key ? BKE_key_copy_nolib(key) : NULL; - /* BM_mesh_validate(em->bm); */ /* for troubleshooting */ + /* BM_mesh_validate(em->bm); */ /* for troubleshooting */ - BM_mesh_bm_to_me( - NULL, em->bm, &um->me, (&(struct BMeshToMeshParams){ - /* Undo code should not be manipulating 'G_MAIN->object' hooks/vertex-parent. */ - .calc_object_remap = false, - .cd_mask_extra = {.vmask = CD_MASK_SHAPE_KEYINDEX}, - })); + BM_mesh_bm_to_me( + NULL, + em->bm, + &um->me, + (&(struct BMeshToMeshParams){ + /* Undo code should not be manipulating 'G_MAIN->object' hooks/vertex-parent. */ + .calc_object_remap = false, + .cd_mask_extra = {.vmask = CD_MASK_SHAPE_KEYINDEX}, + })); - um->selectmode = em->selectmode; - um->shapenr = em->bm->shapenr; + um->selectmode = em->selectmode; + um->shapenr = em->bm->shapenr; #ifdef USE_ARRAY_STORE - { - /* We could be more clever here, - * the previous undo state may be from a separate mesh. */ - const UndoMesh *um_ref = um_arraystore.local_links.last ? - ((LinkData *)um_arraystore.local_links.last)->data : NULL; - - /* add oursrlves */ - BLI_addtail(&um_arraystore.local_links, BLI_genericNodeN(um)); - -#ifdef USE_ARRAY_STORE_THREAD - if (um_arraystore.task_pool == NULL) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - um_arraystore.task_pool = BLI_task_pool_create_background(scheduler, NULL); - } - - struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__); - um_data->um = um; - um_data->um_ref = um_ref; - - BLI_task_pool_push( - um_arraystore.task_pool, - um_arraystore_compact_cb, um_data, true, TASK_PRIORITY_LOW); -#else - um_arraystore_compact_with_info(um, um_ref); -#endif - } + { + /* We could be more clever here, + * the previous undo state may be from a separate mesh. */ + const UndoMesh *um_ref = um_arraystore.local_links.last ? + ((LinkData *)um_arraystore.local_links.last)->data : + NULL; + + /* add oursrlves */ + BLI_addtail(&um_arraystore.local_links, BLI_genericNodeN(um)); + +# ifdef USE_ARRAY_STORE_THREAD + if (um_arraystore.task_pool == NULL) { + TaskScheduler *scheduler = BLI_task_scheduler_get(); + um_arraystore.task_pool = BLI_task_pool_create_background(scheduler, NULL); + } + + struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__); + um_data->um = um; + um_data->um_ref = um_ref; + + BLI_task_pool_push( + um_arraystore.task_pool, um_arraystore_compact_cb, um_data, true, TASK_PRIORITY_LOW); +# else + um_arraystore_compact_with_info(um, um_ref); +# endif + } #endif - return um; + return um; } static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh) { - BMEditMesh *em_tmp; - Object *ob = em->ob; - BMesh *bm; - Key *key = obmesh->key; + BMEditMesh *em_tmp; + Object *ob = em->ob; + BMesh *bm; + Key *key = obmesh->key; #ifdef USE_ARRAY_STORE -#ifdef USE_ARRAY_STORE_THREAD - /* changes this waits is low, but must have finished */ - BLI_task_pool_work_and_wait(um_arraystore.task_pool); -#endif +# ifdef USE_ARRAY_STORE_THREAD + /* changes this waits is low, but must have finished */ + BLI_task_pool_work_and_wait(um_arraystore.task_pool); +# endif -#ifdef DEBUG_TIME - TIMEIT_START(mesh_undo_expand); -#endif +# ifdef DEBUG_TIME + TIMEIT_START(mesh_undo_expand); +# endif - um_arraystore_expand(um); + um_arraystore_expand(um); -#ifdef DEBUG_TIME - TIMEIT_END(mesh_undo_expand); -#endif -#endif /* USE_ARRAY_STORE */ +# ifdef DEBUG_TIME + TIMEIT_END(mesh_undo_expand); +# endif +#endif /* USE_ARRAY_STORE */ - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me); + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me); - em->bm->shapenr = um->shapenr; + em->bm->shapenr = um->shapenr; - EDBM_mesh_free(em); + EDBM_mesh_free(em); - bm = BM_mesh_create( - &allocsize, - &((struct BMeshCreateParams){.use_toolflags = true,})); + bm = BM_mesh_create(&allocsize, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); - BM_mesh_bm_from_me( - bm, &um->me, (&(struct BMeshFromMeshParams){ - .calc_face_normal = true, .active_shapekey = um->shapenr, - })); + BM_mesh_bm_from_me(bm, + &um->me, + (&(struct BMeshFromMeshParams){ + .calc_face_normal = true, + .active_shapekey = um->shapenr, + })); - em_tmp = BKE_editmesh_create(bm, true); - *em = *em_tmp; + em_tmp = BKE_editmesh_create(bm, true); + *em = *em_tmp; - em->selectmode = um->selectmode; - bm->selectmode = um->selectmode; - em->ob = ob; + em->selectmode = um->selectmode; + bm->selectmode = um->selectmode; + em->ob = ob; - bm->spacearr_dirty = BM_SPACEARR_DIRTY_ALL; + bm->spacearr_dirty = BM_SPACEARR_DIRTY_ALL; - /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens - * if the active is a basis for any other. */ - if (key && (key->type == KEY_RELATIVE)) { - /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume - * shapenr from restored bmesh and keyblock indices are in sync. */ - const int kb_act_idx = ob->shapenr - 1; + /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens + * if the active is a basis for any other. */ + if (key && (key->type == KEY_RELATIVE)) { + /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume + * shapenr from restored bmesh and keyblock indices are in sync. */ + const int kb_act_idx = ob->shapenr - 1; - /* If it is, let's patch the current mesh key block to its restored value. - * Else, the offsets won't be computed and it won't matter. */ - if (BKE_keyblock_is_basis(key, kb_act_idx)) { - KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx); + /* If it is, let's patch the current mesh key block to its restored value. + * Else, the offsets won't be computed and it won't matter. */ + if (BKE_keyblock_is_basis(key, kb_act_idx)) { + KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx); - if (kb_act->totelem != um->me.totvert) { - /* The current mesh has some extra/missing verts compared to the undo, adjust. */ - MEM_SAFE_FREE(kb_act->data); - kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__); - kb_act->totelem = um->me.totvert; - } + if (kb_act->totelem != um->me.totvert) { + /* The current mesh has some extra/missing verts compared to the undo, adjust. */ + MEM_SAFE_FREE(kb_act->data); + kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__); + kb_act->totelem = um->me.totvert; + } - BKE_keyblock_update_from_mesh(&um->me, kb_act); - } - } + BKE_keyblock_update_from_mesh(&um->me, kb_act); + } + } - ob->shapenr = um->shapenr; + ob->shapenr = um->shapenr; - MEM_freeN(em_tmp); + MEM_freeN(em_tmp); #ifdef USE_ARRAY_STORE - um_arraystore_expand_clear(um); + um_arraystore_expand_clear(um); #endif } static void undomesh_free_data(UndoMesh *um) { - Mesh *me = &um->me; + Mesh *me = &um->me; #ifdef USE_ARRAY_STORE -#ifdef USE_ARRAY_STORE_THREAD - /* changes this waits is low, but must have finished */ - BLI_task_pool_work_and_wait(um_arraystore.task_pool); -#endif +# ifdef USE_ARRAY_STORE_THREAD + /* changes this waits is low, but must have finished */ + BLI_task_pool_work_and_wait(um_arraystore.task_pool); +# endif - /* we need to expand so any allocations in custom-data are freed with the mesh */ - um_arraystore_expand(um); + /* we need to expand so any allocations in custom-data are freed with the mesh */ + um_arraystore_expand(um); - { - LinkData *link = BLI_findptr(&um_arraystore.local_links, um, offsetof(LinkData, data)); - BLI_remlink(&um_arraystore.local_links, link); - MEM_freeN(link); - } - um_arraystore_free(um); + { + LinkData *link = BLI_findptr(&um_arraystore.local_links, um, offsetof(LinkData, data)); + BLI_remlink(&um_arraystore.local_links, link); + MEM_freeN(link); + } + um_arraystore_free(um); #endif - if (me->key) { - BKE_key_free(me->key); - MEM_freeN(me->key); - } + if (me->key) { + BKE_key_free(me->key); + MEM_freeN(me->key); + } - BKE_mesh_free(me); + BKE_mesh_free(me); } static Object *editmesh_object_from_context(bContext *C) { - Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_MESH) { - Mesh *me = obedit->data; - if (me->edit_mesh != NULL) { - return obedit; - } - } - return NULL; + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_MESH) { + Mesh *me = obedit->data; + if (me->edit_mesh != NULL) { + return obedit; + } + } + return NULL; } /** \} */ @@ -678,126 +692,137 @@ static Object *editmesh_object_from_context(bContext *C) * \{ */ typedef struct MeshUndoStep_Elem { - struct MeshUndoStep_Elem *next, *prev; - UndoRefID_Object obedit_ref; - UndoMesh data; + struct MeshUndoStep_Elem *next, *prev; + UndoRefID_Object obedit_ref; + UndoMesh data; } MeshUndoStep_Elem; typedef struct MeshUndoStep { - UndoStep step; - struct UndoIDPtrMap *id_map; - MeshUndoStep_Elem *elems; - uint elems_len; + UndoStep step; + struct UndoIDPtrMap *id_map; + MeshUndoStep_Elem *elems; + uint elems_len; } MeshUndoStep; static bool mesh_undosys_poll(bContext *C) { - return editmesh_object_from_context(C) != NULL; + return editmesh_object_from_context(C) != NULL; } -static bool mesh_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p) +static bool mesh_undosys_step_encode(struct bContext *C, + struct Main *UNUSED(bmain), + UndoStep *us_p) { - MeshUndoStep *us = (MeshUndoStep *)us_p; - - /* Important not to use the 3D view when getting objects because all objects - * outside of this list will be moved out of edit-mode when reading back undo steps. */ - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, NULL, &objects_len); - - us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__); - us->elems_len = objects_len; - - for (uint i = 0; i < objects_len; i++) { - Object *ob = objects[i]; - MeshUndoStep_Elem *elem = &us->elems[i]; - - elem->obedit_ref.ptr = ob; - Mesh *me = elem->obedit_ref.ptr->data; - undomesh_from_editmesh(&elem->data, me->edit_mesh, me->key); - us->step.data_size += elem->data.undo_size; - } - MEM_freeN(objects); - return true; + MeshUndoStep *us = (MeshUndoStep *)us_p; + + /* Important not to use the 3D view when getting objects because all objects + * outside of this list will be moved out of edit-mode when reading back undo steps. */ + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, NULL, &objects_len); + + us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__); + us->elems_len = objects_len; + + for (uint i = 0; i < objects_len; i++) { + Object *ob = objects[i]; + MeshUndoStep_Elem *elem = &us->elems[i]; + + elem->obedit_ref.ptr = ob; + Mesh *me = elem->obedit_ref.ptr->data; + undomesh_from_editmesh(&elem->data, me->edit_mesh, me->key); + us->step.data_size += elem->data.undo_size; + } + MEM_freeN(objects); + return true; } -static void mesh_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir)) +static void mesh_undosys_step_decode(struct bContext *C, + struct Main *UNUSED(bmain), + UndoStep *us_p, + int UNUSED(dir)) { - MeshUndoStep *us = (MeshUndoStep *)us_p; - - /* Load all our objects into edit-mode, clear everything else. */ - ED_undo_object_editmode_restore_helper(C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems)); - - BLI_assert(mesh_undosys_poll(C)); - - for (uint i = 0; i < us->elems_len; i++) { - MeshUndoStep_Elem *elem = &us->elems[i]; - Object *obedit = elem->obedit_ref.ptr; - Mesh *me = obedit->data; - if (me->edit_mesh == NULL) { - /* Should never fail, may not crash but can give odd behavior. */ - CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid", - us_p->name, obedit->id.name); - continue; - } - BMEditMesh *em = me->edit_mesh; - undomesh_to_editmesh(&elem->data, em, obedit->data); - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); - } - - /* The first element is always active */ - ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG); - - Scene *scene = CTX_data_scene(C); - scene->toolsettings->selectmode = us->elems[0].data.selectmode; - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); + MeshUndoStep *us = (MeshUndoStep *)us_p; + + /* Load all our objects into edit-mode, clear everything else. */ + ED_undo_object_editmode_restore_helper( + C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems)); + + BLI_assert(mesh_undosys_poll(C)); + + for (uint i = 0; i < us->elems_len; i++) { + MeshUndoStep_Elem *elem = &us->elems[i]; + Object *obedit = elem->obedit_ref.ptr; + Mesh *me = obedit->data; + if (me->edit_mesh == NULL) { + /* Should never fail, may not crash but can give odd behavior. */ + CLOG_ERROR(&LOG, + "name='%s', failed to enter edit-mode for object '%s', undo state invalid", + us_p->name, + obedit->id.name); + continue; + } + BMEditMesh *em = me->edit_mesh; + undomesh_to_editmesh(&elem->data, em, obedit->data); + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + } + + /* The first element is always active */ + ED_undo_object_set_active_or_warn( + CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG); + + Scene *scene = CTX_data_scene(C); + scene->toolsettings->selectmode = us->elems[0].data.selectmode; + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } static void mesh_undosys_step_free(UndoStep *us_p) { - MeshUndoStep *us = (MeshUndoStep *)us_p; + MeshUndoStep *us = (MeshUndoStep *)us_p; - for (uint i = 0; i < us->elems_len; i++) { - MeshUndoStep_Elem *elem = &us->elems[i]; - undomesh_free_data(&elem->data); - } - MEM_freeN(us->elems); + for (uint i = 0; i < us->elems_len; i++) { + MeshUndoStep_Elem *elem = &us->elems[i]; + undomesh_free_data(&elem->data); + } + MEM_freeN(us->elems); - if (us->id_map != NULL) { - BKE_undosys_ID_map_destroy(us->id_map); - } + if (us->id_map != NULL) { + BKE_undosys_ID_map_destroy(us->id_map); + } } -static void mesh_undosys_foreach_ID_ref( - UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +static void mesh_undosys_foreach_ID_ref(UndoStep *us_p, + UndoTypeForEachIDRefFn foreach_ID_ref_fn, + void *user_data) { - MeshUndoStep *us = (MeshUndoStep *)us_p; + MeshUndoStep *us = (MeshUndoStep *)us_p; - for (uint i = 0; i < us->elems_len; i++) { - MeshUndoStep_Elem *elem = &us->elems[i]; - foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref)); - } + for (uint i = 0; i < us->elems_len; i++) { + MeshUndoStep_Elem *elem = &us->elems[i]; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref)); + } - if (us->id_map != NULL) { - BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data); - } + if (us->id_map != NULL) { + BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data); + } } /* Export for ED_undo_sys. */ void ED_mesh_undosys_type(UndoType *ut) { - ut->name = "Edit Mesh"; - ut->poll = mesh_undosys_poll; - ut->step_encode = mesh_undosys_step_encode; - ut->step_decode = mesh_undosys_step_decode; - ut->step_free = mesh_undosys_step_free; + ut->name = "Edit Mesh"; + ut->poll = mesh_undosys_poll; + ut->step_encode = mesh_undosys_step_encode; + ut->step_decode = mesh_undosys_step_decode; + ut->step_free = mesh_undosys_step_free; - ut->step_foreach_ID_ref = mesh_undosys_foreach_ID_ref; + ut->step_foreach_ID_ref = mesh_undosys_foreach_ID_ref; - ut->use_context = true; + ut->use_context = true; - ut->step_size = sizeof(MeshUndoStep); + ut->step_size = sizeof(MeshUndoStep); } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index f86a2388f87..1cb550fccc4 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -44,7 +44,7 @@ #include "DEG_depsgraph.h" -#include "BKE_object.h" /* XXX. only for EDBM_mesh_load(). */ +#include "BKE_object.h" /* XXX. only for EDBM_mesh_load(). */ #include "WM_api.h" #include "WM_types.h" @@ -53,7 +53,7 @@ #include "ED_screen.h" #include "ED_view3d.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /* -------------------------------------------------------------------- */ /** \name Redo API @@ -66,47 +66,47 @@ BMBackup EDBM_redo_state_store(BMEditMesh *em) { - BMBackup backup; - backup.bmcopy = BM_mesh_copy(em->bm); - return backup; + BMBackup backup; + backup.bmcopy = BM_mesh_copy(em->bm); + return backup; } void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess) { - BMesh *tmpbm; - if (!em || !backup.bmcopy) { - return; - } - - BM_mesh_data_free(em->bm); - tmpbm = BM_mesh_copy(backup.bmcopy); - *em->bm = *tmpbm; - MEM_freeN(tmpbm); - tmpbm = NULL; - - if (recalctess) { - BKE_editmesh_tessface_calc(em); - } + BMesh *tmpbm; + if (!em || !backup.bmcopy) { + return; + } + + BM_mesh_data_free(em->bm); + tmpbm = BM_mesh_copy(backup.bmcopy); + *em->bm = *tmpbm; + MEM_freeN(tmpbm); + tmpbm = NULL; + + if (recalctess) { + BKE_editmesh_tessface_calc(em); + } } void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) { - if (em && backup->bmcopy) { - BM_mesh_data_free(em->bm); - *em->bm = *backup->bmcopy; - } - else if (backup->bmcopy) { - BM_mesh_data_free(backup->bmcopy); - } - - if (backup->bmcopy) { - MEM_freeN(backup->bmcopy); - } - backup->bmcopy = NULL; - - if (recalctess && em) { - BKE_editmesh_tessface_calc(em); - } + if (em && backup->bmcopy) { + BM_mesh_data_free(em->bm); + *em->bm = *backup->bmcopy; + } + else if (backup->bmcopy) { + BM_mesh_data_free(backup->bmcopy); + } + + if (backup->bmcopy) { + MEM_freeN(backup->bmcopy); + } + backup->bmcopy = NULL; + + if (recalctess && em) { + BKE_editmesh_tessface_calc(em); + } } /** \} */ @@ -117,163 +117,166 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...) { - BMesh *bm = em->bm; - va_list list; + BMesh *bm = em->bm; + va_list list; - va_start(list, fmt); + va_start(list, fmt); - if (!BMO_op_vinitf(bm, bmop, BMO_FLAG_DEFAULTS, fmt, list)) { - BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__); - va_end(list); - return false; - } + if (!BMO_op_vinitf(bm, bmop, BMO_FLAG_DEFAULTS, fmt, list)) { + BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__); + va_end(list); + return false; + } - if (!em->emcopy) { - em->emcopy = BKE_editmesh_copy(em); - } - em->emcopyusers++; + if (!em->emcopy) { + em->emcopy = BKE_editmesh_copy(em); + } + em->emcopyusers++; - va_end(list); + va_end(list); - return true; + return true; } /* returns 0 on error, 1 on success. executes and finishes a bmesh operator */ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report) { - const char *errmsg; - - BMO_op_finish(em->bm, bmop); - - if (BMO_error_get(em->bm, &errmsg, NULL)) { - BMEditMesh *emcopy = em->emcopy; - - if (do_report) { - BKE_report(op->reports, RPT_ERROR, errmsg); - } - - EDBM_mesh_free(em); - *em = *emcopy; - - MEM_freeN(emcopy); - em->emcopyusers = 0; - em->emcopy = NULL; - - /* 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); - } - - if (em->ob) { - DEG_id_tag_update(&((Mesh *)em->ob->data)->id, ID_RECALC_COPY_ON_WRITE); - } - - return false; - } - else { - em->emcopyusers--; - if (em->emcopyusers < 0) { - printf("warning: em->emcopyusers was less than zero.\n"); - } - - if (em->emcopyusers <= 0) { - BKE_editmesh_free(em->emcopy); - MEM_freeN(em->emcopy); - em->emcopy = NULL; - } - - return true; - } + const char *errmsg; + + BMO_op_finish(em->bm, bmop); + + if (BMO_error_get(em->bm, &errmsg, NULL)) { + BMEditMesh *emcopy = em->emcopy; + + if (do_report) { + BKE_report(op->reports, RPT_ERROR, errmsg); + } + + EDBM_mesh_free(em); + *em = *emcopy; + + MEM_freeN(emcopy); + em->emcopyusers = 0; + em->emcopy = NULL; + + /* 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); + } + + if (em->ob) { + DEG_id_tag_update(&((Mesh *)em->ob->data)->id, ID_RECALC_COPY_ON_WRITE); + } + + return false; + } + else { + em->emcopyusers--; + if (em->emcopyusers < 0) { + printf("warning: em->emcopyusers was less than zero.\n"); + } + + if (em->emcopyusers <= 0) { + BKE_editmesh_free(em->emcopy); + MEM_freeN(em->emcopy); + em->emcopy = NULL; + } + + return true; + } } bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...) { - BMesh *bm = em->bm; - BMOperator bmop; - va_list list; + BMesh *bm = em->bm; + BMOperator bmop; + va_list list; - va_start(list, fmt); + va_start(list, fmt); - if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) { - BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__); - va_end(list); - return false; - } + if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) { + BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__); + va_end(list); + return false; + } - if (!em->emcopy) { - em->emcopy = BKE_editmesh_copy(em); - } - em->emcopyusers++; + if (!em->emcopy) { + em->emcopy = BKE_editmesh_copy(em); + } + em->emcopyusers++; - BMO_op_exec(bm, &bmop); + BMO_op_exec(bm, &bmop); - va_end(list); - return EDBM_op_finish(em, &bmop, op, true); + va_end(list); + return EDBM_op_finish(em, &bmop, op, true); } -bool EDBM_op_call_and_selectf( - BMEditMesh *em, wmOperator *op, - const char *select_slot_out, const bool select_extend, - const char *fmt, ...) +bool EDBM_op_call_and_selectf(BMEditMesh *em, + wmOperator *op, + const char *select_slot_out, + const bool select_extend, + const char *fmt, + ...) { - BMOpSlot *slot_select_out; - BMesh *bm = em->bm; - BMOperator bmop; - va_list list; - char hflag; + BMOpSlot *slot_select_out; + BMesh *bm = em->bm; + BMOperator bmop; + va_list list; + char hflag; - va_start(list, fmt); + va_start(list, fmt); - if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) { - BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__); - va_end(list); - return false; - } + if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) { + BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__); + va_end(list); + return false; + } - if (!em->emcopy) { - em->emcopy = BKE_editmesh_copy(em); - } - em->emcopyusers++; + if (!em->emcopy) { + em->emcopy = BKE_editmesh_copy(em); + } + em->emcopyusers++; - BMO_op_exec(bm, &bmop); + BMO_op_exec(bm, &bmop); - slot_select_out = BMO_slot_get(bmop.slots_out, select_slot_out); - hflag = slot_select_out->slot_subtype.elem & BM_ALL_NOLOOP; - BLI_assert(hflag != 0); + slot_select_out = BMO_slot_get(bmop.slots_out, select_slot_out); + hflag = slot_select_out->slot_subtype.elem & BM_ALL_NOLOOP; + BLI_assert(hflag != 0); - if (select_extend == false) { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - } + if (select_extend == false) { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + } - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, select_slot_out, hflag, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, select_slot_out, hflag, BM_ELEM_SELECT, true); - va_end(list); - return EDBM_op_finish(em, &bmop, op, true); + va_end(list); + return EDBM_op_finish(em, &bmop, op, true); } bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...) { - BMesh *bm = em->bm; - BMOperator bmop; - va_list list; + BMesh *bm = em->bm; + BMOperator bmop; + va_list list; - va_start(list, fmt); + va_start(list, fmt); - if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) { - va_end(list); - return false; - } + if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) { + va_end(list); + return false; + } - if (!em->emcopy) { - em->emcopy = BKE_editmesh_copy(em); - } - em->emcopyusers++; + if (!em->emcopy) { + em->emcopy = BKE_editmesh_copy(em); + } + em->emcopyusers++; - BMO_op_exec(bm, &bmop); + BMO_op_exec(bm, &bmop); - va_end(list); - return EDBM_op_finish(em, &bmop, NULL, false); + va_end(list); + return EDBM_op_finish(em, &bmop, NULL, false); } /** \} */ @@ -286,37 +289,40 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...) 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, - &((struct BMeshCreateParams){.use_toolflags = true,})); - - if (me->edit_mesh) { - /* this happens when switching shape keys */ - EDBM_mesh_free(me->edit_mesh); - MEM_freeN(me->edit_mesh); - } - - /* currently executing operators re-tessellates, so we can avoid doing here - * but at some point it may need to be added back. */ + 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, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); + + if (me->edit_mesh) { + /* this happens when switching shape keys */ + EDBM_mesh_free(me->edit_mesh); + MEM_freeN(me->edit_mesh); + } + + /* currently executing operators re-tessellates, so we can avoid doing here + * but at some point it may need to be added back. */ #if 0 - me->edit_mesh = BKE_editmesh_create(bm, true); + me->edit_mesh = BKE_editmesh_create(bm, true); #else - me->edit_mesh = BKE_editmesh_create(bm, false); + me->edit_mesh = BKE_editmesh_create(bm, false); #endif - me->edit_mesh->selectmode = me->edit_mesh->bm->selectmode = select_mode; - me->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0; - me->edit_mesh->ob = ob; + me->edit_mesh->selectmode = me->edit_mesh->bm->selectmode = select_mode; + me->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0; + me->edit_mesh->ob = ob; - /* we need to flush selection because the mode may have changed from when last in editmode */ - EDBM_selectmode_flush(me->edit_mesh); + /* we need to flush selection because the mode may have changed from when last in editmode */ + EDBM_selectmode_flush(me->edit_mesh); } /** @@ -325,61 +331,63 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index) */ void EDBM_mesh_load(Main *bmain, Object *ob) { - Mesh *me = ob->data; - BMesh *bm = me->edit_mesh->bm; - - /* Workaround for T42360, 'ob->shapenr' should be 1 in this case. - * however this isn't synchronized between objects at the moment. */ - if (UNLIKELY((ob->shapenr == 0) && (me->key && !BLI_listbase_is_empty(&me->key->block)))) { - bm->shapenr = 1; - } - - BM_mesh_bm_to_me( - bmain, bm, me, (&(struct BMeshToMeshParams){ - .calc_object_remap = true, - })); + Mesh *me = ob->data; + BMesh *bm = me->edit_mesh->bm; + + /* Workaround for T42360, 'ob->shapenr' should be 1 in this case. + * however this isn't synchronized between objects at the moment. */ + if (UNLIKELY((ob->shapenr == 0) && (me->key && !BLI_listbase_is_empty(&me->key->block)))) { + bm->shapenr = 1; + } + + BM_mesh_bm_to_me(bmain, + bm, + me, + (&(struct BMeshToMeshParams){ + .calc_object_remap = true, + })); #ifdef USE_TESSFACE_DEFAULT - BKE_mesh_tessface_calc(me); + 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. - * - * Do it for all objects which shares the same mesh datablock, since their - * derived meshes might also be referencing data which was just freed, - * - * Annoying enough, but currently seems most efficient way to avoid access - * of freed data on scene update, especially in cases when there are dependency - * cycles. - */ + /* 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. + * + * Do it for all objects which shares the same mesh datablock, since their + * derived meshes might also be referencing data which was just freed, + * + * Annoying enough, but currently seems most efficient way to avoid access + * of freed data on scene update, especially in cases when there are dependency + * cycles. + */ #if 0 - for (Object *other_object = bmain->objects.first; - other_object != NULL; - other_object = other_object->id.next) - { - if (other_object->data == ob->data) { - BKE_object_free_derived_caches(other_object); - } - } + for (Object *other_object = bmain->objects.first; + other_object != NULL; + other_object = other_object->id.next) + { + if (other_object->data == ob->data) { + BKE_object_free_derived_caches(other_object); + } + } #endif } void EDBM_mesh_clear(BMEditMesh *em) { - /* clear bmesh */ - BM_mesh_clear(em->bm); - - /* free derived meshes */ - BKE_editmesh_free_derivedmesh(em); - - /* free tessellation data */ - em->tottri = 0; - if (em->looptris) { - MEM_freeN(em->looptris); - em->looptris = NULL; - } + /* clear bmesh */ + BM_mesh_clear(em->bm); + + /* free derived meshes */ + BKE_editmesh_free_derivedmesh(em); + + /* free tessellation data */ + em->tottri = 0; + if (em->looptris) { + MEM_freeN(em->looptris); + em->looptris = NULL; + } } /** @@ -387,13 +395,13 @@ void EDBM_mesh_clear(BMEditMesh *em) */ void EDBM_mesh_free(BMEditMesh *em) { - /* These tables aren't used yet, so it's not strictly necessary - * to 'end' them (with 'e' param) but if someone tries to start - * using them, having these in place will save a lot of pain */ - ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); - ED_mesh_mirror_topo_table(NULL, NULL, 'e'); + /* These tables aren't used yet, so it's not strictly necessary + * to 'end' them (with 'e' param) but if someone tries to start + * using them, having these in place will save a lot of pain */ + ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); + ED_mesh_mirror_topo_table(NULL, NULL, 'e'); - BKE_editmesh_free(em); + BKE_editmesh_free(em); } /** \} */ @@ -404,89 +412,99 @@ void EDBM_mesh_free(BMEditMesh *em) void EDBM_selectmode_to_scene(bContext *C) { - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (!em) { - return; - } + if (!em) { + return; + } - scene->toolsettings->selectmode = em->selectmode; + scene->toolsettings->selectmode = em->selectmode; - /* Request redraw of header buttons (to show new select mode) */ - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene); + /* Request redraw of header buttons (to show new select mode) */ + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene); } void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode) { - BM_mesh_select_mode_flush_ex(em->bm, selectmode); + BM_mesh_select_mode_flush_ex(em->bm, selectmode); } void EDBM_selectmode_flush(BMEditMesh *em) { - EDBM_selectmode_flush_ex(em, em->selectmode); + EDBM_selectmode_flush_ex(em, em->selectmode); } void EDBM_deselect_flush(BMEditMesh *em) { - /* function below doesn't use. just do this to keep the values in sync */ - em->bm->selectmode = em->selectmode; - BM_mesh_deselect_flush(em->bm); + /* function below doesn't use. just do this to keep the values in sync */ + em->bm->selectmode = em->selectmode; + BM_mesh_deselect_flush(em->bm); } void EDBM_select_flush(BMEditMesh *em) { - /* function below doesn't use. just do this to keep the values in sync */ - em->bm->selectmode = em->selectmode; - BM_mesh_select_flush(em->bm); + /* function below doesn't use. just do this to keep the values in sync */ + em->bm->selectmode = em->selectmode; + BM_mesh_select_flush(em->bm); } void EDBM_select_more(BMEditMesh *em, const bool use_face_step) { - BMOperator bmop; - const bool use_faces = (em->selectmode == SCE_SELECT_FACE); - - BMO_op_initf( - em->bm, &bmop, BMO_FLAG_DEFAULTS, - "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", - BM_ELEM_SELECT, false, use_faces, use_face_step); - BMO_op_exec(em->bm, &bmop); - /* don't flush selection in edge/vertex mode */ - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); - BMO_op_finish(em->bm, &bmop); - - EDBM_selectmode_flush(em); + BMOperator bmop; + const bool use_faces = (em->selectmode == SCE_SELECT_FACE); + + BMO_op_initf(em->bm, + &bmop, + BMO_FLAG_DEFAULTS, + "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", + BM_ELEM_SELECT, + false, + use_faces, + use_face_step); + BMO_op_exec(em->bm, &bmop); + /* don't flush selection in edge/vertex mode */ + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); + BMO_op_finish(em->bm, &bmop); + + EDBM_selectmode_flush(em); } void EDBM_select_less(BMEditMesh *em, const bool use_face_step) { - BMOperator bmop; - const bool use_faces = (em->selectmode == SCE_SELECT_FACE); - - BMO_op_initf( - em->bm, &bmop, BMO_FLAG_DEFAULTS, - "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", - BM_ELEM_SELECT, true, use_faces, use_face_step); - BMO_op_exec(em->bm, &bmop); - /* don't flush selection in edge/vertex mode */ - BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); - BMO_op_finish(em->bm, &bmop); - - EDBM_selectmode_flush(em); - - /* only needed for select less, ensure we don't have isolated elements remaining */ - BM_mesh_select_mode_clean(em->bm); + BMOperator bmop; + const bool use_faces = (em->selectmode == SCE_SELECT_FACE); + + BMO_op_initf(em->bm, + &bmop, + BMO_FLAG_DEFAULTS, + "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", + BM_ELEM_SELECT, + true, + use_faces, + use_face_step); + BMO_op_exec(em->bm, &bmop); + /* don't flush selection in edge/vertex mode */ + BMO_slot_buffer_hflag_disable( + em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); + BMO_op_finish(em->bm, &bmop); + + EDBM_selectmode_flush(em); + + /* only needed for select less, ensure we don't have isolated elements remaining */ + BM_mesh_select_mode_clean(em->bm); } void EDBM_flag_disable_all(BMEditMesh *em, const char hflag) { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, false); + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, false); } void EDBM_flag_enable_all(BMEditMesh *em, const char hflag) { - BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true); + BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true); } /** \} */ @@ -498,419 +516,431 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag) /** * Return a new UVVertMap from the editmesh */ -UvVertMap *BM_uv_vert_map_create( - BMesh *bm, - const float limit[2], const bool use_select, const bool use_winding) +UvVertMap *BM_uv_vert_map_create(BMesh *bm, + const float limit[2], + const bool use_select, + const bool use_winding) { - BMVert *ev; - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - /* vars from original func */ - UvVertMap *vmap; - UvMapVert *buf; - MLoopUV *luv; - unsigned int a; - int totverts, i, totuv, totfaces; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - bool *winding = NULL; - BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - - BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); - - totfaces = bm->totface; - totverts = bm->totvert; - totuv = 0; - - /* generate UvMapVert array */ - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - totuv += efa->len; - } - } - - if (totuv == 0) { - return NULL; - } - vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap"); - if (!vmap) { - return NULL; - } - - vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totverts, "UvMapVert_pt"); - buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * totuv, "UvMapVert"); - if (use_winding) { - winding = MEM_callocN(sizeof(*winding) * totfaces, "winding"); - } - - if (!vmap->vert || !vmap->buf) { - BKE_mesh_uv_vert_map_free(vmap); - return NULL; - } - - BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) { - if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - float (*tf_uv)[2] = NULL; - - if (use_winding) { - tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len); - } - - BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) { - buf->loop_of_poly_index = i; - buf->poly_index = a; - buf->separate = 0; - - buf->next = vmap->vert[BM_elem_index_get(l->v)]; - vmap->vert[BM_elem_index_get(l->v)] = buf; - buf++; - - if (use_winding) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - copy_v2_v2(tf_uv[i], luv->uv); - } - } - - if (use_winding) { - winding[a] = cross_poly_v2(tf_uv, efa->len) > 0; - } - } - } - - /* sort individual uvs for each vert */ - BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) { - UvMapVert *newvlist = NULL, *vlist = vmap->vert[a]; - UvMapVert *iterv, *v, *lastv, *next; - float *uv, *uv2, uvdiff[2]; - - while (vlist) { - v = vlist; - vlist = vlist->next; - v->next = newvlist; - newvlist = v; - - efa = BM_face_at_index(bm, v->poly_index); - - l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->loop_of_poly_index); - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uv = luv->uv; - - lastv = NULL; - iterv = vlist; - - while (iterv) { - next = iterv->next; - efa = BM_face_at_index(bm, iterv->poly_index); - l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->loop_of_poly_index); - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uv2 = luv->uv; - - sub_v2_v2v2(uvdiff, uv2, uv); - - if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] && - (!use_winding || winding[iterv->poly_index] == winding[v->poly_index])) - { - if (lastv) lastv->next = next; - else vlist = next; - iterv->next = newvlist; - newvlist = iterv; - } - else { - lastv = iterv; - } - - iterv = next; - } - - newvlist->separate = 1; - } - - vmap->vert[a] = newvlist; - } - - if (use_winding) { - MEM_freeN(winding); - } - - BLI_buffer_free(&tf_uv_buf); - - return vmap; + BMVert *ev; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + /* vars from original func */ + UvVertMap *vmap; + UvMapVert *buf; + MLoopUV *luv; + unsigned int a; + int totverts, i, totuv, totfaces; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + bool *winding = NULL; + BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + + BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); + + totfaces = bm->totface; + totverts = bm->totvert; + totuv = 0; + + /* generate UvMapVert array */ + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + totuv += efa->len; + } + } + + if (totuv == 0) { + return NULL; + } + vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap"); + if (!vmap) { + return NULL; + } + + vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totverts, "UvMapVert_pt"); + buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * totuv, "UvMapVert"); + if (use_winding) { + winding = MEM_callocN(sizeof(*winding) * totfaces, "winding"); + } + + if (!vmap->vert || !vmap->buf) { + BKE_mesh_uv_vert_map_free(vmap); + return NULL; + } + + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) { + if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + float(*tf_uv)[2] = NULL; + + if (use_winding) { + tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len); + } + + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + buf->loop_of_poly_index = i; + buf->poly_index = a; + buf->separate = 0; + + buf->next = vmap->vert[BM_elem_index_get(l->v)]; + vmap->vert[BM_elem_index_get(l->v)] = buf; + buf++; + + if (use_winding) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + copy_v2_v2(tf_uv[i], luv->uv); + } + } + + if (use_winding) { + winding[a] = cross_poly_v2(tf_uv, efa->len) > 0; + } + } + } + + /* sort individual uvs for each vert */ + BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) { + UvMapVert *newvlist = NULL, *vlist = vmap->vert[a]; + UvMapVert *iterv, *v, *lastv, *next; + float *uv, *uv2, uvdiff[2]; + + while (vlist) { + v = vlist; + vlist = vlist->next; + v->next = newvlist; + newvlist = v; + + efa = BM_face_at_index(bm, v->poly_index); + + l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->loop_of_poly_index); + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + uv = luv->uv; + + lastv = NULL; + iterv = vlist; + + while (iterv) { + next = iterv->next; + efa = BM_face_at_index(bm, iterv->poly_index); + l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->loop_of_poly_index); + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + uv2 = luv->uv; + + sub_v2_v2v2(uvdiff, uv2, uv); + + if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] && + (!use_winding || winding[iterv->poly_index] == winding[v->poly_index])) { + if (lastv) + lastv->next = next; + else + vlist = next; + iterv->next = newvlist; + newvlist = iterv; + } + else { + lastv = iterv; + } + + iterv = next; + } + + newvlist->separate = 1; + } + + vmap->vert[a] = newvlist; + } + + if (use_winding) { + MEM_freeN(winding); + } + + BLI_buffer_free(&tf_uv_buf); + + return vmap; } UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v) { - return vmap->vert[v]; + return vmap->vert[v]; } /* A specialized vert map used by stitch operator */ -UvElementMap *BM_uv_element_map_create( - BMesh *bm, - const bool selected, const bool use_winding, const bool do_islands) +UvElementMap *BM_uv_element_map_create(BMesh *bm, + const bool selected, + const bool use_winding, + const bool do_islands) { - BMVert *ev; - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - /* vars from original func */ - UvElementMap *element_map; - UvElement *buf; - bool *winding = NULL; - BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - - MLoopUV *luv; - int totverts, totfaces, i, totuv, j; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); - - totfaces = bm->totface; - totverts = bm->totvert; - totuv = 0; - - /* generate UvElement array */ - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - totuv += efa->len; - } - } - - if (totuv == 0) { - return NULL; - } - - element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap"); - element_map->totalUVs = totuv; - element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts, "UvElementVerts"); - buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv, "UvElement"); - - if (use_winding) { - winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding"); - } - - BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) { - - if (use_winding) { - winding[j] = false; - } - - if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - float (*tf_uv)[2] = NULL; - - if (use_winding) { - tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len); - } - - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - buf->l = l; - buf->separate = 0; - buf->island = INVALID_ISLAND; - buf->loop_of_poly_index = i; - - buf->next = element_map->vert[BM_elem_index_get(l->v)]; - element_map->vert[BM_elem_index_get(l->v)] = buf; - - if (use_winding) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - copy_v2_v2(tf_uv[i], luv->uv); - } - - buf++; - } - - if (use_winding) { - winding[j] = cross_poly_v2(tf_uv, efa->len) > 0; - } - } - } - - /* sort individual uvs for each vert */ - BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, i) { - UvElement *newvlist = NULL, *vlist = element_map->vert[i]; - UvElement *iterv, *v, *lastv, *next; - float *uv, *uv2, uvdiff[2]; - - while (vlist) { - v = vlist; - vlist = vlist->next; - v->next = newvlist; - newvlist = v; - - l = v->l; - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uv = luv->uv; - - lastv = NULL; - iterv = vlist; - - while (iterv) { - next = iterv->next; - - l = iterv->l; - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uv2 = luv->uv; - - sub_v2_v2v2(uvdiff, uv2, uv); - - if (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT && - (!use_winding || winding[BM_elem_index_get(iterv->l->f)] == winding[BM_elem_index_get(v->l->f)])) - { - if (lastv) lastv->next = next; - else vlist = next; - iterv->next = newvlist; - newvlist = iterv; - } - else { - lastv = iterv; - } - - iterv = next; - } - - newvlist->separate = 1; - } - - element_map->vert[i] = newvlist; - } - - if (use_winding) { - MEM_freeN(winding); - } - - if (do_islands) { - unsigned int *map; - BMFace **stack; - int stacksize = 0; - UvElement *islandbuf; - /* island number for faces */ - int *island_number = NULL; - - int nislands = 0, islandbufsize = 0; - - /* map holds the map from current vmap->buf to the new, sorted map */ - map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap"); - stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack"); - islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer"); - island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face"); - copy_vn_i(island_number, totfaces, INVALID_ISLAND); - - /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. - * Now we should sort uv's in islands. */ - for (i = 0; i < totuv; i++) { - if (element_map->buf[i].island == INVALID_ISLAND) { - element_map->buf[i].island = nislands; - stack[0] = element_map->buf[i].l->f; - island_number[BM_elem_index_get(stack[0])] = nislands; - stacksize = 1; - - while (stacksize > 0) { - efa = stack[--stacksize]; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)]; - - for (element = initelement; element; element = element->next) { - if (element->separate) - initelement = element; - - if (element->l->f == efa) { - /* found the uv corresponding to our face and vertex. - * Now fill it to the buffer */ - element->island = nislands; - map[element - element_map->buf] = islandbufsize; - islandbuf[islandbufsize].l = element->l; - islandbuf[islandbufsize].separate = element->separate; - islandbuf[islandbufsize].loop_of_poly_index = element->loop_of_poly_index; - islandbuf[islandbufsize].island = nislands; - islandbufsize++; - - for (element = initelement; element; element = element->next) { - if (element->separate && element != initelement) - break; - - if (island_number[BM_elem_index_get(element->l->f)] == INVALID_ISLAND) { - stack[stacksize++] = element->l->f; - island_number[BM_elem_index_get(element->l->f)] = nislands; - } - } - break; - } - } - } - } - - nislands++; - } - } - - MEM_freeN(island_number); - - /* remap */ - for (i = 0; i < bm->totvert; i++) { - /* important since we may do selection only. Some of these may be NULL */ - if (element_map->vert[i]) - element_map->vert[i] = &islandbuf[map[element_map->vert[i] - element_map->buf]]; - } - - element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands, "UvElementMap_island_indices"); - j = 0; - for (i = 0; i < totuv; i++) { - UvElement *element = element_map->buf[i].next; - if (element == NULL) - islandbuf[map[i]].next = NULL; - else - islandbuf[map[i]].next = &islandbuf[map[element - element_map->buf]]; - - if (islandbuf[i].island != j) { - j++; - element_map->islandIndices[j] = i; - } - } - - MEM_freeN(element_map->buf); - - element_map->buf = islandbuf; - element_map->totalIslands = nislands; - MEM_freeN(stack); - MEM_freeN(map); - } - - BLI_buffer_free(&tf_uv_buf); - - return element_map; + BMVert *ev; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + /* vars from original func */ + UvElementMap *element_map; + UvElement *buf; + bool *winding = NULL; + BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + + MLoopUV *luv; + int totverts, totfaces, i, totuv, j; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); + + totfaces = bm->totface; + totverts = bm->totvert; + totuv = 0; + + /* generate UvElement array */ + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + totuv += efa->len; + } + } + + if (totuv == 0) { + return NULL; + } + + element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap"); + element_map->totalUVs = totuv; + element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts, + "UvElementVerts"); + buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv, + "UvElement"); + + if (use_winding) { + winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding"); + } + + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) { + + if (use_winding) { + winding[j] = false; + } + + if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + float(*tf_uv)[2] = NULL; + + if (use_winding) { + tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len); + } + + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + buf->l = l; + buf->separate = 0; + buf->island = INVALID_ISLAND; + buf->loop_of_poly_index = i; + + buf->next = element_map->vert[BM_elem_index_get(l->v)]; + element_map->vert[BM_elem_index_get(l->v)] = buf; + + if (use_winding) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + copy_v2_v2(tf_uv[i], luv->uv); + } + + buf++; + } + + if (use_winding) { + winding[j] = cross_poly_v2(tf_uv, efa->len) > 0; + } + } + } + + /* sort individual uvs for each vert */ + BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, i) { + UvElement *newvlist = NULL, *vlist = element_map->vert[i]; + UvElement *iterv, *v, *lastv, *next; + float *uv, *uv2, uvdiff[2]; + + while (vlist) { + v = vlist; + vlist = vlist->next; + v->next = newvlist; + newvlist = v; + + l = v->l; + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + uv = luv->uv; + + lastv = NULL; + iterv = vlist; + + while (iterv) { + next = iterv->next; + + l = iterv->l; + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + uv2 = luv->uv; + + sub_v2_v2v2(uvdiff, uv2, uv); + + if (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT && + (!use_winding || + winding[BM_elem_index_get(iterv->l->f)] == winding[BM_elem_index_get(v->l->f)])) { + if (lastv) + lastv->next = next; + else + vlist = next; + iterv->next = newvlist; + newvlist = iterv; + } + else { + lastv = iterv; + } + + iterv = next; + } + + newvlist->separate = 1; + } + + element_map->vert[i] = newvlist; + } + + if (use_winding) { + MEM_freeN(winding); + } + + if (do_islands) { + unsigned int *map; + BMFace **stack; + int stacksize = 0; + UvElement *islandbuf; + /* island number for faces */ + int *island_number = NULL; + + int nislands = 0, islandbufsize = 0; + + /* map holds the map from current vmap->buf to the new, sorted map */ + map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap"); + stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack"); + islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer"); + island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face"); + copy_vn_i(island_number, totfaces, INVALID_ISLAND); + + /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. + * Now we should sort uv's in islands. */ + for (i = 0; i < totuv; i++) { + if (element_map->buf[i].island == INVALID_ISLAND) { + element_map->buf[i].island = nislands; + stack[0] = element_map->buf[i].l->f; + island_number[BM_elem_index_get(stack[0])] = nislands; + stacksize = 1; + + while (stacksize > 0) { + efa = stack[--stacksize]; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)]; + + for (element = initelement; element; element = element->next) { + if (element->separate) + initelement = element; + + if (element->l->f == efa) { + /* found the uv corresponding to our face and vertex. + * Now fill it to the buffer */ + element->island = nislands; + map[element - element_map->buf] = islandbufsize; + islandbuf[islandbufsize].l = element->l; + islandbuf[islandbufsize].separate = element->separate; + islandbuf[islandbufsize].loop_of_poly_index = element->loop_of_poly_index; + islandbuf[islandbufsize].island = nislands; + islandbufsize++; + + for (element = initelement; element; element = element->next) { + if (element->separate && element != initelement) + break; + + if (island_number[BM_elem_index_get(element->l->f)] == INVALID_ISLAND) { + stack[stacksize++] = element->l->f; + island_number[BM_elem_index_get(element->l->f)] = nislands; + } + } + break; + } + } + } + } + + nislands++; + } + } + + MEM_freeN(island_number); + + /* remap */ + for (i = 0; i < bm->totvert; i++) { + /* important since we may do selection only. Some of these may be NULL */ + if (element_map->vert[i]) + element_map->vert[i] = &islandbuf[map[element_map->vert[i] - element_map->buf]]; + } + + element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands, + "UvElementMap_island_indices"); + j = 0; + for (i = 0; i < totuv; i++) { + UvElement *element = element_map->buf[i].next; + if (element == NULL) + islandbuf[map[i]].next = NULL; + else + islandbuf[map[i]].next = &islandbuf[map[element - element_map->buf]]; + + if (islandbuf[i].island != j) { + j++; + element_map->islandIndices[j] = i; + } + } + + MEM_freeN(element_map->buf); + + element_map->buf = islandbuf; + element_map->totalIslands = nislands; + MEM_freeN(stack); + MEM_freeN(map); + } + + BLI_buffer_free(&tf_uv_buf); + + return element_map; } void BM_uv_vert_map_free(UvVertMap *vmap) { - if (vmap) { - if (vmap->vert) MEM_freeN(vmap->vert); - if (vmap->buf) MEM_freeN(vmap->buf); - MEM_freeN(vmap); - } + if (vmap) { + if (vmap->vert) + MEM_freeN(vmap->vert); + if (vmap->buf) + MEM_freeN(vmap->buf); + MEM_freeN(vmap); + } } void BM_uv_element_map_free(UvElementMap *element_map) { - if (element_map) { - if (element_map->vert) MEM_freeN(element_map->vert); - if (element_map->buf) MEM_freeN(element_map->buf); - if (element_map->islandIndices) MEM_freeN(element_map->islandIndices); - MEM_freeN(element_map); - } + if (element_map) { + if (element_map->vert) + MEM_freeN(element_map->vert); + if (element_map->buf) + MEM_freeN(element_map->buf); + if (element_map->islandIndices) + MEM_freeN(element_map->islandIndices); + MEM_freeN(element_map); + } } UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l) { - for (UvElement *element = map->vert[BM_elem_index_get(l->v)]; - element; - element = element->next) - { - if (element->l->f == efa) { - return element; - } - } - - return NULL; + for (UvElement *element = map->vert[BM_elem_index_get(l->v)]; element; element = element->next) { + if (element->l->f == efa) { + return element; + } + } + + return NULL; } /** \} */ @@ -925,33 +955,32 @@ UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l) */ BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected) { - BMFace *efa = NULL; + BMFace *efa = NULL; - if (!EDBM_uv_check(em)) { - return NULL; - } + if (!EDBM_uv_check(em)) { + return NULL; + } - efa = BM_mesh_active_face_get(em->bm, sloppy, selected); + efa = BM_mesh_active_face_get(em->bm, sloppy, selected); - if (efa) { - return efa; - } + if (efa) { + return efa; + } - return NULL; + return NULL; } /* can we edit UV's for this mesh?*/ bool EDBM_uv_check(BMEditMesh *em) { - /* some of these checks could be a touch overkill */ - return em && em->bm->totface && - CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV); + /* some of these checks could be a touch overkill */ + return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV); } bool EDBM_vert_color_check(BMEditMesh *em) { - /* some of these checks could be a touch overkill */ - return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL); + /* some of these checks could be a touch overkill */ + return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL); } /** \} */ @@ -962,8 +991,8 @@ bool EDBM_vert_color_check(BMEditMesh *em) static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index) { - intptr_t eve_i = index_lookup[index]; - return (eve_i == -1) ? NULL : (BMVert *)eve_i; + intptr_t eve_i = index_lookup[index]; + return (eve_i == -1) ? NULL : (BMVert *)eve_i; } /** @@ -994,203 +1023,212 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index) * \param maxdist: Distance for close point test. * \param r_index: Optional array to write into, as an alternative to a customdata layer (length of total verts). */ -void EDBM_verts_mirror_cache_begin_ex( - BMEditMesh *em, const int axis, const bool use_self, const bool use_select, - /* extra args */ - const bool use_topology, float maxdist, int *r_index) +void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, + const int axis, + const bool use_self, + const bool use_select, + /* extra args */ + const bool use_topology, + float maxdist, + int *r_index) { - Mesh *me = (Mesh *)em->ob->data; - BMesh *bm = em->bm; - BMIter iter; - BMVert *v; - int cd_vmirr_offset = 0; - int i; - const float maxdist_sq = SQUARE(maxdist); - - /* one or the other is used depending if topo is enabled */ - KDTree_3d *tree = NULL; - MirrTopoStore_t mesh_topo_store = {NULL, -1, -1, -1}; - - BM_mesh_elem_table_ensure(bm, BM_VERT); - - if (r_index == NULL) { - const char *layer_id = BM_CD_LAYER_ID; - em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id); - if (em->mirror_cdlayer == -1) { - BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_INT, layer_id); - em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id); - } - - cd_vmirr_offset = CustomData_get_n_offset( - &bm->vdata, CD_PROP_INT, - em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT)); - - bm->vdata.layers[em->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY; - } - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - if (use_topology) { - ED_mesh_mirrtopo_init(me, NULL, &mesh_topo_store, true); - } - else { - tree = BLI_kdtree_3d_new(bm->totvert); - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - BLI_kdtree_3d_insert(tree, i, v->co); - } - BLI_kdtree_3d_balance(tree); - } + Mesh *me = (Mesh *)em->ob->data; + BMesh *bm = em->bm; + BMIter iter; + BMVert *v; + int cd_vmirr_offset = 0; + int i; + const float maxdist_sq = SQUARE(maxdist); + + /* one or the other is used depending if topo is enabled */ + KDTree_3d *tree = NULL; + MirrTopoStore_t mesh_topo_store = {NULL, -1, -1, -1}; + + BM_mesh_elem_table_ensure(bm, BM_VERT); + + if (r_index == NULL) { + const char *layer_id = BM_CD_LAYER_ID; + em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id); + if (em->mirror_cdlayer == -1) { + BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_INT, layer_id); + em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id); + } + + cd_vmirr_offset = CustomData_get_n_offset( + &bm->vdata, + CD_PROP_INT, + em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT)); + + bm->vdata.layers[em->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY; + } + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + if (use_topology) { + ED_mesh_mirrtopo_init(me, NULL, &mesh_topo_store, true); + } + else { + tree = BLI_kdtree_3d_new(bm->totvert); + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + BLI_kdtree_3d_insert(tree, i, v->co); + } + BLI_kdtree_3d_balance(tree); + } #define VERT_INTPTR(_v, _i) (r_index ? &r_index[_i] : BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset)) - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - BLI_assert(BM_elem_index_get(v) == i); - - /* temporary for testing, check for selection */ - if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) { - /* do nothing */ - } - else { - BMVert *v_mirr; - int *idx = VERT_INTPTR(v, i); - - if (use_topology) { - v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i); - } - else { - int i_mirr; - float co[3]; - copy_v3_v3(co, v->co); - co[axis] *= -1.0f; - - v_mirr = NULL; - i_mirr = BLI_kdtree_3d_find_nearest(tree, co, NULL); - if (i_mirr != -1) { - BMVert *v_test = BM_vert_at_index(bm, i_mirr); - if (len_squared_v3v3(co, v_test->co) < maxdist_sq) { - v_mirr = v_test; - } - } - } - - if (v_mirr && (use_self || (v_mirr != v))) { - const int i_mirr = BM_elem_index_get(v_mirr); - *idx = i_mirr; - idx = VERT_INTPTR(v_mirr, i_mirr); - *idx = i; - } - else { - *idx = -1; - } - } - - } + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + BLI_assert(BM_elem_index_get(v) == i); + + /* temporary for testing, check for selection */ + if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) { + /* do nothing */ + } + else { + BMVert *v_mirr; + int *idx = VERT_INTPTR(v, i); + + if (use_topology) { + v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i); + } + else { + int i_mirr; + float co[3]; + copy_v3_v3(co, v->co); + co[axis] *= -1.0f; + + v_mirr = NULL; + i_mirr = BLI_kdtree_3d_find_nearest(tree, co, NULL); + if (i_mirr != -1) { + BMVert *v_test = BM_vert_at_index(bm, i_mirr); + if (len_squared_v3v3(co, v_test->co) < maxdist_sq) { + v_mirr = v_test; + } + } + } + + if (v_mirr && (use_self || (v_mirr != v))) { + const int i_mirr = BM_elem_index_get(v_mirr); + *idx = i_mirr; + idx = VERT_INTPTR(v_mirr, i_mirr); + *idx = i; + } + else { + *idx = -1; + } + } + } #undef VERT_INTPTR - if (use_topology) { - ED_mesh_mirrtopo_free(&mesh_topo_store); - } - else { - BLI_kdtree_3d_free(tree); - } + if (use_topology) { + ED_mesh_mirrtopo_free(&mesh_topo_store); + } + else { + BLI_kdtree_3d_free(tree); + } } -void EDBM_verts_mirror_cache_begin( - BMEditMesh *em, const int axis, - const bool use_self, const bool use_select, - const bool use_topology) +void EDBM_verts_mirror_cache_begin(BMEditMesh *em, + const int axis, + const bool use_self, + const bool use_select, + const bool use_topology) { - EDBM_verts_mirror_cache_begin_ex( - em, axis, - use_self, use_select, - /* extra args */ - use_topology, BM_SEARCH_MAXDIST_MIRR, NULL); + EDBM_verts_mirror_cache_begin_ex(em, + axis, + use_self, + use_select, + /* extra args */ + use_topology, + BM_SEARCH_MAXDIST_MIRR, + NULL); } BMVert *EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v) { - const int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer); + const int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer); - BLI_assert(em->mirror_cdlayer != -1); /* invalid use */ + BLI_assert(em->mirror_cdlayer != -1); /* invalid use */ - if (mirr && *mirr >= 0 && *mirr < em->bm->totvert) { - if (!em->bm->vtable) { - printf("err: should only be called between " - "EDBM_verts_mirror_cache_begin and EDBM_verts_mirror_cache_end"); - return NULL; - } + if (mirr && *mirr >= 0 && *mirr < em->bm->totvert) { + if (!em->bm->vtable) { + printf( + "err: should only be called between " + "EDBM_verts_mirror_cache_begin and EDBM_verts_mirror_cache_end"); + return NULL; + } - return em->bm->vtable[*mirr]; - } + return em->bm->vtable[*mirr]; + } - return NULL; + return NULL; } BMEdge *EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e) { - BMVert *v1_mirr = EDBM_verts_mirror_get(em, e->v1); - if (v1_mirr) { - BMVert *v2_mirr = EDBM_verts_mirror_get(em, e->v2); - if (v2_mirr) { - return BM_edge_exists(v1_mirr, v2_mirr); - } - } - - return NULL; + BMVert *v1_mirr = EDBM_verts_mirror_get(em, e->v1); + if (v1_mirr) { + BMVert *v2_mirr = EDBM_verts_mirror_get(em, e->v2); + if (v2_mirr) { + return BM_edge_exists(v1_mirr, v2_mirr); + } + } + + return NULL; } BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f) { - BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len); + BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len); - BMLoop *l_iter, *l_first; - unsigned int i = 0; + BMLoop *l_iter, *l_first; + unsigned int i = 0; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if ((v_mirr_arr[i++] = EDBM_verts_mirror_get(em, l_iter->v)) == NULL) { - return NULL; - } - } while ((l_iter = l_iter->next) != l_first); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if ((v_mirr_arr[i++] = EDBM_verts_mirror_get(em, l_iter->v)) == NULL) { + return NULL; + } + } while ((l_iter = l_iter->next) != l_first); - return BM_face_exists(v_mirr_arr, f->len); + return BM_face_exists(v_mirr_arr, f->len); } void EDBM_verts_mirror_cache_clear(BMEditMesh *em, BMVert *v) { - int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer); + int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer); - BLI_assert(em->mirror_cdlayer != -1); /* invalid use */ + BLI_assert(em->mirror_cdlayer != -1); /* invalid use */ - if (mirr) { - *mirr = -1; - } + if (mirr) { + *mirr = -1; + } } void EDBM_verts_mirror_cache_end(BMEditMesh *em) { - em->mirror_cdlayer = -1; + em->mirror_cdlayer = -1; } void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_to) { - BMIter iter; - BMVert *v; - - BLI_assert((em->bm->vtable != NULL) && ((em->bm->elem_table_dirty & BM_VERT) == 0)); - - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT) == sel_from) { - BMVert *mirr = EDBM_verts_mirror_get(em, v); - if (mirr) { - if (BM_elem_flag_test(mirr, BM_ELEM_SELECT) == sel_to) { - copy_v3_v3(mirr->co, v->co); - mirr->co[0] *= -1.0f; - } - } - } - } + BMIter iter; + BMVert *v; + + BLI_assert((em->bm->vtable != NULL) && ((em->bm->elem_table_dirty & BM_VERT) == 0)); + + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT) == sel_from) { + BMVert *mirr = EDBM_verts_mirror_get(em, v); + if (mirr) { + if (BM_elem_flag_test(mirr, BM_ELEM_SELECT) == sel_to) { + copy_v3_v3(mirr->co, v->co); + mirr->co[0] *= -1.0f; + } + } + } + } } /** \} */ @@ -1202,105 +1240,105 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t /* swap is 0 or 1, if 1 it hides not selected */ bool EDBM_mesh_hide(BMEditMesh *em, bool swap) { - BMIter iter; - BMElem *ele; - int itermode; - char hflag_swap = swap ? BM_ELEM_SELECT : 0; - bool changed = true; - - if (em->selectmode & SCE_SELECT_VERTEX) - itermode = BM_VERTS_OF_MESH; - else if (em->selectmode & SCE_SELECT_EDGE) - itermode = BM_EDGES_OF_MESH; - else - itermode = BM_FACES_OF_MESH; - - BM_ITER_MESH (ele, &iter, em->bm, itermode) { - if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) { - if (BM_elem_flag_test(ele, BM_ELEM_SELECT) ^ hflag_swap) { - BM_elem_hide_set(em->bm, ele, true); - changed = true; - } - } - } - - if (changed) { - EDBM_selectmode_flush(em); - } - return changed; - - /* original hide flushing comment (OUTDATED): - * hide happens on least dominant select mode, and flushes up, not down! - * (helps preventing errors in subsurf) */ - /* - vertex hidden, always means edge is hidden too - * - edge hidden, always means face is hidden too - * - face hidden, only set face hide - * - then only flush back down what's absolute hidden - */ + BMIter iter; + BMElem *ele; + int itermode; + char hflag_swap = swap ? BM_ELEM_SELECT : 0; + bool changed = true; + + if (em->selectmode & SCE_SELECT_VERTEX) + itermode = BM_VERTS_OF_MESH; + else if (em->selectmode & SCE_SELECT_EDGE) + itermode = BM_EDGES_OF_MESH; + else + itermode = BM_FACES_OF_MESH; + + BM_ITER_MESH (ele, &iter, em->bm, itermode) { + if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT) ^ hflag_swap) { + BM_elem_hide_set(em->bm, ele, true); + changed = true; + } + } + } + + if (changed) { + EDBM_selectmode_flush(em); + } + return changed; + + /* original hide flushing comment (OUTDATED): + * hide happens on least dominant select mode, and flushes up, not down! + * (helps preventing errors in subsurf) */ + /* - vertex hidden, always means edge is hidden too + * - edge hidden, always means face is hidden too + * - face hidden, only set face hide + * - then only flush back down what's absolute hidden + */ } bool EDBM_mesh_reveal(BMEditMesh *em, bool select) { - const char iter_types[3] = { - BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH, - }; - - const bool sels[3] = { - (em->selectmode & SCE_SELECT_VERTEX) != 0, - (em->selectmode & SCE_SELECT_EDGE) != 0, - (em->selectmode & SCE_SELECT_FACE) != 0, - }; - int i; - bool changed = false; - - /* Use tag flag to remember what was hidden before all is revealed. - * BM_ELEM_HIDDEN --> BM_ELEM_TAG */ - for (i = 0; i < 3; i++) { - BMIter iter; - BMElem *ele; - - BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) { - if (BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) { - BM_elem_flag_enable(ele, BM_ELEM_TAG); - changed = true; - } - else { - BM_elem_flag_disable(ele, BM_ELEM_TAG); - } - } - } - - if (!changed) { - return false; - } - - /* Reveal everything */ - EDBM_flag_disable_all(em, BM_ELEM_HIDDEN); - - /* Select relevant just-revealed elements */ - for (i = 0; i < 3; i++) { - BMIter iter; - BMElem *ele; - - if (!sels[i]) { - continue; - } - - BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) { - if (BM_elem_flag_test(ele, BM_ELEM_TAG)) { - BM_elem_select_set(em->bm, ele, select); - } - } - } - - EDBM_selectmode_flush(em); - - /* hidden faces can have invalid normals */ - EDBM_mesh_normals_update(em); - - return true; + const char iter_types[3] = { + BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH, + }; + + const bool sels[3] = { + (em->selectmode & SCE_SELECT_VERTEX) != 0, + (em->selectmode & SCE_SELECT_EDGE) != 0, + (em->selectmode & SCE_SELECT_FACE) != 0, + }; + int i; + bool changed = false; + + /* Use tag flag to remember what was hidden before all is revealed. + * BM_ELEM_HIDDEN --> BM_ELEM_TAG */ + for (i = 0; i < 3; i++) { + BMIter iter; + BMElem *ele; + + BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) { + if (BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) { + BM_elem_flag_enable(ele, BM_ELEM_TAG); + changed = true; + } + else { + BM_elem_flag_disable(ele, BM_ELEM_TAG); + } + } + } + + if (!changed) { + return false; + } + + /* Reveal everything */ + EDBM_flag_disable_all(em, BM_ELEM_HIDDEN); + + /* Select relevant just-revealed elements */ + for (i = 0; i < 3; i++) { + BMIter iter; + BMElem *ele; + + if (!sels[i]) { + continue; + } + + BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) { + if (BM_elem_flag_test(ele, BM_ELEM_TAG)) { + BM_elem_select_set(em->bm, ele, select); + } + } + } + + EDBM_selectmode_flush(em); + + /* hidden faces can have invalid normals */ + EDBM_mesh_normals_update(em); + + return true; } /** \} */ @@ -1311,73 +1349,73 @@ bool EDBM_mesh_reveal(BMEditMesh *em, bool select) void EDBM_mesh_normals_update(BMEditMesh *em) { - BM_mesh_normals_update(em->bm); + BM_mesh_normals_update(em->bm); } void EDBM_stats_update(BMEditMesh *em) { - const char iter_types[3] = { - BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH, - }; - - BMIter iter; - BMElem *ele; - int *tots[3]; - int i; - - tots[0] = &em->bm->totvertsel; - tots[1] = &em->bm->totedgesel; - tots[2] = &em->bm->totfacesel; - - em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; - - for (i = 0; i < 3; i++) { - ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL); - for ( ; ele; ele = BM_iter_step(&iter)) { - if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { - (*tots[i])++; - } - } - } + const char iter_types[3] = { + BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH, + }; + + BMIter iter; + BMElem *ele; + int *tots[3]; + int i; + + tots[0] = &em->bm->totvertsel; + tots[1] = &em->bm->totedgesel; + tots[2] = &em->bm->totfacesel; + + em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; + + for (i = 0; i < 3; i++) { + ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL); + for (; ele; ele = BM_iter_step(&iter)) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { + (*tots[i])++; + } + } + } } /* 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) { - 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 (is_destructive) { - /* TODO. we may be able to remove this now! - Campbell */ - // BM_mesh_elem_table_free(em->bm, BM_ALL_NOLOOP); - } - else { - /* in debug mode double check we didn't need to recalculate */ - BLI_assert(BM_mesh_elem_table_check(em->bm) == true); - } - if (em->bm->spacearr_dirty & BM_SPACEARR_BMO_SET) { - BM_lnorspace_invalidate(em->bm, false); - em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET; - } - /* don't keep stale derivedMesh data around, see: [#38872] */ - BKE_editmesh_free_derivedmesh(em); + 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 (is_destructive) { + /* TODO. we may be able to remove this now! - Campbell */ + // BM_mesh_elem_table_free(em->bm, BM_ALL_NOLOOP); + } + else { + /* in debug mode double check we didn't need to recalculate */ + BLI_assert(BM_mesh_elem_table_check(em->bm) == true); + } + if (em->bm->spacearr_dirty & BM_SPACEARR_BMO_SET) { + BM_lnorspace_invalidate(em->bm, false); + em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET; + } + /* don't keep stale derivedMesh data around, see: [#38872] */ + BKE_editmesh_free_derivedmesh(em); #ifdef DEBUG - { - BMEditSelection *ese; - for (ese = em->bm->selected.first; ese; ese = ese->next) { - BLI_assert(BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)); - } - } + { + BMEditSelection *ese; + for (ese = em->bm->selected.first; ese; ese = ese->next) { + BLI_assert(BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)); + } + } #endif } @@ -1390,11 +1428,11 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d /* poll call for mesh operators requiring a view3d context */ bool EDBM_view3d_poll(bContext *C) { - if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) { - return 1; - } + if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) { + return 1; + } - return 0; + return 0; } /** \} */ @@ -1405,19 +1443,19 @@ bool EDBM_view3d_poll(bContext *C) BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa) { - BMElem *ele = NULL; - - if ((em->selectmode & SCE_SELECT_VERTEX) && eve) { - ele = (BMElem *)eve; - } - else if ((em->selectmode & SCE_SELECT_EDGE) && eed) { - ele = (BMElem *)eed; - } - else if ((em->selectmode & SCE_SELECT_FACE) && efa) { - ele = (BMElem *)efa; - } - - return ele; + BMElem *ele = NULL; + + if ((em->selectmode & SCE_SELECT_VERTEX) && eve) { + ele = (BMElem *)eve; + } + else if ((em->selectmode & SCE_SELECT_EDGE) && eed) { + ele = (BMElem *)eed; + } + else if ((em->selectmode & SCE_SELECT_FACE) && efa) { + ele = (BMElem *)efa; + } + + return ele; } /** @@ -1427,44 +1465,44 @@ BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFa */ int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele) { - BMesh *bm = em->bm; - int index = BM_elem_index_get(ele); - - if (ele->head.htype == BM_VERT) { - BLI_assert(!(bm->elem_index_dirty & BM_VERT)); - } - else if (ele->head.htype == BM_EDGE) { - BLI_assert(!(bm->elem_index_dirty & BM_EDGE)); - index += bm->totvert; - } - else if (ele->head.htype == BM_FACE) { - BLI_assert(!(bm->elem_index_dirty & BM_FACE)); - index += bm->totvert + bm->totedge; - } - else { - BLI_assert(0); - } - - return index; + BMesh *bm = em->bm; + int index = BM_elem_index_get(ele); + + if (ele->head.htype == BM_VERT) { + BLI_assert(!(bm->elem_index_dirty & BM_VERT)); + } + else if (ele->head.htype == BM_EDGE) { + BLI_assert(!(bm->elem_index_dirty & BM_EDGE)); + index += bm->totvert; + } + else if (ele->head.htype == BM_FACE) { + BLI_assert(!(bm->elem_index_dirty & BM_FACE)); + index += bm->totvert + bm->totedge; + } + else { + BLI_assert(0); + } + + return index; } BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index) { - BMesh *bm = em->bm; - - if (index < bm->totvert) { - return (BMElem *)BM_vert_at_index_find_or_table(bm, index); - } - index -= bm->totvert; - if (index < bm->totedge) { - return (BMElem *)BM_edge_at_index_find_or_table(bm, index); - } - index -= bm->totedge; - if (index < bm->totface) { - return (BMElem *)BM_face_at_index_find_or_table(bm, index); - } - - return NULL; + BMesh *bm = em->bm; + + if (index < bm->totvert) { + return (BMElem *)BM_vert_at_index_find_or_table(bm, index); + } + index -= bm->totvert; + if (index < bm->totedge) { + return (BMElem *)BM_edge_at_index_find_or_table(bm, index); + } + index -= bm->totedge; + if (index < bm->totface) { + return (BMElem *)BM_face_at_index_find_or_table(bm, index); + } + + return NULL; } /** \} */ @@ -1473,83 +1511,87 @@ BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index) /** \name BMesh BVH API * \{ */ -static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e) +static BMFace *edge_ray_cast( + struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e) { - BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL); + BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL); - if (f && BM_edge_in_face(e, f)) { - return NULL; - } + if (f && BM_edge_in_face(e, f)) { + return NULL; + } - return f; + return f; } static void scale_point(float c1[3], const float p[3], const float s) { - sub_v3_v3(c1, p); - mul_v3_fl(c1, s); - add_v3_v3(c1, p); + sub_v3_v3(c1, p); + mul_v3_fl(c1, s); + add_v3_v3(c1, p); } -bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, +bool BMBVH_EdgeVisible(struct BMBVHTree *tree, + BMEdge *e, struct Depsgraph *depsgraph, - ARegion *ar, View3D *v3d, Object *obedit) + ARegion *ar, + View3D *v3d, + Object *obedit) { - BMFace *f; - float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3]; - float origin[3], invmat[4][4]; - float epsilon = 0.01f; - float end[3]; - const float mval_f[2] = { - ar->winx / 2.0f, - ar->winy / 2.0f, - }; - - ED_view3d_win_to_segment_clipped(depsgraph, ar, v3d, mval_f, origin, end, false); - - invert_m4_m4(invmat, obedit->obmat); - mul_m4_v3(invmat, origin); - - copy_v3_v3(co1, e->v1->co); - mid_v3_v3v3(co2, e->v1->co, e->v2->co); - copy_v3_v3(co3, e->v2->co); - - scale_point(co1, co2, 0.99); - scale_point(co3, co2, 0.99); - - /* ok, idea is to generate rays going from the camera origin to the - * three points on the edge (v1, mid, v2)*/ - sub_v3_v3v3(dir1, origin, co1); - sub_v3_v3v3(dir2, origin, co2); - sub_v3_v3v3(dir3, origin, co3); - - normalize_v3_length(dir1, epsilon); - normalize_v3_length(dir2, epsilon); - normalize_v3_length(dir3, epsilon); - - /* offset coordinates slightly along view vectors, to avoid - * hitting the faces that own the edge.*/ - add_v3_v3v3(co1, co1, dir1); - add_v3_v3v3(co2, co2, dir2); - add_v3_v3v3(co3, co3, dir3); - - normalize_v3(dir1); - normalize_v3(dir2); - normalize_v3(dir3); - - /* do three samplings: left, middle, right */ - f = edge_ray_cast(tree, co1, dir1, NULL, e); - if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) { - return true; - } - else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) { - return true; - } - else if (!f) { - return true; - } - - return false; + BMFace *f; + float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3]; + float origin[3], invmat[4][4]; + float epsilon = 0.01f; + float end[3]; + const float mval_f[2] = { + ar->winx / 2.0f, + ar->winy / 2.0f, + }; + + ED_view3d_win_to_segment_clipped(depsgraph, ar, v3d, mval_f, origin, end, false); + + invert_m4_m4(invmat, obedit->obmat); + mul_m4_v3(invmat, origin); + + copy_v3_v3(co1, e->v1->co); + mid_v3_v3v3(co2, e->v1->co, e->v2->co); + copy_v3_v3(co3, e->v2->co); + + scale_point(co1, co2, 0.99); + scale_point(co3, co2, 0.99); + + /* ok, idea is to generate rays going from the camera origin to the + * three points on the edge (v1, mid, v2)*/ + sub_v3_v3v3(dir1, origin, co1); + sub_v3_v3v3(dir2, origin, co2); + sub_v3_v3v3(dir3, origin, co3); + + normalize_v3_length(dir1, epsilon); + normalize_v3_length(dir2, epsilon); + normalize_v3_length(dir3, epsilon); + + /* offset coordinates slightly along view vectors, to avoid + * hitting the faces that own the edge.*/ + add_v3_v3v3(co1, co1, dir1); + add_v3_v3v3(co2, co2, dir2); + add_v3_v3v3(co3, co3, dir3); + + normalize_v3(dir1); + normalize_v3(dir2); + normalize_v3(dir3); + + /* do three samplings: left, middle, right */ + f = edge_ray_cast(tree, co1, dir1, NULL, e); + if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) { + return true; + } + else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) { + return true; + } + else if (!f) { + return true; + } + + return false; } /** \} */ diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 3d880fc0bfe..2f4fbcab9bc 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -52,651 +52,651 @@ #include "ED_uvedit.h" #include "ED_view3d.h" -#include "mesh_intern.h" /* own include */ - +#include "mesh_intern.h" /* own include */ static CustomData *mesh_customdata_get_type(Mesh *me, const char htype, int *r_tot) { - CustomData *data; - BMesh *bm = (me->edit_mesh) ? me->edit_mesh->bm : NULL; - int tot; - - /* this */ - switch (htype) { - case BM_VERT: - if (bm) { - data = &bm->vdata; - tot = bm->totvert; - } - else { - data = &me->vdata; - tot = me->totvert; - } - break; - case BM_EDGE: - if (bm) { - data = &bm->edata; - tot = bm->totedge; - } - else { - data = &me->edata; - tot = me->totedge; - } - break; - case BM_LOOP: - if (bm) { - data = &bm->ldata; - tot = bm->totloop; - } - else { - data = &me->ldata; - tot = me->totloop; - } - break; - case BM_FACE: - if (bm) { - data = &bm->pdata; - tot = bm->totface; - } - else { - data = &me->pdata; - tot = me->totpoly; - } - break; - default: - BLI_assert(0); - tot = 0; - data = NULL; - break; - } - - *r_tot = tot; - return data; + CustomData *data; + BMesh *bm = (me->edit_mesh) ? me->edit_mesh->bm : NULL; + int tot; + + /* this */ + switch (htype) { + case BM_VERT: + if (bm) { + data = &bm->vdata; + tot = bm->totvert; + } + else { + data = &me->vdata; + tot = me->totvert; + } + break; + case BM_EDGE: + if (bm) { + data = &bm->edata; + tot = bm->totedge; + } + else { + data = &me->edata; + tot = me->totedge; + } + break; + case BM_LOOP: + if (bm) { + data = &bm->ldata; + tot = bm->totloop; + } + else { + data = &me->ldata; + tot = me->totloop; + } + break; + case BM_FACE: + if (bm) { + data = &bm->pdata; + tot = bm->totface; + } + else { + data = &me->pdata; + tot = me->totpoly; + } + break; + default: + BLI_assert(0); + tot = 0; + data = NULL; + break; + } + + *r_tot = tot; + return data; } #define GET_CD_DATA(me, data) ((me)->edit_mesh ? &(me)->edit_mesh->bm->data : &(me)->data) static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer) { - const int type = layer->type; - CustomData *data; - int layer_index, tot, n; - - data = mesh_customdata_get_type(me, (ELEM(type, CD_MLOOPUV, CD_MLOOPCOL)) ? BM_LOOP : BM_FACE, &tot); - layer_index = CustomData_get_layer_index(data, type); - n = (layer - &data->layers[layer_index]); - BLI_assert(n >= 0 && (n + layer_index) < data->totlayer); - - if (me->edit_mesh) { - BM_data_layer_free_n(me->edit_mesh->bm, data, type, n); - } - else { - CustomData_free_layer(data, type, tot, layer_index + n); - BKE_mesh_update_customdata_pointers(me, true); - } + const int type = layer->type; + CustomData *data; + int layer_index, tot, n; + + data = mesh_customdata_get_type( + me, (ELEM(type, CD_MLOOPUV, CD_MLOOPCOL)) ? BM_LOOP : BM_FACE, &tot); + layer_index = CustomData_get_layer_index(data, type); + n = (layer - &data->layers[layer_index]); + BLI_assert(n >= 0 && (n + layer_index) < data->totlayer); + + if (me->edit_mesh) { + BM_data_layer_free_n(me->edit_mesh->bm, data, type, n); + } + else { + CustomData_free_layer(data, type, tot, layer_index + n); + BKE_mesh_update_customdata_pointers(me, true); + } } static void mesh_uv_reset_array(float **fuv, const int len) { - if (len == 3) { - fuv[0][0] = 0.0; - fuv[0][1] = 0.0; - - fuv[1][0] = 1.0; - fuv[1][1] = 0.0; - - fuv[2][0] = 1.0; - fuv[2][1] = 1.0; - } - else if (len == 4) { - fuv[0][0] = 0.0; - fuv[0][1] = 0.0; - - fuv[1][0] = 1.0; - fuv[1][1] = 0.0; - - fuv[2][0] = 1.0; - fuv[2][1] = 1.0; - - fuv[3][0] = 0.0; - fuv[3][1] = 1.0; - /*make sure we ignore 2-sided faces*/ - } - else if (len > 2) { - float fac = 0.0f, dfac = 1.0f / (float)len; - int i; - - dfac *= (float)M_PI * 2.0f; - - for (i = 0; i < len; i++) { - fuv[i][0] = 0.5f * sinf(fac) + 0.5f; - fuv[i][1] = 0.5f * cosf(fac) + 0.5f; - - fac += dfac; - } - } + if (len == 3) { + fuv[0][0] = 0.0; + fuv[0][1] = 0.0; + + fuv[1][0] = 1.0; + fuv[1][1] = 0.0; + + fuv[2][0] = 1.0; + fuv[2][1] = 1.0; + } + else if (len == 4) { + fuv[0][0] = 0.0; + fuv[0][1] = 0.0; + + fuv[1][0] = 1.0; + fuv[1][1] = 0.0; + + fuv[2][0] = 1.0; + fuv[2][1] = 1.0; + + fuv[3][0] = 0.0; + fuv[3][1] = 1.0; + /*make sure we ignore 2-sided faces*/ + } + else if (len > 2) { + float fac = 0.0f, dfac = 1.0f / (float)len; + int i; + + dfac *= (float)M_PI * 2.0f; + + for (i = 0; i < len; i++) { + fuv[i][0] = 0.5f * sinf(fac) + 0.5f; + fuv[i][1] = 0.5f * cosf(fac) + 0.5f; + + fac += dfac; + } + } } static void mesh_uv_reset_bmface(BMFace *f, const int cd_loop_uv_offset) { - float **fuv = BLI_array_alloca(fuv, f->len); - BMIter liter; - BMLoop *l; - int i; + float **fuv = BLI_array_alloca(fuv, f->len); + BMIter liter; + BMLoop *l; + int i; - BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, i) { - fuv[i] = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; - } + BM_ITER_ELEM_INDEX(l, &liter, f, BM_LOOPS_OF_FACE, i) + { + fuv[i] = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; + } - mesh_uv_reset_array(fuv, f->len); + mesh_uv_reset_array(fuv, f->len); } static void mesh_uv_reset_mface(MPoly *mp, MLoopUV *mloopuv) { - float **fuv = BLI_array_alloca(fuv, mp->totloop); - int i; + float **fuv = BLI_array_alloca(fuv, mp->totloop); + int i; - for (i = 0; i < mp->totloop; i++) { - fuv[i] = mloopuv[mp->loopstart + i].uv; - } + for (i = 0; i < mp->totloop; i++) { + fuv[i] = mloopuv[mp->loopstart + i].uv; + } - mesh_uv_reset_array(fuv, mp->totloop); + mesh_uv_reset_array(fuv, mp->totloop); } /* without bContext, called in uvedit */ void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum) { - BMEditMesh *em = me->edit_mesh; + BMEditMesh *em = me->edit_mesh; - if (em) { - /* Collect BMesh UVs */ - const int cd_loop_uv_offset = CustomData_get_n_offset(&em->bm->ldata, CD_MLOOPUV, layernum); + if (em) { + /* Collect BMesh UVs */ + const int cd_loop_uv_offset = CustomData_get_n_offset(&em->bm->ldata, CD_MLOOPUV, layernum); - BMFace *efa; - BMIter iter; + BMFace *efa; + BMIter iter; - BLI_assert(cd_loop_uv_offset != -1); + BLI_assert(cd_loop_uv_offset != -1); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; - mesh_uv_reset_bmface(efa, cd_loop_uv_offset); - } - } - else { - /* Collect Mesh UVs */ - MLoopUV *mloopuv; - int i; + mesh_uv_reset_bmface(efa, cd_loop_uv_offset); + } + } + else { + /* Collect Mesh UVs */ + MLoopUV *mloopuv; + int i; - BLI_assert(CustomData_has_layer(&me->ldata, CD_MLOOPUV)); - mloopuv = CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, layernum); + BLI_assert(CustomData_has_layer(&me->ldata, CD_MLOOPUV)); + mloopuv = CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, layernum); - for (i = 0; i < me->totpoly; i++) { - mesh_uv_reset_mface(&me->mpoly[i], mloopuv); - } - } + for (i = 0; i < me->totpoly; i++) { + mesh_uv_reset_mface(&me->mpoly[i], mloopuv); + } + } - DEG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); } void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me) { - /* could be ldata or pdata */ - CustomData *ldata = GET_CD_DATA(me, ldata); - const int layernum = CustomData_get_active_layer(ldata, CD_MLOOPUV); - ED_mesh_uv_loop_reset_ex(me, layernum); + /* could be ldata or pdata */ + CustomData *ldata = GET_CD_DATA(me, ldata); + const int layernum = CustomData_get_active_layer(ldata, CD_MLOOPUV); + ED_mesh_uv_loop_reset_ex(me, layernum); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); } /* note: keep in sync with ED_mesh_color_add */ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set, const bool do_init) { - BMEditMesh *em; - int layernum_dst; - - bool is_init = false; - - if (me->edit_mesh) { - em = me->edit_mesh; - - layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV); - if (layernum_dst >= MAX_MTFACE) - return -1; - - /* CD_MLOOPUV */ - BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_MLOOPUV, name); - /* copy data from active UV */ - if (layernum_dst && do_init) { - const int layernum_src = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPUV); - BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPUV, layernum_src, layernum_dst); - - is_init = true; - } - if (active_set || layernum_dst == 0) { - CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum_dst); - } - } - else { - layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); - if (layernum_dst >= MAX_MTFACE) - return -1; - - 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); - } - - /* don't overwrite our copied coords */ - if (!is_init && do_init) { - ED_mesh_uv_loop_reset_ex(me, layernum_dst); - } - - DEG_id_tag_update(&me->id, 0); - WM_main_add_notifier(NC_GEOM | ND_DATA, me); - - return layernum_dst; + BMEditMesh *em; + int layernum_dst; + + bool is_init = false; + + if (me->edit_mesh) { + em = me->edit_mesh; + + layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV); + if (layernum_dst >= MAX_MTFACE) + return -1; + + /* CD_MLOOPUV */ + BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_MLOOPUV, name); + /* copy data from active UV */ + if (layernum_dst && do_init) { + const int layernum_src = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPUV); + BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPUV, layernum_src, layernum_dst); + + is_init = true; + } + if (active_set || layernum_dst == 0) { + CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum_dst); + } + } + else { + layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); + if (layernum_dst >= MAX_MTFACE) + return -1; + + 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); + } + + /* don't overwrite our copied coords */ + if (!is_init && do_init) { + ED_mesh_uv_loop_reset_ex(me, layernum_dst); + } + + DEG_id_tag_update(&me->id, 0); + WM_main_add_notifier(NC_GEOM | ND_DATA, me); + + return layernum_dst; } void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name) { - BMEditMesh *em; - int layernum_dst; - - if (me->edit_mesh) { - em = me->edit_mesh; - - layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV); - if (layernum_dst == 0) - ED_mesh_uv_texture_add(me, name, true, true); - } - else { - layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); - if (layernum_dst == 0) - ED_mesh_uv_texture_add(me, name, true, true); - } + BMEditMesh *em; + int layernum_dst; + + if (me->edit_mesh) { + em = me->edit_mesh; + + layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV); + if (layernum_dst == 0) + ED_mesh_uv_texture_add(me, name, true, true); + } + else { + layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); + if (layernum_dst == 0) + ED_mesh_uv_texture_add(me, name, true, true); + } } - bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n) { - CustomData *ldata = GET_CD_DATA(me, ldata); - CustomDataLayer *cdlu; - int index; + CustomData *ldata = GET_CD_DATA(me, ldata); + CustomDataLayer *cdlu; + int index; - index = CustomData_get_layer_index_n(ldata, CD_MLOOPUV, n); - cdlu = (index == -1) ? NULL : &ldata->layers[index]; + index = CustomData_get_layer_index_n(ldata, CD_MLOOPUV, n); + cdlu = (index == -1) ? NULL : &ldata->layers[index]; - if (!cdlu) - return false; + if (!cdlu) + return false; - delete_customdata_layer(me, cdlu); + delete_customdata_layer(me, cdlu); - DEG_id_tag_update(&me->id, 0); - WM_main_add_notifier(NC_GEOM | ND_DATA, me); + DEG_id_tag_update(&me->id, 0); + WM_main_add_notifier(NC_GEOM | ND_DATA, me); - return true; + return true; } bool ED_mesh_uv_texture_remove_active(Mesh *me) { - /* texpoly/uv are assumed to be in sync */ - CustomData *ldata = GET_CD_DATA(me, ldata); - const int n = CustomData_get_active_layer(ldata, CD_MLOOPUV); - - if (n != -1) { - return ED_mesh_uv_texture_remove_index(me, n); - } - else { - return false; - } + /* texpoly/uv are assumed to be in sync */ + CustomData *ldata = GET_CD_DATA(me, ldata); + const int n = CustomData_get_active_layer(ldata, CD_MLOOPUV); + + if (n != -1) { + return ED_mesh_uv_texture_remove_index(me, n); + } + else { + return false; + } } bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name) { - /* texpoly/uv are assumed to be in sync */ - CustomData *ldata = GET_CD_DATA(me, ldata); - const int n = CustomData_get_named_layer(ldata, CD_MLOOPUV, name); - if (n != -1) { - return ED_mesh_uv_texture_remove_index(me, n); - } - else { - return false; - } + /* texpoly/uv are assumed to be in sync */ + CustomData *ldata = GET_CD_DATA(me, ldata); + const int n = CustomData_get_named_layer(ldata, CD_MLOOPUV, name); + if (n != -1) { + return ED_mesh_uv_texture_remove_index(me, n); + } + else { + return false; + } } /* note: keep in sync with ED_mesh_uv_texture_add */ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set, const bool do_init) { - BMEditMesh *em; - int layernum; - - if (me->edit_mesh) { - em = me->edit_mesh; - - layernum = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL); - if (layernum >= MAX_MCOL) { - return -1; - } - - /* CD_MLOOPCOL */ - BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_MLOOPCOL, name); - /* copy data from active vertex color layer */ - if (layernum && do_init) { - const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPCOL); - BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum_dst, layernum); - } - if (active_set || layernum == 0) { - CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum); - } - } - else { - layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); - if (layernum >= MAX_MCOL) { - return -1; - } - - 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); - } - - DEG_id_tag_update(&me->id, 0); - WM_main_add_notifier(NC_GEOM | ND_DATA, me); - - return layernum; + BMEditMesh *em; + int layernum; + + if (me->edit_mesh) { + em = me->edit_mesh; + + layernum = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL); + if (layernum >= MAX_MCOL) { + return -1; + } + + /* CD_MLOOPCOL */ + BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_MLOOPCOL, name); + /* copy data from active vertex color layer */ + if (layernum && do_init) { + const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPCOL); + BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum_dst, layernum); + } + if (active_set || layernum == 0) { + CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum); + } + } + else { + layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); + if (layernum >= MAX_MCOL) { + return -1; + } + + 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); + } + + DEG_id_tag_update(&me->id, 0); + WM_main_add_notifier(NC_GEOM | ND_DATA, me); + + return layernum; } bool ED_mesh_color_ensure(struct Mesh *me, const char *name) { - BLI_assert(me->edit_mesh == NULL); + BLI_assert(me->edit_mesh == NULL); - if (!me->mloopcol && me->totloop) { - CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name); - BKE_mesh_update_customdata_pointers(me, true); - } + if (!me->mloopcol && me->totloop) { + CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name); + BKE_mesh_update_customdata_pointers(me, true); + } - DEG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); - return (me->mloopcol != NULL); + return (me->mloopcol != NULL); } bool ED_mesh_color_remove_index(Mesh *me, const int n) { - CustomData *ldata = GET_CD_DATA(me, ldata); - CustomDataLayer *cdl; - int index; + CustomData *ldata = GET_CD_DATA(me, ldata); + CustomDataLayer *cdl; + int index; - index = CustomData_get_layer_index_n(ldata, CD_MLOOPCOL, n); - cdl = (index == -1) ? NULL : &ldata->layers[index]; + index = CustomData_get_layer_index_n(ldata, CD_MLOOPCOL, n); + cdl = (index == -1) ? NULL : &ldata->layers[index]; - if (!cdl) - return false; + if (!cdl) + return false; - delete_customdata_layer(me, cdl); - DEG_id_tag_update(&me->id, 0); - WM_main_add_notifier(NC_GEOM | ND_DATA, me); + delete_customdata_layer(me, cdl); + DEG_id_tag_update(&me->id, 0); + WM_main_add_notifier(NC_GEOM | ND_DATA, me); - return true; + return true; } bool ED_mesh_color_remove_active(Mesh *me) { - CustomData *ldata = GET_CD_DATA(me, ldata); - const int n = CustomData_get_active_layer(ldata, CD_MLOOPCOL); - if (n != -1) { - return ED_mesh_color_remove_index(me, n); - } - else { - return false; - } + CustomData *ldata = GET_CD_DATA(me, ldata); + const int n = CustomData_get_active_layer(ldata, CD_MLOOPCOL); + if (n != -1) { + return ED_mesh_color_remove_index(me, n); + } + else { + return false; + } } bool ED_mesh_color_remove_named(Mesh *me, const char *name) { - CustomData *ldata = GET_CD_DATA(me, ldata); - const int n = CustomData_get_named_layer(ldata, CD_MLOOPCOL, name); - if (n != -1) { - return ED_mesh_color_remove_index(me, n); - } - else { - return false; - } + CustomData *ldata = GET_CD_DATA(me, ldata); + const int n = CustomData_get_named_layer(ldata, CD_MLOOPCOL, name); + if (n != -1) { + return ED_mesh_color_remove_index(me, n); + } + else { + return false; + } } /*********************** UV texture operators ************************/ static bool layers_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED(data)); + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && !ID_IS_LINKED(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED(data)); } static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Object *ob = ED_object_context(C); + Mesh *me = ob->data; - if (ED_mesh_uv_texture_add(me, NULL, true, true) == -1) - return OPERATOR_CANCELLED; + if (ED_mesh_uv_texture_add(me, NULL, true, true) == -1) + return OPERATOR_CANCELLED; - if (ob->mode & OB_MODE_TEXTURE_PAINT) { - Scene *scene = CTX_data_scene(C); - BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); - } + if (ob->mode & OB_MODE_TEXTURE_PAINT) { + Scene *scene = CTX_data_scene(C); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_uv_texture_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add UV Map"; - ot->description = "Add UV Map"; - ot->idname = "MESH_OT_uv_texture_add"; + /* identifiers */ + ot->name = "Add UV Map"; + ot->description = "Add UV Map"; + ot->idname = "MESH_OT_uv_texture_add"; - /* api callbacks */ - ot->poll = layers_poll; - ot->exec = mesh_uv_texture_add_exec; + /* api callbacks */ + ot->poll = layers_poll; + ot->exec = mesh_uv_texture_add_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int mesh_uv_texture_remove_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Object *ob = ED_object_context(C); + Mesh *me = ob->data; - if (!ED_mesh_uv_texture_remove_active(me)) - return OPERATOR_CANCELLED; + if (!ED_mesh_uv_texture_remove_active(me)) + return OPERATOR_CANCELLED; - if (ob->mode & OB_MODE_TEXTURE_PAINT) { - Scene *scene = CTX_data_scene(C); - BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); - } + if (ob->mode & OB_MODE_TEXTURE_PAINT) { + Scene *scene = CTX_data_scene(C); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_uv_texture_remove(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove UV Map"; - ot->description = "Remove UV Map"; - ot->idname = "MESH_OT_uv_texture_remove"; + /* identifiers */ + ot->name = "Remove UV Map"; + ot->description = "Remove UV Map"; + ot->idname = "MESH_OT_uv_texture_remove"; - /* api callbacks */ - ot->poll = layers_poll; - ot->exec = mesh_uv_texture_remove_exec; + /* api callbacks */ + ot->poll = layers_poll; + ot->exec = mesh_uv_texture_remove_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /*********************** vertex color operators ************************/ static int mesh_vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Object *ob = ED_object_context(C); + Mesh *me = ob->data; - if (ED_mesh_color_add(me, NULL, true, true) == -1) - return OPERATOR_CANCELLED; + if (ED_mesh_color_add(me, NULL, true, true) == -1) + return OPERATOR_CANCELLED; - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_vertex_color_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Vertex Color"; - ot->description = "Add vertex color layer"; - ot->idname = "MESH_OT_vertex_color_add"; + /* identifiers */ + ot->name = "Add Vertex Color"; + ot->description = "Add vertex color layer"; + ot->idname = "MESH_OT_vertex_color_add"; - /* api callbacks */ - ot->poll = layers_poll; - ot->exec = mesh_vertex_color_add_exec; + /* api callbacks */ + ot->poll = layers_poll; + ot->exec = mesh_vertex_color_add_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int mesh_vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Object *ob = ED_object_context(C); + Mesh *me = ob->data; - if (!ED_mesh_color_remove_active(me)) - return OPERATOR_CANCELLED; + if (!ED_mesh_color_remove_active(me)) + return OPERATOR_CANCELLED; - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_vertex_color_remove(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Vertex Color"; - ot->description = "Remove vertex color layer"; - ot->idname = "MESH_OT_vertex_color_remove"; + /* identifiers */ + ot->name = "Remove Vertex Color"; + ot->description = "Remove vertex color layer"; + ot->idname = "MESH_OT_vertex_color_remove"; - /* api callbacks */ - ot->exec = mesh_vertex_color_remove_exec; - ot->poll = layers_poll; + /* api callbacks */ + ot->exec = mesh_vertex_color_remove_exec; + ot->poll = layers_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* *** CustomData clear functions, we need an operator for each *** */ -static int mesh_customdata_clear_exec__internal(bContext *C, - char htype, int type) +static int mesh_customdata_clear_exec__internal(bContext *C, char htype, int type) { - Object *obedit = ED_object_context(C); - Mesh *me = obedit->data; - - int tot; - CustomData *data = mesh_customdata_get_type(me, htype, &tot); - - BLI_assert(CustomData_layertype_is_singleton(type) == true); - - if (CustomData_has_layer(data, type)) { - if (me->edit_mesh) { - BM_data_layer_free(me->edit_mesh->bm, data, type); - } - else { - CustomData_free_layers(data, type, tot); - } - - DEG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + Object *obedit = ED_object_context(C); + Mesh *me = obedit->data; + + int tot; + CustomData *data = mesh_customdata_get_type(me, htype, &tot); + + BLI_assert(CustomData_layertype_is_singleton(type) == true); + + if (CustomData_has_layer(data, type)) { + if (me->edit_mesh) { + BM_data_layer_free(me->edit_mesh->bm, data, type); + } + else { + CustomData_free_layers(data, type, tot); + } + + DEG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } /* Clear Mask */ static bool mesh_customdata_mask_clear_poll(bContext *C) { - Object *ob = ED_object_context(C); - if (ob && ob->type == OB_MESH) { - Mesh *me = ob->data; - - /* special case - can't run this if we're in sculpt mode */ - if (ob->mode & OB_MODE_SCULPT) { - return false; - } - - if (!ID_IS_LINKED(me)) { - CustomData *data = GET_CD_DATA(me, vdata); - if (CustomData_has_layer(data, CD_PAINT_MASK)) { - return true; - } - data = GET_CD_DATA(me, ldata); - if (CustomData_has_layer(data, CD_GRID_PAINT_MASK)) { - return true; - } - } - } - return false; + Object *ob = ED_object_context(C); + if (ob && ob->type == OB_MESH) { + Mesh *me = ob->data; + + /* special case - can't run this if we're in sculpt mode */ + if (ob->mode & OB_MODE_SCULPT) { + return false; + } + + if (!ID_IS_LINKED(me)) { + CustomData *data = GET_CD_DATA(me, vdata); + if (CustomData_has_layer(data, CD_PAINT_MASK)) { + return true; + } + data = GET_CD_DATA(me, ldata); + if (CustomData_has_layer(data, CD_GRID_PAINT_MASK)) { + return true; + } + } + } + return false; } static int mesh_customdata_mask_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - int ret_a = mesh_customdata_clear_exec__internal(C, BM_VERT, CD_PAINT_MASK); - int ret_b = mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_GRID_PAINT_MASK); - - if (ret_a == OPERATOR_FINISHED || - ret_b == OPERATOR_FINISHED) - { - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + int ret_a = mesh_customdata_clear_exec__internal(C, BM_VERT, CD_PAINT_MASK); + int ret_b = mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_GRID_PAINT_MASK); + + if (ret_a == OPERATOR_FINISHED || ret_b == OPERATOR_FINISHED) { + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void MESH_OT_customdata_mask_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Sculpt-Mask Data"; - ot->idname = "MESH_OT_customdata_mask_clear"; - ot->description = "Clear vertex sculpt masking data from the mesh"; + /* identifiers */ + ot->name = "Clear Sculpt-Mask Data"; + ot->idname = "MESH_OT_customdata_mask_clear"; + ot->description = "Clear vertex sculpt masking data from the mesh"; - /* api callbacks */ - ot->exec = mesh_customdata_mask_clear_exec; - ot->poll = mesh_customdata_mask_clear_poll; + /* api callbacks */ + ot->exec = mesh_customdata_mask_clear_exec; + ot->poll = mesh_customdata_mask_clear_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** @@ -705,545 +705,554 @@ void MESH_OT_customdata_mask_clear(wmOperatorType *ot) */ static int mesh_customdata_skin_state(bContext *C) { - Object *ob = ED_object_context(C); - - if (ob && ob->type == OB_MESH) { - Mesh *me = ob->data; - if (!ID_IS_LINKED(me)) { - CustomData *data = GET_CD_DATA(me, vdata); - return CustomData_has_layer(data, CD_MVERT_SKIN); - } - } - return -1; + Object *ob = ED_object_context(C); + + if (ob && ob->type == OB_MESH) { + Mesh *me = ob->data; + if (!ID_IS_LINKED(me)) { + CustomData *data = GET_CD_DATA(me, vdata); + return CustomData_has_layer(data, CD_MVERT_SKIN); + } + } + return -1; } static bool mesh_customdata_skin_add_poll(bContext *C) { - return (mesh_customdata_skin_state(C) == 0); + return (mesh_customdata_skin_state(C) == 0); } static int mesh_customdata_skin_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Object *ob = ED_object_context(C); + Mesh *me = ob->data; - BKE_mesh_ensure_skin_customdata(me); + BKE_mesh_ensure_skin_customdata(me); - DEG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + DEG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void MESH_OT_customdata_skin_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Skin Data"; - ot->idname = "MESH_OT_customdata_skin_add"; - ot->description = "Add a vertex skin layer"; + /* identifiers */ + ot->name = "Add Skin Data"; + ot->idname = "MESH_OT_customdata_skin_add"; + ot->description = "Add a vertex skin layer"; - /* api callbacks */ - ot->exec = mesh_customdata_skin_add_exec; - ot->poll = mesh_customdata_skin_add_poll; + /* api callbacks */ + ot->exec = mesh_customdata_skin_add_exec; + ot->poll = mesh_customdata_skin_add_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static bool mesh_customdata_skin_clear_poll(bContext *C) { - return (mesh_customdata_skin_state(C) == 1); + return (mesh_customdata_skin_state(C) == 1); } static int mesh_customdata_skin_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - return mesh_customdata_clear_exec__internal(C, BM_VERT, CD_MVERT_SKIN); + return mesh_customdata_clear_exec__internal(C, BM_VERT, CD_MVERT_SKIN); } void MESH_OT_customdata_skin_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Skin Data"; - ot->idname = "MESH_OT_customdata_skin_clear"; - ot->description = "Clear vertex skin layer"; + /* identifiers */ + ot->name = "Clear Skin Data"; + ot->idname = "MESH_OT_customdata_skin_clear"; + ot->description = "Clear vertex skin layer"; - /* api callbacks */ - ot->exec = mesh_customdata_skin_clear_exec; - ot->poll = mesh_customdata_skin_clear_poll; + /* api callbacks */ + ot->exec = mesh_customdata_skin_clear_exec; + ot->poll = mesh_customdata_skin_clear_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* Clear custom loop normals */ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; - - if (!BKE_mesh_has_custom_loop_normals(me)) { - CustomData *data = GET_CD_DATA(me, ldata); - - if (me->edit_mesh) { - /* Tag edges as sharp according to smooth threshold if needed, to preserve autosmooth shading. */ - if (me->flag & ME_AUTOSMOOTH) { - BM_edges_sharp_from_angle_set(me->edit_mesh->bm, me->smoothresh); - } - - BM_data_layer_add(me->edit_mesh->bm, data, CD_CUSTOMLOOPNORMAL); - } - else { - /* Tag edges as sharp according to smooth threshold if needed, to preserve autosmooth shading. */ - if (me->flag & ME_AUTOSMOOTH) { - float (*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__); - - BKE_mesh_calc_normals_poly( - me->mvert, NULL, me->totvert, - me->mloop, me->mpoly, - me->totloop, me->totpoly, - polynors, true); - - BKE_edges_sharp_from_angle_set( - me->mvert, me->totvert, - me->medge, me->totedge, - me->mloop, me->totloop, - me->mpoly, polynors, me->totpoly, - me->smoothresh); - - MEM_freeN(polynors); - } - - CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop); - } - - DEG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; + Object *ob = ED_object_context(C); + Mesh *me = ob->data; + + if (!BKE_mesh_has_custom_loop_normals(me)) { + CustomData *data = GET_CD_DATA(me, ldata); + + if (me->edit_mesh) { + /* Tag edges as sharp according to smooth threshold if needed, to preserve autosmooth shading. */ + if (me->flag & ME_AUTOSMOOTH) { + BM_edges_sharp_from_angle_set(me->edit_mesh->bm, me->smoothresh); + } + + BM_data_layer_add(me->edit_mesh->bm, data, CD_CUSTOMLOOPNORMAL); + } + else { + /* Tag edges as sharp according to smooth threshold if needed, to preserve autosmooth shading. */ + if (me->flag & ME_AUTOSMOOTH) { + float(*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__); + + BKE_mesh_calc_normals_poly(me->mvert, + NULL, + me->totvert, + me->mloop, + me->mpoly, + me->totloop, + me->totpoly, + polynors, + true); + + BKE_edges_sharp_from_angle_set(me->mvert, + me->totvert, + me->medge, + me->totedge, + me->mloop, + me->totloop, + me->mpoly, + polynors, + me->totpoly, + me->smoothresh); + + MEM_freeN(polynors); + } + + CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop); + } + + DEG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + + return OPERATOR_FINISHED; + } + return OPERATOR_CANCELLED; } void MESH_OT_customdata_custom_splitnormals_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Custom Split Normals Data"; - ot->idname = "MESH_OT_customdata_custom_splitnormals_add"; - ot->description = "Add a custom split normals layer, if none exists yet"; + /* identifiers */ + ot->name = "Add Custom Split Normals Data"; + ot->idname = "MESH_OT_customdata_custom_splitnormals_add"; + ot->description = "Add a custom split normals layer, if none exists yet"; - /* api callbacks */ - ot->exec = mesh_customdata_custom_splitnormals_add_exec; - ot->poll = ED_operator_object_active_editable_mesh; + /* api callbacks */ + ot->exec = mesh_customdata_custom_splitnormals_add_exec; + ot->poll = ED_operator_object_active_editable_mesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int mesh_customdata_custom_splitnormals_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Object *ob = ED_object_context(C); + Mesh *me = ob->data; - if (BKE_mesh_has_custom_loop_normals(me)) { - return mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_CUSTOMLOOPNORMAL); - } - return OPERATOR_CANCELLED; + if (BKE_mesh_has_custom_loop_normals(me)) { + return mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_CUSTOMLOOPNORMAL); + } + return OPERATOR_CANCELLED; } void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Custom Split Normals Data"; - ot->idname = "MESH_OT_customdata_custom_splitnormals_clear"; - ot->description = "Remove the custom split normals layer, if it exists"; + /* identifiers */ + ot->name = "Clear Custom Split Normals Data"; + ot->idname = "MESH_OT_customdata_custom_splitnormals_clear"; + ot->description = "Remove the custom split normals layer, if it exists"; - /* api callbacks */ - ot->exec = mesh_customdata_custom_splitnormals_clear_exec; - ot->poll = ED_operator_object_active_editable_mesh; + /* api callbacks */ + ot->exec = mesh_customdata_custom_splitnormals_clear_exec; + ot->poll = ED_operator_object_active_editable_mesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /************************** 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 calc_tessface) { - bool tessface_input = false; + bool tessface_input = false; - if (mesh->totface > 0 && mesh->totpoly == 0) { - BKE_mesh_convert_mfaces_to_mpolys(mesh); + 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; - } + /* would only be converting back again, don't bother */ + tessface_input = true; + } - if (calc_edges_loose && mesh->totedge) { - BKE_mesh_calc_edges_loose(mesh); - } + if (calc_edges_loose && mesh->totedge) { + BKE_mesh_calc_edges_loose(mesh); + } - if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0)) - BKE_mesh_calc_edges(mesh, calc_edges, true); + if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0)) + 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); - } + 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); + } - BKE_mesh_calc_normals(mesh); + BKE_mesh_calc_normals(mesh); - DEG_id_tag_update(&mesh->id, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, mesh); + DEG_id_tag_update(&mesh->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, mesh); } static void mesh_add_verts(Mesh *mesh, int len) { - CustomData vdata; - MVert *mvert; - int i, totvert; + CustomData vdata; + MVert *mvert; + int i, totvert; - if (len == 0) - return; + if (len == 0) + return; - totvert = mesh->totvert + len; - CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert); - CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); + totvert = mesh->totvert + len; + CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert); + CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); - if (!CustomData_has_layer(&vdata, CD_MVERT)) - CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); + if (!CustomData_has_layer(&vdata, CD_MVERT)) + CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); - CustomData_free(&mesh->vdata, mesh->totvert); - mesh->vdata = vdata; - BKE_mesh_update_customdata_pointers(mesh, false); + CustomData_free(&mesh->vdata, mesh->totvert); + mesh->vdata = vdata; + BKE_mesh_update_customdata_pointers(mesh, false); - /* scan the input list and insert the new vertices */ + /* scan the input list and insert the new vertices */ - /* set default flags */ - mvert = &mesh->mvert[mesh->totvert]; - for (i = 0; i < len; i++, mvert++) - mvert->flag |= SELECT; + /* set default flags */ + mvert = &mesh->mvert[mesh->totvert]; + for (i = 0; i < len; i++, mvert++) + mvert->flag |= SELECT; - /* set final vertex list size */ - mesh->totvert = totvert; + /* set final vertex list size */ + mesh->totvert = totvert; } static void mesh_add_edges(Mesh *mesh, int len) { - CustomData edata; - MEdge *medge; - int i, totedge; + CustomData edata; + MEdge *medge; + int i, totedge; - if (len == 0) - return; + if (len == 0) + return; - totedge = mesh->totedge + len; + totedge = mesh->totedge + len; - /* update customdata */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); - CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); + /* update customdata */ + CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); + CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); - if (!CustomData_has_layer(&edata, CD_MEDGE)) - CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); + if (!CustomData_has_layer(&edata, CD_MEDGE)) + CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); - CustomData_free(&mesh->edata, mesh->totedge); - mesh->edata = edata; - BKE_mesh_update_customdata_pointers(mesh, false); /* new edges don't change tessellation */ + CustomData_free(&mesh->edata, mesh->totedge); + mesh->edata = edata; + BKE_mesh_update_customdata_pointers(mesh, false); /* new edges don't change tessellation */ - /* set default flags */ - medge = &mesh->medge[mesh->totedge]; - for (i = 0; i < len; i++, medge++) - medge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT; + /* set default flags */ + medge = &mesh->medge[mesh->totedge]; + for (i = 0; i < len; i++, medge++) + medge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT; - mesh->totedge = totedge; + mesh->totedge = totedge; } static void mesh_add_tessfaces(Mesh *mesh, int len) { - CustomData fdata; - MFace *mface; - int i, totface; + CustomData fdata; + MFace *mface; + int i, totface; - if (len == 0) - return; + if (len == 0) + return; - totface = mesh->totface + len; /* new face count */ + 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); + /* 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); + 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); + 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; + /* set default flags */ + mface = &mesh->mface[mesh->totface]; + for (i = 0; i < len; i++, mface++) + mface->flag = ME_FACE_SEL; - mesh->totface = totface; + mesh->totface = totface; } static void mesh_add_loops(Mesh *mesh, int len) { - CustomData ldata; - int totloop; + CustomData ldata; + int totloop; - if (len == 0) - return; + if (len == 0) + return; - totloop = mesh->totloop + len; /* new face count */ + totloop = mesh->totloop + len; /* new face count */ - /* update customdata */ - CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop); - CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); + /* update customdata */ + CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop); + CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); - if (!CustomData_has_layer(&ldata, CD_MLOOP)) - CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop); + if (!CustomData_has_layer(&ldata, CD_MLOOP)) + CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop); - CustomData_free(&mesh->ldata, mesh->totloop); - mesh->ldata = ldata; - BKE_mesh_update_customdata_pointers(mesh, true); + CustomData_free(&mesh->ldata, mesh->totloop); + mesh->ldata = ldata; + BKE_mesh_update_customdata_pointers(mesh, true); - mesh->totloop = totloop; + mesh->totloop = totloop; } static void mesh_add_polys(Mesh *mesh, int len) { - CustomData pdata; - MPoly *mpoly; - int i, totpoly; + CustomData pdata; + MPoly *mpoly; + int i, totpoly; - if (len == 0) - return; + if (len == 0) + return; - totpoly = mesh->totpoly + len; /* new face count */ + totpoly = mesh->totpoly + len; /* new face count */ - /* update customdata */ - CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly); - CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); + /* update customdata */ + CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly); + CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); - if (!CustomData_has_layer(&pdata, CD_MPOLY)) - CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly); + if (!CustomData_has_layer(&pdata, CD_MPOLY)) + CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly); - CustomData_free(&mesh->pdata, mesh->totpoly); - mesh->pdata = pdata; - BKE_mesh_update_customdata_pointers(mesh, true); + CustomData_free(&mesh->pdata, mesh->totpoly); + mesh->pdata = pdata; + BKE_mesh_update_customdata_pointers(mesh, true); - /* set default flags */ - mpoly = &mesh->mpoly[mesh->totpoly]; - for (i = 0; i < len; i++, mpoly++) - mpoly->flag = ME_FACE_SEL; + /* set default flags */ + mpoly = &mesh->mpoly[mesh->totpoly]; + for (i = 0; i < len; i++, mpoly++) + mpoly->flag = ME_FACE_SEL; - mesh->totpoly = totpoly; + mesh->totpoly = totpoly; } static void mesh_remove_verts(Mesh *mesh, int len) { - int totvert; + int totvert; - if (len == 0) - return; + if (len == 0) + return; - totvert = mesh->totvert - len; - CustomData_free_elem(&mesh->vdata, totvert, len); + totvert = mesh->totvert - len; + CustomData_free_elem(&mesh->vdata, totvert, len); - /* set final vertex list size */ - mesh->totvert = totvert; + /* set final vertex list size */ + mesh->totvert = totvert; } static void mesh_remove_edges(Mesh *mesh, int len) { - int totedge; + int totedge; - if (len == 0) - return; + if (len == 0) + return; - totedge = mesh->totedge - len; - CustomData_free_elem(&mesh->edata, totedge, len); + totedge = mesh->totedge - len; + CustomData_free_elem(&mesh->edata, totedge, len); - mesh->totedge = totedge; + mesh->totedge = totedge; } static void mesh_remove_faces(Mesh *mesh, int len) { - int totface; + int totface; - if (len == 0) - return; + if (len == 0) + return; - totface = mesh->totface - len; /* new face count */ - CustomData_free_elem(&mesh->fdata, totface, len); + totface = mesh->totface - len; /* new face count */ + CustomData_free_elem(&mesh->fdata, totface, len); - mesh->totface = totface; + mesh->totface = totface; } #if 0 void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces) { - if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add geometry in edit mode"); - return; - } - - if (verts) - mesh_add_verts(mesh, verts); - if (edges) - mesh_add_edges(mesh, edges); - if (faces) - mesh_add_faces(mesh, faces); + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot add geometry in edit mode"); + return; + } + + if (verts) + mesh_add_verts(mesh, verts); + if (edges) + mesh_add_edges(mesh, edges); + if (faces) + mesh_add_faces(mesh, faces); } #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->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; - } + if (mesh->mpoly) { + BKE_report(reports, RPT_ERROR, "Cannot add tessfaces to a mesh that already has polygons"); + return; + } - mesh_add_tessfaces(mesh, count); + mesh_add_tessfaces(mesh, count); } void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count) { - if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add edges in edit mode"); - return; - } + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot add edges in edit mode"); + return; + } - mesh_add_edges(mesh, count); + mesh_add_edges(mesh, count); } void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count) { - if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add vertices in edit mode"); - return; - } + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot add vertices in edit mode"); + return; + } - mesh_add_verts(mesh, 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); + 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) { - BKE_report(reports, RPT_ERROR, "Cannot remove edges in edit mode"); - return; - } - else if (count > mesh->totedge) { - BKE_report(reports, RPT_ERROR, "Cannot remove more edges than the mesh contains"); - return; - } - - mesh_remove_edges(mesh, count); + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot remove edges in edit mode"); + return; + } + else if (count > mesh->totedge) { + BKE_report(reports, RPT_ERROR, "Cannot remove more edges than the mesh contains"); + return; + } + + mesh_remove_edges(mesh, count); } void ED_mesh_vertices_remove(Mesh *mesh, ReportList *reports, int count) { - if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot remove vertices in edit mode"); - return; - } - else if (count > mesh->totvert) { - BKE_report(reports, RPT_ERROR, "Cannot remove more vertices than the mesh contains"); - return; - } - - mesh_remove_verts(mesh, count); + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot remove vertices in edit mode"); + return; + } + else if (count > mesh->totvert) { + BKE_report(reports, RPT_ERROR, "Cannot remove more vertices than the mesh contains"); + return; + } + + mesh_remove_verts(mesh, count); } void ED_mesh_loops_add(Mesh *mesh, ReportList *reports, int count) { - if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add loops in edit mode"); - return; - } + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot add loops in edit mode"); + return; + } - mesh_add_loops(mesh, count); + mesh_add_loops(mesh, count); } void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count) { - if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add polygons in edit mode"); - return; - } + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot add polygons in edit mode"); + return; + } - mesh_add_polys(mesh, 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; - } + 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) +void ED_mesh_report_mirror_ex(wmOperator *op, int totmirr, int totfail, char selectmode) { - const char *elem_type; - - if (selectmode & SCE_SELECT_VERTEX) { - elem_type = "vertices"; - } - else if (selectmode & SCE_SELECT_EDGE) { - elem_type = "edges"; - } - else { - elem_type = "faces"; - } - - if (totfail) { - BKE_reportf(op->reports, RPT_WARNING, "%d %s mirrored, %d failed", totmirr, elem_type, totfail); - } - else { - BKE_reportf(op->reports, RPT_INFO, "%d %s mirrored", totmirr, elem_type); - } + const char *elem_type; + + if (selectmode & SCE_SELECT_VERTEX) { + elem_type = "vertices"; + } + else if (selectmode & SCE_SELECT_EDGE) { + elem_type = "edges"; + } + else { + elem_type = "faces"; + } + + if (totfail) { + BKE_reportf( + op->reports, RPT_WARNING, "%d %s mirrored, %d failed", totmirr, elem_type, totfail); + } + else { + BKE_reportf(op->reports, RPT_INFO, "%d %s mirrored", totmirr, elem_type); + } } void ED_mesh_report_mirror(wmOperator *op, int totmirr, int totfail) { - ED_mesh_report_mirror_ex(op, totmirr, totfail, SCE_SELECT_VERTEX); + ED_mesh_report_mirror_ex(op, totmirr, totfail, SCE_SELECT_VERTEX); } diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 06499ace422..1a03879ed17 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -46,9 +46,12 @@ struct wmOperatorType; /* Calls a bmesh op, reporting errors to the user, etc */ bool EDBM_op_callf(struct BMEditMesh *em, struct wmOperator *op, const char *fmt, ...); -bool EDBM_op_call_and_selectf(struct BMEditMesh *em, struct wmOperator *op, - const char *select_slot, const bool select_replace, - const char *fmt, ...); +bool EDBM_op_call_and_selectf(struct BMEditMesh *em, + struct wmOperator *op, + const char *select_slot, + const bool select_replace, + const char *fmt, + ...); /* Same as above, but doesn't report errors.*/ bool EDBM_op_call_silentf(struct BMEditMesh *em, const char *fmt, ...); @@ -57,20 +60,23 @@ bool EDBM_op_call_silentf(struct BMEditMesh *em, const char *fmt, ...); * it. * * execute the operator with BM_Exec_Op */ -bool EDBM_op_init(struct BMEditMesh *em, struct BMOperator *bmop, - struct wmOperator *op, const char *fmt, ...); +bool EDBM_op_init( + struct BMEditMesh *em, struct BMOperator *bmop, struct wmOperator *op, const char *fmt, ...); /* Cleans up after a bmesh operator */ -bool EDBM_op_finish(struct BMEditMesh *em, struct BMOperator *bmop, - struct wmOperator *op, const bool do_report); +bool EDBM_op_finish(struct BMEditMesh *em, + struct BMOperator *bmop, + struct wmOperator *op, + const bool do_report); void EDBM_stats_update(struct BMEditMesh *em); bool EDBM_view3d_poll(struct bContext *C); -struct BMElem *EDBM_elem_from_selectmode( - struct BMEditMesh *em, - struct BMVert *eve, struct BMEdge *eed, struct BMFace *efa); -int EDBM_elem_to_index_any(struct BMEditMesh *em, struct BMElem *ele); +struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em, + struct BMVert *eve, + struct BMEdge *eed, + struct BMFace *efa); +int EDBM_elem_to_index_any(struct BMEditMesh *em, struct BMElem *ele); struct BMElem *EDBM_elem_from_index_any(struct BMEditMesh *em, int index); /* *** editmesh_add.c *** */ @@ -125,25 +131,20 @@ void MESH_OT_intersect(struct wmOperatorType *ot); void MESH_OT_intersect_boolean(struct wmOperatorType *ot); void MESH_OT_face_split_by_edges(struct wmOperatorType *ot); - /* *** editmesh_knife.c *** */ void MESH_OT_knife_tool(struct wmOperatorType *ot); void MESH_OT_knife_project(struct wmOperatorType *ot); -void EDBM_mesh_knife(struct bContext *C, struct LinkNode *polys, - bool use_tag, bool cut_through); +void EDBM_mesh_knife(struct bContext *C, struct LinkNode *polys, bool use_tag, bool cut_through); struct wmKeyMap *knifetool_modal_keymap(struct wmKeyConfig *keyconf); - /* *** editmesh_loopcut.c *** */ void MESH_OT_loopcut(struct wmOperatorType *ot); - /* *** editmesh_rip.c *** */ void MESH_OT_rip(struct wmOperatorType *ot); void MESH_OT_rip_edge(struct wmOperatorType *ot); - /* *** editmesh_select.c *** */ void MESH_OT_select_similar(struct wmOperatorType *ot); void MESH_OT_select_similar_region(struct wmOperatorType *ot); @@ -174,7 +175,6 @@ void MESH_OT_shortest_path_select(struct wmOperatorType *ot); extern struct EnumPropertyItem *corner_type_items; - /* *** editmesh_tools.c *** */ void MESH_OT_subdivide(struct wmOperatorType *ot); void MESH_OT_subdivide_edgering(struct wmOperatorType *ot); @@ -263,5 +263,4 @@ void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot); void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot); void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot); - -#endif /* __MESH_INTERN_H__ */ +#endif /* __MESH_INTERN_H__ */ diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c index 8bfe51d09fa..7d0ee19b5ea 100644 --- a/source/blender/editors/mesh/mesh_mirror.c +++ b/source/blender/editors/mesh/mesh_mirror.c @@ -38,74 +38,77 @@ /** \name Mesh Spatial Mirror API * \{ */ -#define KD_THRESH 0.00002f +#define KD_THRESH 0.00002f -static struct { void *tree; } MirrKdStore = {NULL}; +static struct { + void *tree; +} MirrKdStore = {NULL}; /* mode is 's' start, or 'e' end, or 'u' use */ /* if end, ob can be NULL */ -int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, Mesh *me_eval, const float co[3], char mode) +int ED_mesh_mirror_spatial_table( + Object *ob, BMEditMesh *em, Mesh *me_eval, const float co[3], char mode) { - if (mode == 'u') { /* use table */ - if (MirrKdStore.tree == NULL) - ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's'); - - if (MirrKdStore.tree) { - KDTreeNearest_3d nearest; - const int i = BLI_kdtree_3d_find_nearest(MirrKdStore.tree, co, &nearest); - - if (i != -1) { - if (nearest.dist < KD_THRESH) { - return i; - } - } - } - return -1; - } - else if (mode == 's') { /* start table */ - Mesh *me = ob->data; - const bool use_em = (!me_eval && em && me->edit_mesh == em); - const int totvert = use_em ? em->bm->totvert : me_eval ? me_eval->totvert : me->totvert; - - if (MirrKdStore.tree) /* happens when entering this call without ending it */ - ED_mesh_mirror_spatial_table(ob, em, me_eval, co, 'e'); - - MirrKdStore.tree = BLI_kdtree_3d_new(totvert); - - if (use_em) { - BMVert *eve; - BMIter iter; - int i; - - /* this needs to be valid for index lookups later (callers need) */ - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - - BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - BLI_kdtree_3d_insert(MirrKdStore.tree, i, eve->co); - } - } - else { - MVert *mvert = me_eval ? me_eval->mvert : me->mvert; - int i; - - for (i = 0; i < totvert; i++, mvert++) { - BLI_kdtree_3d_insert(MirrKdStore.tree, i, mvert->co); - } - } - - BLI_kdtree_3d_balance(MirrKdStore.tree); - } - else if (mode == 'e') { /* end table */ - if (MirrKdStore.tree) { - BLI_kdtree_3d_free(MirrKdStore.tree); - MirrKdStore.tree = NULL; - } - } - else { - BLI_assert(0); - } - - return 0; + if (mode == 'u') { /* use table */ + if (MirrKdStore.tree == NULL) + ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's'); + + if (MirrKdStore.tree) { + KDTreeNearest_3d nearest; + const int i = BLI_kdtree_3d_find_nearest(MirrKdStore.tree, co, &nearest); + + if (i != -1) { + if (nearest.dist < KD_THRESH) { + return i; + } + } + } + return -1; + } + else if (mode == 's') { /* start table */ + Mesh *me = ob->data; + const bool use_em = (!me_eval && em && me->edit_mesh == em); + const int totvert = use_em ? em->bm->totvert : me_eval ? me_eval->totvert : me->totvert; + + if (MirrKdStore.tree) /* happens when entering this call without ending it */ + ED_mesh_mirror_spatial_table(ob, em, me_eval, co, 'e'); + + MirrKdStore.tree = BLI_kdtree_3d_new(totvert); + + if (use_em) { + BMVert *eve; + BMIter iter; + int i; + + /* this needs to be valid for index lookups later (callers need) */ + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + BLI_kdtree_3d_insert(MirrKdStore.tree, i, eve->co); + } + } + else { + MVert *mvert = me_eval ? me_eval->mvert : me->mvert; + int i; + + for (i = 0; i < totvert; i++, mvert++) { + BLI_kdtree_3d_insert(MirrKdStore.tree, i, mvert->co); + } + } + + BLI_kdtree_3d_balance(MirrKdStore.tree); + } + else if (mode == 'e') { /* end table */ + if (MirrKdStore.tree) { + BLI_kdtree_3d_free(MirrKdStore.tree); + MirrKdStore.tree = NULL; + } + } + else { + BLI_assert(0); + } + + return 0; } /** \} */ @@ -117,256 +120,258 @@ int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, Mesh *me_eval, cons typedef unsigned int MirrTopoHash_t; typedef struct MirrTopoVert_t { - MirrTopoHash_t hash; - int v_index; + MirrTopoHash_t hash; + int v_index; } MirrTopoVert_t; static int mirrtopo_hash_sort(const void *l1, const void *l2) { - if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1; - else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1; - return 0; + if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) + return 1; + else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) + return -1; + return 0; } static int mirrtopo_vert_sort(const void *v1, const void *v2) { - if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1; - else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1; - return 0; + if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) + return 1; + else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) + return -1; + return 0; } bool ED_mesh_mirrtopo_recalc_check(Mesh *me, Mesh *me_eval, MirrTopoStore_t *mesh_topo_store) { - const bool is_editmode = (me->edit_mesh != NULL); - int totvert; - int totedge; - - if (me_eval) { - totvert = me_eval->totvert; - totedge = me_eval->totedge; - } - else if (me->edit_mesh) { - totvert = me->edit_mesh->bm->totvert; - totedge = me->edit_mesh->bm->totedge; - } - else { - totvert = me->totvert; - totedge = me->totedge; - } - - if ((mesh_topo_store->index_lookup == NULL) || - (mesh_topo_store->prev_is_editmode != is_editmode) || - (totvert != mesh_topo_store->prev_vert_tot) || - (totedge != mesh_topo_store->prev_edge_tot)) - { - return true; - } - else { - return false; - } - + const bool is_editmode = (me->edit_mesh != NULL); + int totvert; + int totedge; + + if (me_eval) { + totvert = me_eval->totvert; + totedge = me_eval->totedge; + } + else if (me->edit_mesh) { + totvert = me->edit_mesh->bm->totvert; + totedge = me->edit_mesh->bm->totedge; + } + else { + totvert = me->totvert; + totedge = me->totedge; + } + + if ((mesh_topo_store->index_lookup == NULL) || + (mesh_topo_store->prev_is_editmode != is_editmode) || + (totvert != mesh_topo_store->prev_vert_tot) || (totedge != mesh_topo_store->prev_edge_tot)) { + return true; + } + else { + return false; + } } -void ED_mesh_mirrtopo_init( - Mesh *me, Mesh *me_eval, MirrTopoStore_t *mesh_topo_store, - const bool skip_em_vert_array_init) +void ED_mesh_mirrtopo_init(Mesh *me, + Mesh *me_eval, + MirrTopoStore_t *mesh_topo_store, + const bool skip_em_vert_array_init) { - const bool is_editmode = (me->edit_mesh != NULL); - MEdge *medge = NULL, *med; - BMEditMesh *em = me_eval ? NULL : me->edit_mesh; - - /* editmode*/ - BMEdge *eed; - BMIter iter; - - int a, last; - int totvert, totedge; - int tot_unique = -1, tot_unique_prev = -1; - int tot_unique_edges = 0, tot_unique_edges_prev; - - MirrTopoHash_t *topo_hash = NULL; - MirrTopoHash_t *topo_hash_prev = NULL; - MirrTopoVert_t *topo_pairs; - MirrTopoHash_t topo_pass = 1; - - intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */ - - /* reallocate if needed */ - ED_mesh_mirrtopo_free(mesh_topo_store); - - mesh_topo_store->prev_is_editmode = is_editmode; - - if (em) { - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - totvert = em->bm->totvert; - } - else { - totvert = me_eval ? me_eval->totvert : me->totvert; - } - - topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); - - /* Initialize the vert-edge-user counts used to detect unique topology */ - if (em) { - totedge = me->edit_mesh->bm->totedge; - - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); - topo_hash[i1]++; - topo_hash[i2]++; - } - } - else { - totedge = me_eval ? me_eval->totedge : me->totedge; - medge = me_eval ? me_eval->medge : me->medge; - - for (a = 0, med = medge; a < totedge; a++, med++) { - const unsigned int i1 = med->v1, i2 = med->v2; - topo_hash[i1]++; - topo_hash[i2]++; - } - } - - topo_hash_prev = MEM_dupallocN(topo_hash); - - tot_unique_prev = -1; - tot_unique_edges_prev = -1; - while (1) { - /* use the number of edges per vert to give verts unique topology IDs */ - - tot_unique_edges = 0; - - /* This can make really big numbers, wrapping around here is fine */ - if (em) { - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); - topo_hash[i1] += topo_hash_prev[i2] * topo_pass; - topo_hash[i2] += topo_hash_prev[i1] * topo_pass; - tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); - } - } - else { - for (a = 0, med = medge; a < totedge; a++, med++) { - const unsigned int i1 = med->v1, i2 = med->v2; - topo_hash[i1] += topo_hash_prev[i2] * topo_pass; - topo_hash[i2] += topo_hash_prev[i1] * topo_pass; - tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); - } - } - memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); - - /* sort so we can count unique values */ - qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort); - - tot_unique = 1; /* account for skipping the first value */ - for (a = 1; a < totvert; a++) { - if (topo_hash_prev[a - 1] != topo_hash_prev[a]) { - tot_unique++; - } - } - - if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) { - /* Finish searching for unique values when 1 loop dosn't give a - * higher number of unique values compared to the previous loop. */ - break; - } - else { - tot_unique_prev = tot_unique; - tot_unique_edges_prev = tot_unique_edges; - } - /* Copy the hash calculated this iteration, so we can use them next time */ - memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); - - topo_pass++; - } - - /* Hash/Index pairs are needed for sorting to find index pairs */ - topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs"); - - /* since we are looping through verts, initialize these values here too */ - index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup"); - - if (em) { - if (skip_em_vert_array_init == false) { - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - } - } - - for (a = 0; a < totvert; a++) { - topo_pairs[a].hash = topo_hash[a]; - topo_pairs[a].v_index = a; - - /* initialize lookup */ - index_lookup[a] = -1; - } - - qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); - - last = 0; - - /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, - * but you cant ever access the last 'a' index of MirrTopoPairs */ - if (em) { - BMVert **vtable = em->bm->vtable; - for (a = 1; a <= totvert; a++) { - // printf("I %d %ld %d\n", - // (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - const int match_count = a - last; - if (match_count == 2) { - const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; - index_lookup[j] = (intptr_t)vtable[k]; - index_lookup[k] = (intptr_t)vtable[j]; - } - else if (match_count == 1) { - /* Center vertex. */ - const int j = topo_pairs[a - 1].v_index; - index_lookup[j] = (intptr_t)vtable[j]; - } - last = a; - } - } - } - else { - /* same as above, for mesh */ - for (a = 1; a <= totvert; a++) { - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - const int match_count = a - last; - if (match_count == 2) { - const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; - index_lookup[j] = k; - index_lookup[k] = j; - } - else if (match_count == 1) { - /* Center vertex. */ - const int j = topo_pairs[a - 1].v_index; - index_lookup[j] = j; - } - last = a; - } - } - } - - MEM_freeN(topo_pairs); - topo_pairs = NULL; - - MEM_freeN(topo_hash); - MEM_freeN(topo_hash_prev); - - mesh_topo_store->index_lookup = index_lookup; - mesh_topo_store->prev_vert_tot = totvert; - mesh_topo_store->prev_edge_tot = totedge; + const bool is_editmode = (me->edit_mesh != NULL); + MEdge *medge = NULL, *med; + BMEditMesh *em = me_eval ? NULL : me->edit_mesh; + + /* editmode*/ + BMEdge *eed; + BMIter iter; + + int a, last; + int totvert, totedge; + int tot_unique = -1, tot_unique_prev = -1; + int tot_unique_edges = 0, tot_unique_edges_prev; + + MirrTopoHash_t *topo_hash = NULL; + MirrTopoHash_t *topo_hash_prev = NULL; + MirrTopoVert_t *topo_pairs; + MirrTopoHash_t topo_pass = 1; + + intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */ + + /* reallocate if needed */ + ED_mesh_mirrtopo_free(mesh_topo_store); + + mesh_topo_store->prev_is_editmode = is_editmode; + + if (em) { + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + totvert = em->bm->totvert; + } + else { + totvert = me_eval ? me_eval->totvert : me->totvert; + } + + topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); + + /* Initialize the vert-edge-user counts used to detect unique topology */ + if (em) { + totedge = me->edit_mesh->bm->totedge; + + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1]++; + topo_hash[i2]++; + } + } + else { + totedge = me_eval ? me_eval->totedge : me->totedge; + medge = me_eval ? me_eval->medge : me->medge; + + for (a = 0, med = medge; a < totedge; a++, med++) { + const unsigned int i1 = med->v1, i2 = med->v2; + topo_hash[i1]++; + topo_hash[i2]++; + } + } + + topo_hash_prev = MEM_dupallocN(topo_hash); + + tot_unique_prev = -1; + tot_unique_edges_prev = -1; + while (1) { + /* use the number of edges per vert to give verts unique topology IDs */ + + tot_unique_edges = 0; + + /* This can make really big numbers, wrapping around here is fine */ + if (em) { + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); + } + } + else { + for (a = 0, med = medge; a < totedge; a++, med++) { + const unsigned int i1 = med->v1, i2 = med->v2; + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); + } + } + memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); + + /* sort so we can count unique values */ + qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort); + + tot_unique = 1; /* account for skipping the first value */ + for (a = 1; a < totvert; a++) { + if (topo_hash_prev[a - 1] != topo_hash_prev[a]) { + tot_unique++; + } + } + + if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) { + /* Finish searching for unique values when 1 loop dosn't give a + * higher number of unique values compared to the previous loop. */ + break; + } + else { + tot_unique_prev = tot_unique; + tot_unique_edges_prev = tot_unique_edges; + } + /* Copy the hash calculated this iteration, so we can use them next time */ + memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); + + topo_pass++; + } + + /* Hash/Index pairs are needed for sorting to find index pairs */ + topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs"); + + /* since we are looping through verts, initialize these values here too */ + index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup"); + + if (em) { + if (skip_em_vert_array_init == false) { + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + } + } + + for (a = 0; a < totvert; a++) { + topo_pairs[a].hash = topo_hash[a]; + topo_pairs[a].v_index = a; + + /* initialize lookup */ + index_lookup[a] = -1; + } + + qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); + + last = 0; + + /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, + * but you cant ever access the last 'a' index of MirrTopoPairs */ + if (em) { + BMVert **vtable = em->bm->vtable; + for (a = 1; a <= totvert; a++) { + // printf("I %d %ld %d\n", + // (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = (intptr_t)vtable[k]; + index_lookup[k] = (intptr_t)vtable[j]; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = (intptr_t)vtable[j]; + } + last = a; + } + } + } + else { + /* same as above, for mesh */ + for (a = 1; a <= totvert; a++) { + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = k; + index_lookup[k] = j; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = j; + } + last = a; + } + } + } + + MEM_freeN(topo_pairs); + topo_pairs = NULL; + + MEM_freeN(topo_hash); + MEM_freeN(topo_hash_prev); + + mesh_topo_store->index_lookup = index_lookup; + mesh_topo_store->prev_vert_tot = totvert; + mesh_topo_store->prev_edge_tot = totedge; } void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store) { - if (mesh_topo_store->index_lookup) { - MEM_freeN(mesh_topo_store->index_lookup); - } - mesh_topo_store->index_lookup = NULL; - mesh_topo_store->prev_vert_tot = -1; - mesh_topo_store->prev_edge_tot = -1; + if (mesh_topo_store->index_lookup) { + MEM_freeN(mesh_topo_store->index_lookup); + } + mesh_topo_store->index_lookup = NULL; + mesh_topo_store->prev_vert_tot = -1; + mesh_topo_store->prev_edge_tot = -1; } /** \} */ diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 46837889489..8a51b9ba54e 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -34,292 +34,315 @@ #include "ED_screen.h" #include "ED_select_utils.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ /**************************** registration **********************************/ void ED_operatortypes_mesh(void) { - WM_operatortype_append(MESH_OT_select_all); - WM_operatortype_append(MESH_OT_select_interior_faces); - WM_operatortype_append(MESH_OT_select_more); - WM_operatortype_append(MESH_OT_select_less); - WM_operatortype_append(MESH_OT_select_non_manifold); - WM_operatortype_append(MESH_OT_select_linked); - WM_operatortype_append(MESH_OT_select_linked_pick); - WM_operatortype_append(MESH_OT_select_random); - WM_operatortype_append(MESH_OT_select_ungrouped); - WM_operatortype_append(MESH_OT_hide); - WM_operatortype_append(MESH_OT_reveal); - WM_operatortype_append(MESH_OT_select_face_by_sides); - WM_operatortype_append(MESH_OT_select_loose); - WM_operatortype_append(MESH_OT_select_mirror); - WM_operatortype_append(MESH_OT_normals_make_consistent); - WM_operatortype_append(MESH_OT_merge); - WM_operatortype_append(MESH_OT_subdivide); - WM_operatortype_append(MESH_OT_subdivide_edgering); - WM_operatortype_append(MESH_OT_unsubdivide); - WM_operatortype_append(MESH_OT_faces_select_linked_flat); - WM_operatortype_append(MESH_OT_edges_select_sharp); - WM_operatortype_append(MESH_OT_primitive_plane_add); - WM_operatortype_append(MESH_OT_primitive_cube_add); - WM_operatortype_append(MESH_OT_primitive_circle_add); - WM_operatortype_append(MESH_OT_primitive_cylinder_add); - WM_operatortype_append(MESH_OT_primitive_cone_add); - WM_operatortype_append(MESH_OT_primitive_grid_add); - WM_operatortype_append(MESH_OT_primitive_monkey_add); - WM_operatortype_append(MESH_OT_primitive_uv_sphere_add); - WM_operatortype_append(MESH_OT_primitive_ico_sphere_add); - - WM_operatortype_append(MESH_OT_primitive_cube_add_gizmo); - - WM_operatortype_append(MESH_OT_duplicate); - WM_operatortype_append(MESH_OT_remove_doubles); - WM_operatortype_append(MESH_OT_spin); - WM_operatortype_append(MESH_OT_screw); - - WM_operatortype_append(MESH_OT_extrude_region); - WM_operatortype_append(MESH_OT_extrude_context); - WM_operatortype_append(MESH_OT_extrude_faces_indiv); - WM_operatortype_append(MESH_OT_extrude_edges_indiv); - WM_operatortype_append(MESH_OT_extrude_verts_indiv); - - WM_operatortype_append(MESH_OT_split); - WM_operatortype_append(MESH_OT_extrude_repeat); - WM_operatortype_append(MESH_OT_edge_rotate); - WM_operatortype_append(MESH_OT_shortest_path_select); - WM_operatortype_append(MESH_OT_loop_to_region); - WM_operatortype_append(MESH_OT_region_to_loop); - WM_operatortype_append(MESH_OT_select_axis); - - WM_operatortype_append(MESH_OT_uvs_rotate); - WM_operatortype_append(MESH_OT_uvs_reverse); - WM_operatortype_append(MESH_OT_colors_rotate); - WM_operatortype_append(MESH_OT_colors_reverse); - - WM_operatortype_append(MESH_OT_fill); - WM_operatortype_append(MESH_OT_fill_grid); - WM_operatortype_append(MESH_OT_fill_holes); - WM_operatortype_append(MESH_OT_beautify_fill); - WM_operatortype_append(MESH_OT_quads_convert_to_tris); - WM_operatortype_append(MESH_OT_tris_convert_to_quads); - WM_operatortype_append(MESH_OT_decimate); - WM_operatortype_append(MESH_OT_dissolve_verts); - WM_operatortype_append(MESH_OT_dissolve_edges); - WM_operatortype_append(MESH_OT_dissolve_faces); - WM_operatortype_append(MESH_OT_dissolve_mode); - WM_operatortype_append(MESH_OT_dissolve_limited); - WM_operatortype_append(MESH_OT_dissolve_degenerate); - WM_operatortype_append(MESH_OT_delete_edgeloop); - WM_operatortype_append(MESH_OT_faces_shade_smooth); - WM_operatortype_append(MESH_OT_faces_shade_flat); - WM_operatortype_append(MESH_OT_sort_elements); + WM_operatortype_append(MESH_OT_select_all); + WM_operatortype_append(MESH_OT_select_interior_faces); + WM_operatortype_append(MESH_OT_select_more); + WM_operatortype_append(MESH_OT_select_less); + WM_operatortype_append(MESH_OT_select_non_manifold); + WM_operatortype_append(MESH_OT_select_linked); + WM_operatortype_append(MESH_OT_select_linked_pick); + WM_operatortype_append(MESH_OT_select_random); + WM_operatortype_append(MESH_OT_select_ungrouped); + WM_operatortype_append(MESH_OT_hide); + WM_operatortype_append(MESH_OT_reveal); + WM_operatortype_append(MESH_OT_select_face_by_sides); + WM_operatortype_append(MESH_OT_select_loose); + WM_operatortype_append(MESH_OT_select_mirror); + WM_operatortype_append(MESH_OT_normals_make_consistent); + WM_operatortype_append(MESH_OT_merge); + WM_operatortype_append(MESH_OT_subdivide); + WM_operatortype_append(MESH_OT_subdivide_edgering); + WM_operatortype_append(MESH_OT_unsubdivide); + WM_operatortype_append(MESH_OT_faces_select_linked_flat); + WM_operatortype_append(MESH_OT_edges_select_sharp); + WM_operatortype_append(MESH_OT_primitive_plane_add); + WM_operatortype_append(MESH_OT_primitive_cube_add); + WM_operatortype_append(MESH_OT_primitive_circle_add); + WM_operatortype_append(MESH_OT_primitive_cylinder_add); + WM_operatortype_append(MESH_OT_primitive_cone_add); + WM_operatortype_append(MESH_OT_primitive_grid_add); + WM_operatortype_append(MESH_OT_primitive_monkey_add); + WM_operatortype_append(MESH_OT_primitive_uv_sphere_add); + WM_operatortype_append(MESH_OT_primitive_ico_sphere_add); + + WM_operatortype_append(MESH_OT_primitive_cube_add_gizmo); + + WM_operatortype_append(MESH_OT_duplicate); + WM_operatortype_append(MESH_OT_remove_doubles); + WM_operatortype_append(MESH_OT_spin); + WM_operatortype_append(MESH_OT_screw); + + WM_operatortype_append(MESH_OT_extrude_region); + WM_operatortype_append(MESH_OT_extrude_context); + WM_operatortype_append(MESH_OT_extrude_faces_indiv); + WM_operatortype_append(MESH_OT_extrude_edges_indiv); + WM_operatortype_append(MESH_OT_extrude_verts_indiv); + + WM_operatortype_append(MESH_OT_split); + WM_operatortype_append(MESH_OT_extrude_repeat); + WM_operatortype_append(MESH_OT_edge_rotate); + WM_operatortype_append(MESH_OT_shortest_path_select); + WM_operatortype_append(MESH_OT_loop_to_region); + WM_operatortype_append(MESH_OT_region_to_loop); + WM_operatortype_append(MESH_OT_select_axis); + + WM_operatortype_append(MESH_OT_uvs_rotate); + WM_operatortype_append(MESH_OT_uvs_reverse); + WM_operatortype_append(MESH_OT_colors_rotate); + WM_operatortype_append(MESH_OT_colors_reverse); + + WM_operatortype_append(MESH_OT_fill); + WM_operatortype_append(MESH_OT_fill_grid); + WM_operatortype_append(MESH_OT_fill_holes); + WM_operatortype_append(MESH_OT_beautify_fill); + WM_operatortype_append(MESH_OT_quads_convert_to_tris); + WM_operatortype_append(MESH_OT_tris_convert_to_quads); + WM_operatortype_append(MESH_OT_decimate); + WM_operatortype_append(MESH_OT_dissolve_verts); + WM_operatortype_append(MESH_OT_dissolve_edges); + WM_operatortype_append(MESH_OT_dissolve_faces); + WM_operatortype_append(MESH_OT_dissolve_mode); + WM_operatortype_append(MESH_OT_dissolve_limited); + WM_operatortype_append(MESH_OT_dissolve_degenerate); + WM_operatortype_append(MESH_OT_delete_edgeloop); + WM_operatortype_append(MESH_OT_faces_shade_smooth); + WM_operatortype_append(MESH_OT_faces_shade_flat); + WM_operatortype_append(MESH_OT_sort_elements); #ifdef WITH_FREESTYLE - WM_operatortype_append(MESH_OT_mark_freestyle_face); + WM_operatortype_append(MESH_OT_mark_freestyle_face); #endif - WM_operatortype_append(MESH_OT_delete); - WM_operatortype_append(MESH_OT_delete_loose); - WM_operatortype_append(MESH_OT_edge_collapse); - - WM_operatortype_append(MESH_OT_separate); - WM_operatortype_append(MESH_OT_dupli_extrude_cursor); - WM_operatortype_append(MESH_OT_loop_select); - WM_operatortype_append(MESH_OT_edge_face_add); - WM_operatortype_append(MESH_OT_shortest_path_pick); - WM_operatortype_append(MESH_OT_select_similar); - WM_operatortype_append(MESH_OT_select_similar_region); - WM_operatortype_append(MESH_OT_select_mode); - WM_operatortype_append(MESH_OT_loop_multi_select); - WM_operatortype_append(MESH_OT_mark_seam); - WM_operatortype_append(MESH_OT_mark_sharp); + WM_operatortype_append(MESH_OT_delete); + WM_operatortype_append(MESH_OT_delete_loose); + WM_operatortype_append(MESH_OT_edge_collapse); + + WM_operatortype_append(MESH_OT_separate); + WM_operatortype_append(MESH_OT_dupli_extrude_cursor); + WM_operatortype_append(MESH_OT_loop_select); + WM_operatortype_append(MESH_OT_edge_face_add); + WM_operatortype_append(MESH_OT_shortest_path_pick); + WM_operatortype_append(MESH_OT_select_similar); + WM_operatortype_append(MESH_OT_select_similar_region); + WM_operatortype_append(MESH_OT_select_mode); + WM_operatortype_append(MESH_OT_loop_multi_select); + WM_operatortype_append(MESH_OT_mark_seam); + WM_operatortype_append(MESH_OT_mark_sharp); #ifdef WITH_FREESTYLE - WM_operatortype_append(MESH_OT_mark_freestyle_edge); + WM_operatortype_append(MESH_OT_mark_freestyle_edge); #endif - WM_operatortype_append(MESH_OT_vertices_smooth); - WM_operatortype_append(MESH_OT_vertices_smooth_laplacian); - WM_operatortype_append(MESH_OT_flip_normals); - WM_operatortype_append(MESH_OT_rip); - WM_operatortype_append(MESH_OT_rip_edge); - WM_operatortype_append(MESH_OT_blend_from_shape); - WM_operatortype_append(MESH_OT_shape_propagate_to_all); - - /* editmesh_polybuild */ - 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_uv_texture_add); - WM_operatortype_append(MESH_OT_uv_texture_remove); - WM_operatortype_append(MESH_OT_vertex_color_add); - WM_operatortype_append(MESH_OT_vertex_color_remove); - WM_operatortype_append(MESH_OT_customdata_mask_clear); - WM_operatortype_append(MESH_OT_customdata_skin_add); - WM_operatortype_append(MESH_OT_customdata_skin_clear); - WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_add); - WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_clear); - - WM_operatortype_append(MESH_OT_edgering_select); - WM_operatortype_append(MESH_OT_loopcut); - - WM_operatortype_append(MESH_OT_solidify); - WM_operatortype_append(MESH_OT_select_nth); - WM_operatortype_append(MESH_OT_vert_connect); - WM_operatortype_append(MESH_OT_vert_connect_path); - WM_operatortype_append(MESH_OT_vert_connect_concave); - WM_operatortype_append(MESH_OT_vert_connect_nonplanar); - WM_operatortype_append(MESH_OT_face_make_planar); - WM_operatortype_append(MESH_OT_knife_tool); - WM_operatortype_append(MESH_OT_knife_project); - - WM_operatortype_append(MESH_OT_bevel); - - WM_operatortype_append(MESH_OT_bridge_edge_loops); - WM_operatortype_append(MESH_OT_inset); - WM_operatortype_append(MESH_OT_offset_edge_loops); - WM_operatortype_append(MESH_OT_intersect); - WM_operatortype_append(MESH_OT_intersect_boolean); - WM_operatortype_append(MESH_OT_face_split_by_edges); - WM_operatortype_append(MESH_OT_poke); - WM_operatortype_append(MESH_OT_wireframe); - WM_operatortype_append(MESH_OT_edge_split); + WM_operatortype_append(MESH_OT_vertices_smooth); + WM_operatortype_append(MESH_OT_vertices_smooth_laplacian); + WM_operatortype_append(MESH_OT_flip_normals); + WM_operatortype_append(MESH_OT_rip); + WM_operatortype_append(MESH_OT_rip_edge); + WM_operatortype_append(MESH_OT_blend_from_shape); + WM_operatortype_append(MESH_OT_shape_propagate_to_all); + + /* editmesh_polybuild */ + 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_uv_texture_add); + WM_operatortype_append(MESH_OT_uv_texture_remove); + WM_operatortype_append(MESH_OT_vertex_color_add); + WM_operatortype_append(MESH_OT_vertex_color_remove); + WM_operatortype_append(MESH_OT_customdata_mask_clear); + WM_operatortype_append(MESH_OT_customdata_skin_add); + WM_operatortype_append(MESH_OT_customdata_skin_clear); + WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_add); + WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_clear); + + WM_operatortype_append(MESH_OT_edgering_select); + WM_operatortype_append(MESH_OT_loopcut); + + WM_operatortype_append(MESH_OT_solidify); + WM_operatortype_append(MESH_OT_select_nth); + WM_operatortype_append(MESH_OT_vert_connect); + WM_operatortype_append(MESH_OT_vert_connect_path); + WM_operatortype_append(MESH_OT_vert_connect_concave); + WM_operatortype_append(MESH_OT_vert_connect_nonplanar); + WM_operatortype_append(MESH_OT_face_make_planar); + WM_operatortype_append(MESH_OT_knife_tool); + WM_operatortype_append(MESH_OT_knife_project); + + WM_operatortype_append(MESH_OT_bevel); + + WM_operatortype_append(MESH_OT_bridge_edge_loops); + WM_operatortype_append(MESH_OT_inset); + WM_operatortype_append(MESH_OT_offset_edge_loops); + WM_operatortype_append(MESH_OT_intersect); + WM_operatortype_append(MESH_OT_intersect_boolean); + WM_operatortype_append(MESH_OT_face_split_by_edges); + WM_operatortype_append(MESH_OT_poke); + WM_operatortype_append(MESH_OT_wireframe); + WM_operatortype_append(MESH_OT_edge_split); #ifdef WITH_BULLET - WM_operatortype_append(MESH_OT_convex_hull); + WM_operatortype_append(MESH_OT_convex_hull); #endif - WM_operatortype_append(MESH_OT_bisect); - WM_operatortype_append(MESH_OT_symmetrize); - WM_operatortype_append(MESH_OT_symmetry_snap); - - WM_operatortype_append(MESH_OT_point_normals); - WM_operatortype_append(MESH_OT_merge_normals); - WM_operatortype_append(MESH_OT_split_normals); - WM_operatortype_append(MESH_OT_normals_tools); - WM_operatortype_append(MESH_OT_set_normals_from_faces); - WM_operatortype_append(MESH_OT_average_normals); - WM_operatortype_append(MESH_OT_smoothen_normals); - WM_operatortype_append(MESH_OT_mod_weighted_strength); + WM_operatortype_append(MESH_OT_bisect); + WM_operatortype_append(MESH_OT_symmetrize); + WM_operatortype_append(MESH_OT_symmetry_snap); + + WM_operatortype_append(MESH_OT_point_normals); + WM_operatortype_append(MESH_OT_merge_normals); + WM_operatortype_append(MESH_OT_split_normals); + WM_operatortype_append(MESH_OT_normals_tools); + WM_operatortype_append(MESH_OT_set_normals_from_faces); + WM_operatortype_append(MESH_OT_average_normals); + WM_operatortype_append(MESH_OT_smoothen_normals); + WM_operatortype_append(MESH_OT_mod_weighted_strength); } #if 0 /* UNUSED, remove? */ static int ED_operator_editmesh_face_select(bContext *C) { - Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_MESH) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em && em->selectmode & SCE_SELECT_FACE) { - return 1; - } - } - return 0; + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em && em->selectmode & SCE_SELECT_FACE) { + return 1; + } + } + return 0; } #endif void ED_operatormacros_mesh(void) { - wmOperatorType *ot; - wmOperatorTypeMacro *otmacro; - - ot = WM_operatortype_append_macro("MESH_OT_loopcut_slide", "Loop Cut and Slide", "Cut mesh loop and slide it", - OPTYPE_UNDO | OPTYPE_REGISTER); - WM_operatortype_macro_define(ot, "MESH_OT_loopcut"); - WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide"); - - ot = WM_operatortype_append_macro("MESH_OT_offset_edge_loops_slide", "Offset Edge Slide", "Offset edge loop slide", - OPTYPE_UNDO | OPTYPE_REGISTER); - WM_operatortype_macro_define(ot, "MESH_OT_offset_edge_loops"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide"); - RNA_boolean_set(otmacro->ptr, "single_side", true); - - ot = WM_operatortype_append_macro("MESH_OT_duplicate_move", "Add Duplicate", "Duplicate mesh and move", - OPTYPE_UNDO | OPTYPE_REGISTER); - WM_operatortype_macro_define(ot, "MESH_OT_duplicate"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - ot = WM_operatortype_append_macro("MESH_OT_rip_move", "Rip", "Rip polygons and move the result", - OPTYPE_UNDO | OPTYPE_REGISTER); - otmacro = WM_operatortype_macro_define(ot, "MESH_OT_rip"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - ot = WM_operatortype_append_macro("MESH_OT_rip_edge_move", "Extend Vertices", "Extend vertices and move the result", - OPTYPE_UNDO | OPTYPE_REGISTER); - WM_operatortype_macro_define(ot, "MESH_OT_rip_edge"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - ot = WM_operatortype_append_macro("MESH_OT_extrude_region_move", "Extrude Region and Move", - "Extrude region and move result", OPTYPE_UNDO | OPTYPE_REGISTER); - otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - ot = WM_operatortype_append_macro("MESH_OT_extrude_context_move", "Extrude Region and Move", - "Extrude context and move result", OPTYPE_UNDO | OPTYPE_REGISTER); - otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_context"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - ot = WM_operatortype_append_macro("MESH_OT_extrude_region_shrink_fatten", "Extrude Region and Shrink/Fatten", - "Extrude along normals and move result", OPTYPE_UNDO | OPTYPE_REGISTER); - otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - ot = WM_operatortype_append_macro("MESH_OT_extrude_faces_move", "Extrude Individual Faces and Move", - "Extrude faces and move result", OPTYPE_UNDO | OPTYPE_REGISTER); - otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_faces_indiv"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - ot = WM_operatortype_append_macro("MESH_OT_extrude_edges_move", "Extrude Only Edges and Move", - "Extrude edges and move result", OPTYPE_UNDO | OPTYPE_REGISTER); - otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - ot = WM_operatortype_append_macro("MESH_OT_extrude_vertices_move", "Extrude Only Vertices and Move", - "Extrude vertices and move result", OPTYPE_UNDO | OPTYPE_REGISTER); - otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_verts_indiv"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - - ot = WM_operatortype_append_macro( - "MESH_OT_polybuild_face_at_cursor_move", "Face at Cursor Move", "", - OPTYPE_UNDO | OPTYPE_REGISTER); - WM_operatortype_macro_define(ot, "MESH_OT_polybuild_face_at_cursor"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); - - ot = WM_operatortype_append_macro( - "MESH_OT_polybuild_split_at_cursor_move", "Split at Cursor Move", "", - OPTYPE_UNDO | OPTYPE_REGISTER); - WM_operatortype_macro_define(ot, "MESH_OT_polybuild_split_at_cursor"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", 0); - RNA_boolean_set(otmacro->ptr, "mirror", false); + wmOperatorType *ot; + wmOperatorTypeMacro *otmacro; + + ot = WM_operatortype_append_macro("MESH_OT_loopcut_slide", + "Loop Cut and Slide", + "Cut mesh loop and slide it", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MESH_OT_loopcut"); + WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide"); + + ot = WM_operatortype_append_macro("MESH_OT_offset_edge_loops_slide", + "Offset Edge Slide", + "Offset edge loop slide", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MESH_OT_offset_edge_loops"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide"); + RNA_boolean_set(otmacro->ptr, "single_side", true); + + ot = WM_operatortype_append_macro("MESH_OT_duplicate_move", + "Add Duplicate", + "Duplicate mesh and move", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MESH_OT_duplicate"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_rip_move", + "Rip", + "Rip polygons and move the result", + OPTYPE_UNDO | OPTYPE_REGISTER); + otmacro = WM_operatortype_macro_define(ot, "MESH_OT_rip"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_rip_edge_move", + "Extend Vertices", + "Extend vertices and move the result", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MESH_OT_rip_edge"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_extrude_region_move", + "Extrude Region and Move", + "Extrude region and move result", + OPTYPE_UNDO | OPTYPE_REGISTER); + otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_extrude_context_move", + "Extrude Region and Move", + "Extrude context and move result", + OPTYPE_UNDO | OPTYPE_REGISTER); + otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_context"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_extrude_region_shrink_fatten", + "Extrude Region and Shrink/Fatten", + "Extrude along normals and move result", + OPTYPE_UNDO | OPTYPE_REGISTER); + otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_extrude_faces_move", + "Extrude Individual Faces and Move", + "Extrude faces and move result", + OPTYPE_UNDO | OPTYPE_REGISTER); + otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_faces_indiv"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_extrude_edges_move", + "Extrude Only Edges and Move", + "Extrude edges and move result", + OPTYPE_UNDO | OPTYPE_REGISTER); + otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_extrude_vertices_move", + "Extrude Only Vertices and Move", + "Extrude vertices and move result", + OPTYPE_UNDO | OPTYPE_REGISTER); + otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_verts_indiv"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_polybuild_face_at_cursor_move", + "Face at Cursor Move", + "", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MESH_OT_polybuild_face_at_cursor"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); + + ot = WM_operatortype_append_macro("MESH_OT_polybuild_split_at_cursor_move", + "Split at Cursor Move", + "", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MESH_OT_polybuild_split_at_cursor"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", false); } /* note mesh keymap also for other space? */ void ED_keymap_mesh(wmKeyConfig *keyconf) { - wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Mesh", 0, 0); - keymap->poll = ED_operator_editmesh; + wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Mesh", 0, 0); + keymap->poll = ED_operator_editmesh; - knifetool_modal_keymap(keyconf); - point_normals_modal_keymap(keyconf); - bevel_modal_keymap(keyconf); + knifetool_modal_keymap(keyconf); + point_normals_modal_keymap(keyconf); + bevel_modal_keymap(keyconf); } diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 5339c83d158..ce7908bf0a3 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -74,529 +74,584 @@ /* join selected meshes into the active mesh, context sensitive * return 0 if no join is made (error) and 1 if the join is done */ -static void join_mesh_single( - Depsgraph *depsgraph, Main *bmain, Scene *scene, - Object *ob_dst, Object *ob_src, float imat[4][4], - MVert **mvert_pp, MEdge **medge_pp, MLoop **mloop_pp, MPoly **mpoly_pp, - CustomData *vdata, CustomData *edata, CustomData *ldata, CustomData *pdata, - int totvert, int totedge, int totloop, int totpoly, - Key *key, Key *nkey, - Material **matar, int *matmap, int totcol, - int *vertofs, int *edgeofs, int *loopofs, int *polyofs) +static void join_mesh_single(Depsgraph *depsgraph, + Main *bmain, + Scene *scene, + Object *ob_dst, + Object *ob_src, + float imat[4][4], + MVert **mvert_pp, + MEdge **medge_pp, + MLoop **mloop_pp, + MPoly **mpoly_pp, + CustomData *vdata, + CustomData *edata, + CustomData *ldata, + CustomData *pdata, + int totvert, + int totedge, + int totloop, + int totpoly, + Key *key, + Key *nkey, + Material **matar, + int *matmap, + int totcol, + int *vertofs, + int *edgeofs, + int *loopofs, + int *polyofs) { - int a, b; - - Mesh *me = ob_src->data; - MVert *mvert = *mvert_pp; - MEdge *medge = *medge_pp; - MLoop *mloop = *mloop_pp; - MPoly *mpoly = *mpoly_pp; - - if (me->totvert) { - /* merge customdata flag */ - ((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag; - - /* standard data */ - CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert); - CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert); - - /* vertex groups */ - MDeformVert *dvert = CustomData_get(vdata, *vertofs, CD_MDEFORMVERT); - MDeformVert *dvert_src = CustomData_get(&me->vdata, 0, CD_MDEFORMVERT); - - /* Remap to correct new vgroup indices, if needed. */ - if (dvert_src) { - BLI_assert(dvert != NULL); - - /* Build src to merged mapping of vgroup indices. */ - int *vgroup_index_map; - int vgroup_index_map_len; - vgroup_index_map = BKE_object_defgroup_index_map_create(ob_src, ob_dst, &vgroup_index_map_len); - BKE_object_defgroup_index_map_apply(dvert, me->totvert, vgroup_index_map, vgroup_index_map_len); - if (vgroup_index_map != NULL) { - MEM_freeN(vgroup_index_map); - } - } - - /* if this is the object we're merging into, no need to do anything */ - if (ob_src != ob_dst) { - float cmat[4][4]; - - /* watch this: switch matmul order really goes wrong */ - mul_m4_m4m4(cmat, imat, ob_src->obmat); - - /* transform vertex coordinates into new space */ - for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, mvert++) { - mul_m4_v3(cmat, mvert->co); - } - - /* for each shapekey in destination mesh: - * - if there's a matching one, copy it across (will need to transform vertices into new space...) - * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space) - */ - if (key) { - /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */ - for (KeyBlock *kb = key->block.first; kb; kb = kb->next) { - /* get pointer to where to write data for this mesh in shapekey's data array */ - float (*cos)[3] = ((float (*)[3])kb->data) + *vertofs; - - /* check if this mesh has such a shapekey */ - KeyBlock *okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL; - if (okb) { - /* copy this mesh's shapekey to the destination shapekey - * (need to transform first) */ - float (*ocos)[3] = okb->data; - for (a = 0; a < me->totvert; a++, cos++, ocos++) { - copy_v3_v3(*cos, *ocos); - mul_m4_v3(cmat, *cos); - } - } - else { - /* copy this mesh's vertex coordinates to the destination shapekey */ - for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) { - copy_v3_v3(*cos, mvert->co); - } - } - } - } - } - else { - /* for each shapekey in destination mesh: - * - if it was an 'original', copy the appropriate data from nkey - * - otherwise, copy across plain coordinates (no need to transform coordinates) - */ - if (key) { - for (KeyBlock *kb = key->block.first; kb; kb = kb->next) { - /* get pointer to where to write data for this mesh in shapekey's data array */ - float (*cos)[3] = ((float (*)[3])kb->data) + *vertofs; - - /* check if this was one of the original shapekeys */ - KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL; - if (okb) { - /* copy this mesh's shapekey to the destination shapekey */ - float (*ocos)[3] = okb->data; - for (a = 0; a < me->totvert; a++, cos++, ocos++) { - copy_v3_v3(*cos, *ocos); - } - } - else { - /* copy base-coordinates to the destination shapekey */ - for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) { - copy_v3_v3(*cos, mvert->co); - } - } - } - } - } - } - - if (me->totedge) { - CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); - CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge); - - for (a = 0; a < me->totedge; a++, medge++) { - medge->v1 += *vertofs; - medge->v2 += *vertofs; - } - } - - if (me->totloop) { - if (ob_src != ob_dst) { - MultiresModifierData *mmd; - - multiresModifier_prepare_join(depsgraph, scene, ob_src, ob_dst); - - if ((mmd = get_multires_modifier(scene, ob_src, true))) { - ED_object_iter_other(bmain, ob_src, true, - ED_object_multires_update_totlevels_cb, - &mmd->totlvl); - } - } - - CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop); - CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop); - - for (a = 0; a < me->totloop; a++, mloop++) { - mloop->v += *vertofs; - mloop->e += *edgeofs; - } - } - - if (me->totpoly) { - if (matmap) { - /* make mapping for materials */ - for (a = 1; a <= ob_src->totcol; a++) { - Material *ma = give_current_material(ob_src, a); - - for (b = 0; b < totcol; b++) { - if (ma == matar[b]) { - matmap[a - 1] = b; - break; - } - } - } - } - - CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly); - CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly); - - for (a = 0; a < me->totpoly; a++, mpoly++) { - mpoly->loopstart += *loopofs; - mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0; - } - } - - /* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */ - *vertofs += me->totvert; - *mvert_pp += me->totvert; - *edgeofs += me->totedge; - *medge_pp += me->totedge; - *loopofs += me->totloop; - *mloop_pp += me->totloop; - *polyofs += me->totpoly; - *mpoly_pp += me->totpoly; + int a, b; + + Mesh *me = ob_src->data; + MVert *mvert = *mvert_pp; + MEdge *medge = *medge_pp; + MLoop *mloop = *mloop_pp; + MPoly *mpoly = *mpoly_pp; + + if (me->totvert) { + /* merge customdata flag */ + ((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag; + + /* standard data */ + CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert); + CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert); + + /* vertex groups */ + MDeformVert *dvert = CustomData_get(vdata, *vertofs, CD_MDEFORMVERT); + MDeformVert *dvert_src = CustomData_get(&me->vdata, 0, CD_MDEFORMVERT); + + /* Remap to correct new vgroup indices, if needed. */ + if (dvert_src) { + BLI_assert(dvert != NULL); + + /* Build src to merged mapping of vgroup indices. */ + int *vgroup_index_map; + int vgroup_index_map_len; + vgroup_index_map = BKE_object_defgroup_index_map_create( + ob_src, ob_dst, &vgroup_index_map_len); + BKE_object_defgroup_index_map_apply( + dvert, me->totvert, vgroup_index_map, vgroup_index_map_len); + if (vgroup_index_map != NULL) { + MEM_freeN(vgroup_index_map); + } + } + + /* if this is the object we're merging into, no need to do anything */ + if (ob_src != ob_dst) { + float cmat[4][4]; + + /* watch this: switch matmul order really goes wrong */ + mul_m4_m4m4(cmat, imat, ob_src->obmat); + + /* transform vertex coordinates into new space */ + for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, mvert++) { + mul_m4_v3(cmat, mvert->co); + } + + /* for each shapekey in destination mesh: + * - if there's a matching one, copy it across (will need to transform vertices into new space...) + * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space) + */ + if (key) { + /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */ + for (KeyBlock *kb = key->block.first; kb; kb = kb->next) { + /* get pointer to where to write data for this mesh in shapekey's data array */ + float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs; + + /* check if this mesh has such a shapekey */ + KeyBlock *okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL; + if (okb) { + /* copy this mesh's shapekey to the destination shapekey + * (need to transform first) */ + float(*ocos)[3] = okb->data; + for (a = 0; a < me->totvert; a++, cos++, ocos++) { + copy_v3_v3(*cos, *ocos); + mul_m4_v3(cmat, *cos); + } + } + else { + /* copy this mesh's vertex coordinates to the destination shapekey */ + for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) { + copy_v3_v3(*cos, mvert->co); + } + } + } + } + } + else { + /* for each shapekey in destination mesh: + * - if it was an 'original', copy the appropriate data from nkey + * - otherwise, copy across plain coordinates (no need to transform coordinates) + */ + if (key) { + for (KeyBlock *kb = key->block.first; kb; kb = kb->next) { + /* get pointer to where to write data for this mesh in shapekey's data array */ + float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs; + + /* check if this was one of the original shapekeys */ + KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL; + if (okb) { + /* copy this mesh's shapekey to the destination shapekey */ + float(*ocos)[3] = okb->data; + for (a = 0; a < me->totvert; a++, cos++, ocos++) { + copy_v3_v3(*cos, *ocos); + } + } + else { + /* copy base-coordinates to the destination shapekey */ + for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) { + copy_v3_v3(*cos, mvert->co); + } + } + } + } + } + } + + if (me->totedge) { + CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); + CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge); + + for (a = 0; a < me->totedge; a++, medge++) { + medge->v1 += *vertofs; + medge->v2 += *vertofs; + } + } + + if (me->totloop) { + if (ob_src != ob_dst) { + MultiresModifierData *mmd; + + multiresModifier_prepare_join(depsgraph, scene, ob_src, ob_dst); + + if ((mmd = get_multires_modifier(scene, ob_src, true))) { + ED_object_iter_other( + bmain, ob_src, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl); + } + } + + CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop); + CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop); + + for (a = 0; a < me->totloop; a++, mloop++) { + mloop->v += *vertofs; + mloop->e += *edgeofs; + } + } + + if (me->totpoly) { + if (matmap) { + /* make mapping for materials */ + for (a = 1; a <= ob_src->totcol; a++) { + Material *ma = give_current_material(ob_src, a); + + for (b = 0; b < totcol; b++) { + if (ma == matar[b]) { + matmap[a - 1] = b; + break; + } + } + } + } + + CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly); + CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly); + + for (a = 0; a < me->totpoly; a++, mpoly++) { + mpoly->loopstart += *loopofs; + mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0; + } + } + + /* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */ + *vertofs += me->totvert; + *mvert_pp += me->totvert; + *edgeofs += me->totedge; + *medge_pp += me->totedge; + *loopofs += me->totloop; + *mloop_pp += me->totloop; + *polyofs += me->totpoly; + *mpoly_pp += me->totpoly; } int join_mesh_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - Material **matar = NULL, *ma; - Mesh *me; - MVert *mvert = NULL; - MEdge *medge = NULL; - MPoly *mpoly = NULL; - MLoop *mloop = NULL; - Key *key, *nkey = NULL; - KeyBlock *kb, *kbn; - float imat[4][4]; - int a, b, totcol, totmat = 0, totedge = 0, totvert = 0; - int totloop = 0, totpoly = 0, vertofs, *matmap = NULL; - int i, haskey = 0, edgeofs, loopofs, polyofs; - bool ok = false; - bDeformGroup *dg, *odg; - CustomData vdata, edata, fdata, ldata, pdata; - - if (ob->mode & OB_MODE_EDIT) { - BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode"); - return OPERATOR_CANCELLED; - } - - /* ob is the object we are adding geometry to */ - if (!ob || ob->type != OB_MESH) { - BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh"); - return OPERATOR_CANCELLED; - } - - Depsgraph *depsgraph = CTX_data_depsgraph(C); - - /* count & check */ - CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) - { - if (ob_iter->type == OB_MESH) { - me = ob_iter->data; - - totvert += me->totvert; - totedge += me->totedge; - totloop += me->totloop; - totpoly += me->totpoly; - totmat += ob_iter->totcol; - - if (ob_iter == ob) - ok = true; - - /* check for shapekeys */ - if (me->key) - haskey++; - } - } - CTX_DATA_END; - - /* that way the active object is always selected */ - if (ok == false) { - BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh"); - return OPERATOR_CANCELLED; - } - - /* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */ - me = (Mesh *)ob->data; - key = me->key; - - if (totvert == 0 || totvert == me->totvert) { - BKE_report(op->reports, RPT_WARNING, "No mesh data to join"); - return OPERATOR_CANCELLED; - } - - if (totvert > MESH_MAX_VERTS) { - BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is %ld", totvert, MESH_MAX_VERTS); - return OPERATOR_CANCELLED; - } - - /* remove tessface to ensure we don't hold references to invalid faces */ - BKE_mesh_tessface_clear(me); - - /* new material indices and material array */ - if (totmat) { - matar = MEM_callocN(sizeof(*matar) * totmat, "join_mesh matar"); - matmap = MEM_callocN(sizeof(*matmap) * totmat, "join_mesh matmap"); - } - totcol = ob->totcol; - - /* obact materials in new main array, is nicer start! */ - for (a = 0; a < ob->totcol; a++) { - matar[a] = give_current_material(ob, a + 1); - id_us_plus((ID *)matar[a]); - /* increase id->us : will be lowered later */ - } - - /* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders - * with arrays that are large enough to hold shapekey data for all meshes - * - if destination mesh didn't have shapekeys, but we encountered some in the meshes we're - * joining, set up a new keyblock and assign to the mesh - */ - if (key) { - /* make a duplicate copy that will only be used here... (must remember to free it!) */ - nkey = BKE_key_copy(bmain, key); - - /* for all keys in old block, clear data-arrays */ - for (kb = key->block.first; kb; kb = kb->next) { - if (kb->data) MEM_freeN(kb->data); - kb->data = MEM_callocN(sizeof(float) * 3 * totvert, "join_shapekey"); - kb->totelem = totvert; - } - } - else if (haskey) { - /* add a new key-block and add to the mesh */ - key = me->key = BKE_key_add(bmain, (ID *)me); - key->type = KEY_RELATIVE; - } - - /* first pass over objects - copying materials and vertexgroups across */ - CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) - { - /* only act if a mesh, and not the one we're joining to */ - if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) { - me = ob_iter->data; - - /* Join this object's vertex groups to the base one's */ - for (dg = ob_iter->defbase.first; dg; dg = dg->next) { - /* See if this group exists in the object (if it doesn't, add it to the end) */ - if (!defgroup_find_name(ob, dg->name)) { - odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup"); - memcpy(odg, dg, sizeof(bDeformGroup)); - BLI_addtail(&ob->defbase, odg); - } - } - if (ob->defbase.first && ob->actdef == 0) - ob->actdef = 1; - - - if (me->totvert) { - /* Add this object's materials to the base one's if they don't exist already - * (but only if limits not exceeded yet) */ - if (totcol < MAXMAT) { - for (a = 1; a <= ob_iter->totcol; a++) { - ma = give_current_material(ob_iter, a); - - for (b = 0; b < totcol; b++) { - if (ma == matar[b]) { - break; - } - } - if (b == totcol) { - matar[b] = ma; - if (ma) { - id_us_plus(&ma->id); - } - totcol++; - } - if (totcol >= MAXMAT) { - break; - } - } - } - - /* if this mesh has shapekeys, - * check if destination mesh already has matching entries too */ - if (me->key && key) { - /* for remapping KeyBlock.relative */ - int *index_map = MEM_mallocN(sizeof(int) * me->key->totkey, __func__); - KeyBlock **kb_map = MEM_mallocN(sizeof(KeyBlock *) * me->key->totkey, __func__); - - for (kb = me->key->block.first, i = 0; kb; kb = kb->next, i++) { - BLI_assert(i < me->key->totkey); - - kbn = BKE_keyblock_find_name(key, kb->name); - /* if key doesn't exist in destination mesh, add it */ - if (kbn) { - index_map[i] = BLI_findindex(&key->block, kbn); - } - else { - index_map[i] = key->totkey; - - kbn = BKE_keyblock_add(key, kb->name); - - BKE_keyblock_copy_settings(kbn, kb); - - /* adjust settings to fit (allocate a new data-array) */ - kbn->data = MEM_callocN(sizeof(float) * 3 * totvert, "joined_shapekey"); - kbn->totelem = totvert; - } - - kb_map[i] = kbn; - } - - /* remap relative index values */ - for (kb = me->key->block.first, i = 0; kb; kb = kb->next, i++) { - /* sanity check, should always be true */ - if (LIKELY(kb->relative < me->key->totkey)) { - kb_map[i]->relative = index_map[kb->relative]; - } - } - - MEM_freeN(index_map); - MEM_freeN(kb_map); - } - } - } - } - CTX_DATA_END; - - - /* setup new data for destination mesh */ - CustomData_reset(&vdata); - CustomData_reset(&edata); - CustomData_reset(&fdata); - CustomData_reset(&ldata); - CustomData_reset(&pdata); - - mvert = CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); - medge = CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); - mloop = CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop); - mpoly = CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly); - - vertofs = 0; - edgeofs = 0; - loopofs = 0; - polyofs = 0; - - /* inverse transform for all selected meshes in this object */ - invert_m4_m4(imat, ob->obmat); - - /* Add back active mesh first. - * This allows to keep things similar as they were, as much as possible - * (i.e. data from active mesh will remain first ones in new result of the merge, - * in same order for CD layers, etc). See also T50084. - */ - join_mesh_single( - depsgraph, bmain, scene, - ob, ob, imat, - &mvert, &medge, &mloop, &mpoly, - &vdata, &edata, &ldata, &pdata, - totvert, totedge, totloop, totpoly, - key, nkey, - matar, matmap, totcol, - &vertofs, &edgeofs, &loopofs, &polyofs); - - CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) - { - if (ob_iter == ob) { - continue; - } - /* only join if this is a mesh */ - if (ob_iter->type == OB_MESH) { - join_mesh_single( - depsgraph, bmain, scene, - ob, ob_iter, imat, - &mvert, &medge, &mloop, &mpoly, - &vdata, &edata, &ldata, &pdata, - totvert, totedge, totloop, totpoly, - key, nkey, - matar, matmap, totcol, - &vertofs, &edgeofs, &loopofs, &polyofs); - - /* free base, now that data is merged */ - if (ob_iter != ob) { - ED_object_base_free_and_unlink(bmain, scene, ob_iter); - } - } - } - CTX_DATA_END; - - /* return to mesh we're merging to */ - me = ob->data; - - CustomData_free(&me->vdata, me->totvert); - CustomData_free(&me->edata, me->totedge); - CustomData_free(&me->ldata, me->totloop); - CustomData_free(&me->pdata, me->totpoly); - - me->totvert = totvert; - me->totedge = totedge; - me->totloop = totloop; - me->totpoly = totpoly; - - me->vdata = vdata; - me->edata = edata; - me->ldata = ldata; - me->pdata = pdata; - - /* tessface data removed above, no need to update */ - BKE_mesh_update_customdata_pointers(me, false); - - /* update normals in case objects with non-uniform scale are joined */ - BKE_mesh_calc_normals(me); - - /* old material array */ - for (a = 1; a <= ob->totcol; a++) { - ma = ob->mat[a - 1]; - if (ma) - id_us_min(&ma->id); - } - for (a = 1; a <= me->totcol; a++) { - ma = me->mat[a - 1]; - if (ma) - id_us_min(&ma->id); - } - MEM_SAFE_FREE(ob->mat); - MEM_SAFE_FREE(ob->matbits); - MEM_SAFE_FREE(me->mat); - - if (totcol) { - me->mat = matar; - ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar"); - ob->matbits = MEM_callocN(sizeof(*ob->matbits) * totcol, "join obmatbits"); - MEM_freeN(matmap); - } - - ob->totcol = me->totcol = totcol; - - /* other mesh users */ - test_all_objects_materials(bmain, (ID *)me); - - /* free temp copy of destination shapekeys (if applicable) */ - if (nkey) { - /* We can assume nobody is using that ID currently. */ - BKE_id_free_ex(bmain, nkey, LIB_ID_FREE_NO_UI_USER, false); - } - - /* ensure newly inserted keys are time sorted */ - if (key && (key->type != KEY_RELATIVE)) { - BKE_key_sort(key); - } - - /* Due to dependnecy cycle some other object might access old derived data. */ - BKE_object_free_derived_caches(ob); - - DEG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */ - - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Material **matar = NULL, *ma; + Mesh *me; + MVert *mvert = NULL; + MEdge *medge = NULL; + MPoly *mpoly = NULL; + MLoop *mloop = NULL; + Key *key, *nkey = NULL; + KeyBlock *kb, *kbn; + float imat[4][4]; + int a, b, totcol, totmat = 0, totedge = 0, totvert = 0; + int totloop = 0, totpoly = 0, vertofs, *matmap = NULL; + int i, haskey = 0, edgeofs, loopofs, polyofs; + bool ok = false; + bDeformGroup *dg, *odg; + CustomData vdata, edata, fdata, ldata, pdata; + + if (ob->mode & OB_MODE_EDIT) { + BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode"); + return OPERATOR_CANCELLED; + } + + /* ob is the object we are adding geometry to */ + if (!ob || ob->type != OB_MESH) { + BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh"); + return OPERATOR_CANCELLED; + } + + Depsgraph *depsgraph = CTX_data_depsgraph(C); + + /* count & check */ + CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) { + if (ob_iter->type == OB_MESH) { + me = ob_iter->data; + + totvert += me->totvert; + totedge += me->totedge; + totloop += me->totloop; + totpoly += me->totpoly; + totmat += ob_iter->totcol; + + if (ob_iter == ob) + ok = true; + + /* check for shapekeys */ + if (me->key) + haskey++; + } + } + CTX_DATA_END; + + /* that way the active object is always selected */ + if (ok == false) { + BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh"); + return OPERATOR_CANCELLED; + } + + /* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */ + me = (Mesh *)ob->data; + key = me->key; + + if (totvert == 0 || totvert == me->totvert) { + BKE_report(op->reports, RPT_WARNING, "No mesh data to join"); + return OPERATOR_CANCELLED; + } + + if (totvert > MESH_MAX_VERTS) { + BKE_reportf(op->reports, + RPT_WARNING, + "Joining results in %d vertices, limit is %ld", + totvert, + MESH_MAX_VERTS); + return OPERATOR_CANCELLED; + } + + /* remove tessface to ensure we don't hold references to invalid faces */ + BKE_mesh_tessface_clear(me); + + /* new material indices and material array */ + if (totmat) { + matar = MEM_callocN(sizeof(*matar) * totmat, "join_mesh matar"); + matmap = MEM_callocN(sizeof(*matmap) * totmat, "join_mesh matmap"); + } + totcol = ob->totcol; + + /* obact materials in new main array, is nicer start! */ + for (a = 0; a < ob->totcol; a++) { + matar[a] = give_current_material(ob, a + 1); + id_us_plus((ID *)matar[a]); + /* increase id->us : will be lowered later */ + } + + /* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders + * with arrays that are large enough to hold shapekey data for all meshes + * - if destination mesh didn't have shapekeys, but we encountered some in the meshes we're + * joining, set up a new keyblock and assign to the mesh + */ + if (key) { + /* make a duplicate copy that will only be used here... (must remember to free it!) */ + nkey = BKE_key_copy(bmain, key); + + /* for all keys in old block, clear data-arrays */ + for (kb = key->block.first; kb; kb = kb->next) { + if (kb->data) + MEM_freeN(kb->data); + kb->data = MEM_callocN(sizeof(float) * 3 * totvert, "join_shapekey"); + kb->totelem = totvert; + } + } + else if (haskey) { + /* add a new key-block and add to the mesh */ + key = me->key = BKE_key_add(bmain, (ID *)me); + key->type = KEY_RELATIVE; + } + + /* first pass over objects - copying materials and vertexgroups across */ + CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) { + /* only act if a mesh, and not the one we're joining to */ + if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) { + me = ob_iter->data; + + /* Join this object's vertex groups to the base one's */ + for (dg = ob_iter->defbase.first; dg; dg = dg->next) { + /* See if this group exists in the object (if it doesn't, add it to the end) */ + if (!defgroup_find_name(ob, dg->name)) { + odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup"); + memcpy(odg, dg, sizeof(bDeformGroup)); + BLI_addtail(&ob->defbase, odg); + } + } + if (ob->defbase.first && ob->actdef == 0) + ob->actdef = 1; + + if (me->totvert) { + /* Add this object's materials to the base one's if they don't exist already + * (but only if limits not exceeded yet) */ + if (totcol < MAXMAT) { + for (a = 1; a <= ob_iter->totcol; a++) { + ma = give_current_material(ob_iter, a); + + for (b = 0; b < totcol; b++) { + if (ma == matar[b]) { + break; + } + } + if (b == totcol) { + matar[b] = ma; + if (ma) { + id_us_plus(&ma->id); + } + totcol++; + } + if (totcol >= MAXMAT) { + break; + } + } + } + + /* if this mesh has shapekeys, + * check if destination mesh already has matching entries too */ + if (me->key && key) { + /* for remapping KeyBlock.relative */ + int *index_map = MEM_mallocN(sizeof(int) * me->key->totkey, __func__); + KeyBlock **kb_map = MEM_mallocN(sizeof(KeyBlock *) * me->key->totkey, __func__); + + for (kb = me->key->block.first, i = 0; kb; kb = kb->next, i++) { + BLI_assert(i < me->key->totkey); + + kbn = BKE_keyblock_find_name(key, kb->name); + /* if key doesn't exist in destination mesh, add it */ + if (kbn) { + index_map[i] = BLI_findindex(&key->block, kbn); + } + else { + index_map[i] = key->totkey; + + kbn = BKE_keyblock_add(key, kb->name); + + BKE_keyblock_copy_settings(kbn, kb); + + /* adjust settings to fit (allocate a new data-array) */ + kbn->data = MEM_callocN(sizeof(float) * 3 * totvert, "joined_shapekey"); + kbn->totelem = totvert; + } + + kb_map[i] = kbn; + } + + /* remap relative index values */ + for (kb = me->key->block.first, i = 0; kb; kb = kb->next, i++) { + /* sanity check, should always be true */ + if (LIKELY(kb->relative < me->key->totkey)) { + kb_map[i]->relative = index_map[kb->relative]; + } + } + + MEM_freeN(index_map); + MEM_freeN(kb_map); + } + } + } + } + CTX_DATA_END; + + /* setup new data for destination mesh */ + CustomData_reset(&vdata); + CustomData_reset(&edata); + CustomData_reset(&fdata); + CustomData_reset(&ldata); + CustomData_reset(&pdata); + + mvert = CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); + medge = CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); + mloop = CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop); + mpoly = CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly); + + vertofs = 0; + edgeofs = 0; + loopofs = 0; + polyofs = 0; + + /* inverse transform for all selected meshes in this object */ + invert_m4_m4(imat, ob->obmat); + + /* Add back active mesh first. + * This allows to keep things similar as they were, as much as possible + * (i.e. data from active mesh will remain first ones in new result of the merge, + * in same order for CD layers, etc). See also T50084. + */ + join_mesh_single(depsgraph, + bmain, + scene, + ob, + ob, + imat, + &mvert, + &medge, + &mloop, + &mpoly, + &vdata, + &edata, + &ldata, + &pdata, + totvert, + totedge, + totloop, + totpoly, + key, + nkey, + matar, + matmap, + totcol, + &vertofs, + &edgeofs, + &loopofs, + &polyofs); + + CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) { + if (ob_iter == ob) { + continue; + } + /* only join if this is a mesh */ + if (ob_iter->type == OB_MESH) { + join_mesh_single(depsgraph, + bmain, + scene, + ob, + ob_iter, + imat, + &mvert, + &medge, + &mloop, + &mpoly, + &vdata, + &edata, + &ldata, + &pdata, + totvert, + totedge, + totloop, + totpoly, + key, + nkey, + matar, + matmap, + totcol, + &vertofs, + &edgeofs, + &loopofs, + &polyofs); + + /* free base, now that data is merged */ + if (ob_iter != ob) { + ED_object_base_free_and_unlink(bmain, scene, ob_iter); + } + } + } + CTX_DATA_END; + + /* return to mesh we're merging to */ + me = ob->data; + + CustomData_free(&me->vdata, me->totvert); + CustomData_free(&me->edata, me->totedge); + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); + + me->totvert = totvert; + me->totedge = totedge; + me->totloop = totloop; + me->totpoly = totpoly; + + me->vdata = vdata; + me->edata = edata; + me->ldata = ldata; + me->pdata = pdata; + + /* tessface data removed above, no need to update */ + BKE_mesh_update_customdata_pointers(me, false); + + /* update normals in case objects with non-uniform scale are joined */ + BKE_mesh_calc_normals(me); + + /* old material array */ + for (a = 1; a <= ob->totcol; a++) { + ma = ob->mat[a - 1]; + if (ma) + id_us_min(&ma->id); + } + for (a = 1; a <= me->totcol; a++) { + ma = me->mat[a - 1]; + if (ma) + id_us_min(&ma->id); + } + MEM_SAFE_FREE(ob->mat); + MEM_SAFE_FREE(ob->matbits); + MEM_SAFE_FREE(me->mat); + + if (totcol) { + me->mat = matar; + ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar"); + ob->matbits = MEM_callocN(sizeof(*ob->matbits) * totcol, "join obmatbits"); + MEM_freeN(matmap); + } + + ob->totcol = me->totcol = totcol; + + /* other mesh users */ + test_all_objects_materials(bmain, (ID *)me); + + /* free temp copy of destination shapekeys (if applicable) */ + if (nkey) { + /* We can assume nobody is using that ID currently. */ + BKE_id_free_ex(bmain, nkey, LIB_ID_FREE_NO_UI_USER, false); + } + + /* ensure newly inserted keys are time sorted */ + if (key && (key->type != KEY_RELATIVE)) { + BKE_key_sort(key); + } + + /* Due to dependnecy cycle some other object might access old derived data. */ + BKE_object_free_derived_caches(ob); + + DEG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */ + + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + + return OPERATOR_FINISHED; } /*********************** JOIN AS SHAPES ***************************/ @@ -606,86 +661,85 @@ int join_mesh_exec(bContext *C, wmOperator *op) int join_mesh_shapes_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob_active = CTX_data_active_object(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Mesh *me = (Mesh *)ob_active->data; - Mesh *selme = NULL; - Mesh *me_deformed = NULL; - Key *key = me->key; - KeyBlock *kb; - bool ok = false, nonequal_verts = false; - - CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) - { - if (ob_iter == ob_active) { - continue; - } - - if (ob_iter->type == OB_MESH) { - selme = (Mesh *)ob_iter->data; - - if (selme->totvert == me->totvert) - ok = true; - else - nonequal_verts = 1; - } - } - CTX_DATA_END; - - if (!ok) { - if (nonequal_verts) - BKE_report(op->reports, RPT_WARNING, "Selected meshes must have equal numbers of vertices"); - else - BKE_report(op->reports, RPT_WARNING, "No additional selected meshes with equal vertex count to join"); - return OPERATOR_CANCELLED; - } - - if (key == NULL) { - key = me->key = BKE_key_add(bmain, (ID *)me); - key->type = KEY_RELATIVE; - - /* first key added, so it was the basis. initialize it with the existing mesh */ - kb = BKE_keyblock_add(key, NULL); - BKE_keyblock_convert_from_mesh(me, key, kb); - } - - /* now ready to add new keys from selected meshes */ - CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) - { - if (ob_iter == ob_active) { - continue; - } - - if (ob_iter->type == OB_MESH) { - selme = (Mesh *)ob_iter->data; - - if (selme->totvert == me->totvert) { - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); - - me_deformed = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); - - if (!me_deformed) { - continue; - } - - kb = BKE_keyblock_add(key, ob_iter->id.name + 2); - - BKE_mesh_runtime_eval_to_meshkey(me_deformed, me, kb); - } - } - } - CTX_DATA_END; - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob_active = CTX_data_active_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Mesh *me = (Mesh *)ob_active->data; + Mesh *selme = NULL; + Mesh *me_deformed = NULL; + Key *key = me->key; + KeyBlock *kb; + bool ok = false, nonequal_verts = false; + + CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) { + if (ob_iter == ob_active) { + continue; + } + + if (ob_iter->type == OB_MESH) { + selme = (Mesh *)ob_iter->data; + + if (selme->totvert == me->totvert) + ok = true; + else + nonequal_verts = 1; + } + } + CTX_DATA_END; + + if (!ok) { + if (nonequal_verts) + BKE_report(op->reports, RPT_WARNING, "Selected meshes must have equal numbers of vertices"); + else + BKE_report(op->reports, + RPT_WARNING, + "No additional selected meshes with equal vertex count to join"); + return OPERATOR_CANCELLED; + } + + if (key == NULL) { + key = me->key = BKE_key_add(bmain, (ID *)me); + key->type = KEY_RELATIVE; + + /* first key added, so it was the basis. initialize it with the existing mesh */ + kb = BKE_keyblock_add(key, NULL); + BKE_keyblock_convert_from_mesh(me, key, kb); + } + + /* now ready to add new keys from selected meshes */ + CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) { + if (ob_iter == ob_active) { + continue; + } + + if (ob_iter->type == OB_MESH) { + selme = (Mesh *)ob_iter->data; + + if (selme->totvert == me->totvert) { + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); + + me_deformed = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); + + if (!me_deformed) { + continue; + } + + kb = BKE_keyblock_add(key, ob_iter->id.name + 2); + + BKE_mesh_runtime_eval_to_meshkey(me_deformed, me, kb); + } + } + } + CTX_DATA_END; + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + + return OPERATOR_FINISHED; } - /* -------------------------------------------------------------------- */ /* Mesh Mirror (Topology) */ @@ -699,120 +753,124 @@ static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1}; /* note, is supposed return -1 on error, which callers are currently checking for, but is not used so far */ int ED_mesh_mirror_topo_table(Object *ob, Mesh *me_eval, char mode) { - if (mode == 'u') { /* use table */ - if (ED_mesh_mirrtopo_recalc_check(ob->data, me_eval, &mesh_topo_store)) { - ED_mesh_mirror_topo_table(ob, me_eval, 's'); - } - } - else if (mode == 's') { /* start table */ - ED_mesh_mirrtopo_init(ob->data, me_eval, &mesh_topo_store, false); - } - else if (mode == 'e') { /* end table */ - ED_mesh_mirrtopo_free(&mesh_topo_store); - } - else { - BLI_assert(0); - } - - return 0; + if (mode == 'u') { /* use table */ + if (ED_mesh_mirrtopo_recalc_check(ob->data, me_eval, &mesh_topo_store)) { + ED_mesh_mirror_topo_table(ob, me_eval, 's'); + } + } + else if (mode == 's') { /* start table */ + ED_mesh_mirrtopo_init(ob->data, me_eval, &mesh_topo_store, false); + } + else if (mode == 'e') { /* end table */ + ED_mesh_mirrtopo_free(&mesh_topo_store); + } + else { + BLI_assert(0); + } + + return 0; } /** \} */ - static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh, int index) { - Mesh *me = ob->data; - MVert *mvert = mesh ? mesh->mvert : me->mvert; - float vec[3]; + Mesh *me = ob->data; + MVert *mvert = mesh ? mesh->mvert : me->mvert; + float vec[3]; - mvert = &mvert[index]; - vec[0] = -mvert->co[0]; - vec[1] = mvert->co[1]; - vec[2] = mvert->co[2]; + mvert = &mvert[index]; + vec[0] = -mvert->co[0]; + vec[1] = mvert->co[1]; + vec[2] = mvert->co[2]; - return ED_mesh_mirror_spatial_table(ob, NULL, mesh, vec, 'u'); + return ED_mesh_mirror_spatial_table(ob, NULL, mesh, vec, 'u'); } static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index) { - if (ED_mesh_mirror_topo_table(ob, mesh, 'u') == -1) - return -1; + if (ED_mesh_mirror_topo_table(ob, mesh, 'u') == -1) + return -1; - return mesh_topo_store.index_lookup[index]; + return mesh_topo_store.index_lookup[index]; } int mesh_get_x_mirror_vert(Object *ob, Mesh *me_eval, int index, const bool use_topology) { - if (use_topology) { - return mesh_get_x_mirror_vert_topo(ob, me_eval, index); - } - else { - return mesh_get_x_mirror_vert_spatial(ob, me_eval, index); - } + if (use_topology) { + return mesh_get_x_mirror_vert_topo(ob, me_eval, index); + } + else { + return mesh_get_x_mirror_vert_spatial(ob, me_eval, index); + } } static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, const float co[3]) { - float vec[3]; - int i; - - /* ignore nan verts */ - if ((isfinite(co[0]) == false) || - (isfinite(co[1]) == false) || - (isfinite(co[2]) == false)) - { - return NULL; - } - - vec[0] = -co[0]; - vec[1] = co[1]; - vec[2] = co[2]; - - i = ED_mesh_mirror_spatial_table(ob, em, NULL, vec, 'u'); - if (i != -1) { - return BM_vert_at_index(em->bm, i); - } - return NULL; + float vec[3]; + int i; + + /* ignore nan verts */ + if ((isfinite(co[0]) == false) || (isfinite(co[1]) == false) || (isfinite(co[2]) == false)) { + return NULL; + } + + vec[0] = -co[0]; + vec[1] = co[1]; + vec[2] = co[2]; + + i = ED_mesh_mirror_spatial_table(ob, em, NULL, vec, 'u'); + if (i != -1) { + return BM_vert_at_index(em->bm, i); + } + return NULL; } -static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, struct BMEditMesh *em, BMVert *eve, int index) +static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, + struct BMEditMesh *em, + BMVert *eve, + int index) { - intptr_t poinval; - if (ED_mesh_mirror_topo_table(ob, NULL, 'u') == -1) - return NULL; - - if (index == -1) { - BMIter iter; - BMVert *v; - - index = 0; - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (v == eve) - break; - index++; - } - - if (index == em->bm->totvert) { - return NULL; - } - } - - poinval = mesh_topo_store.index_lookup[index]; - - if (poinval != -1) - return (BMVert *)(poinval); - return NULL; + intptr_t poinval; + if (ED_mesh_mirror_topo_table(ob, NULL, 'u') == -1) + return NULL; + + if (index == -1) { + BMIter iter; + BMVert *v; + + index = 0; + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (v == eve) + break; + index++; + } + + if (index == em->bm->totvert) { + return NULL; + } + } + + poinval = mesh_topo_store.index_lookup[index]; + + if (poinval != -1) + return (BMVert *)(poinval); + return NULL; } -BMVert *editbmesh_get_x_mirror_vert(Object *ob, struct BMEditMesh *em, BMVert *eve, const float co[3], int index, const bool use_topology) +BMVert *editbmesh_get_x_mirror_vert(Object *ob, + struct BMEditMesh *em, + BMVert *eve, + const float co[3], + int index, + const bool use_topology) { - if (use_topology) { - return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index); - } - else { - return editbmesh_get_x_mirror_vert_spatial(ob, em, co); - } + if (use_topology) { + return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index); + } + else { + return editbmesh_get_x_mirror_vert_spatial(ob, em, co); + } } /** @@ -822,187 +880,187 @@ BMVert *editbmesh_get_x_mirror_vert(Object *ob, struct BMEditMesh *em, BMVert *e */ int ED_mesh_mirror_get_vert(Object *ob, int index) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - int index_mirr; - - if (em) { - BMVert *eve, *eve_mirr; - eve = BM_vert_at_index(em->bm, index); - eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index, use_topology); - index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1; - } - else { - index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, use_topology); - } - - return index_mirr; + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + int index_mirr; + + if (em) { + BMVert *eve, *eve_mirr; + eve = BM_vert_at_index(em->bm, index); + eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index, use_topology); + index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1; + } + else { + index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, use_topology); + } + + return index_mirr; } #if 0 static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent) { - float vec[2]; - float cent_vec[2]; - float cent[2]; - - /* ignore nan verts */ - if (isnan(uv[0]) || !isfinite(uv[0]) || - isnan(uv[1]) || !isfinite(uv[1]) - ) - { - return NULL; - } - - if (axis) { - vec[0] = uv[0]; - vec[1] = -((uv[1]) - mirrCent[1]) + mirrCent[1]; - - cent_vec[0] = face_cent[0]; - cent_vec[1] = -((face_cent[1]) - mirrCent[1]) + mirrCent[1]; - } - else { - vec[0] = -((uv[0]) - mirrCent[0]) + mirrCent[0]; - vec[1] = uv[1]; - - cent_vec[0] = -((face_cent[0]) - mirrCent[0]) + mirrCent[0]; - cent_vec[1] = face_cent[1]; - } - - /* TODO - Optimize */ - { - BMIter iter; - BMFace *efa; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - uv_poly_center(efa, cent, cd_loop_uv_offset); - - if ( (fabsf(cent[0] - cent_vec[0]) < 0.001f) && (fabsf(cent[1] - cent_vec[1]) < 0.001f) ) { - BMIter liter; - BMLoop *l; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - if ( (fabsf(luv->uv[0] - vec[0]) < 0.001f) && (fabsf(luv->uv[1] - vec[1]) < 0.001f) ) { - return luv->uv; - - } - } - } - } - } - - return NULL; + float vec[2]; + float cent_vec[2]; + float cent[2]; + + /* ignore nan verts */ + if (isnan(uv[0]) || !isfinite(uv[0]) || + isnan(uv[1]) || !isfinite(uv[1]) + ) + { + return NULL; + } + + if (axis) { + vec[0] = uv[0]; + vec[1] = -((uv[1]) - mirrCent[1]) + mirrCent[1]; + + cent_vec[0] = face_cent[0]; + cent_vec[1] = -((face_cent[1]) - mirrCent[1]) + mirrCent[1]; + } + else { + vec[0] = -((uv[0]) - mirrCent[0]) + mirrCent[0]; + vec[1] = uv[1]; + + cent_vec[0] = -((face_cent[0]) - mirrCent[0]) + mirrCent[0]; + cent_vec[1] = face_cent[1]; + } + + /* TODO - Optimize */ + { + BMIter iter; + BMFace *efa; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + uv_poly_center(efa, cent, cd_loop_uv_offset); + + if ( (fabsf(cent[0] - cent_vec[0]) < 0.001f) && (fabsf(cent[1] - cent_vec[1]) < 0.001f) ) { + BMIter liter; + BMLoop *l; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if ( (fabsf(luv->uv[0] - vec[0]) < 0.001f) && (fabsf(luv->uv[1] - vec[1]) < 0.001f) ) { + return luv->uv; + + } + } + } + } + } + + return NULL; } #endif static unsigned int mirror_facehash(const void *ptr) { - const MFace *mf = ptr; - unsigned int v0, v1; - - if (mf->v4) { - v0 = MIN4(mf->v1, mf->v2, mf->v3, mf->v4); - v1 = MAX4(mf->v1, mf->v2, mf->v3, mf->v4); - } - else { - v0 = MIN3(mf->v1, mf->v2, mf->v3); - v1 = MAX3(mf->v1, mf->v2, mf->v3); - } - - return ((v0 * 39) ^ (v1 * 31)); + const MFace *mf = ptr; + unsigned int v0, v1; + + if (mf->v4) { + v0 = MIN4(mf->v1, mf->v2, mf->v3, mf->v4); + v1 = MAX4(mf->v1, mf->v2, mf->v3, mf->v4); + } + else { + v0 = MIN3(mf->v1, mf->v2, mf->v3); + v1 = MAX3(mf->v1, mf->v2, mf->v3); + } + + return ((v0 * 39) ^ (v1 * 31)); } static int mirror_facerotation(MFace *a, MFace *b) { - if (b->v4) { - if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3 && a->v4 == b->v4) - return 0; - else if (a->v4 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3 && a->v3 == b->v4) - return 1; - else if (a->v3 == b->v1 && a->v4 == b->v2 && a->v1 == b->v3 && a->v2 == b->v4) - return 2; - else if (a->v2 == b->v1 && a->v3 == b->v2 && a->v4 == b->v3 && a->v1 == b->v4) - return 3; - } - else { - if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3) - return 0; - else if (a->v3 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3) - return 1; - else if (a->v2 == b->v1 && a->v3 == b->v2 && a->v1 == b->v3) - return 2; - } - - return -1; + if (b->v4) { + if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3 && a->v4 == b->v4) + return 0; + else if (a->v4 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3 && a->v3 == b->v4) + return 1; + else if (a->v3 == b->v1 && a->v4 == b->v2 && a->v1 == b->v3 && a->v2 == b->v4) + return 2; + else if (a->v2 == b->v1 && a->v3 == b->v2 && a->v4 == b->v3 && a->v1 == b->v4) + return 3; + } + else { + if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3) + return 0; + else if (a->v3 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3) + return 1; + else if (a->v2 == b->v1 && a->v3 == b->v2 && a->v1 == b->v3) + return 2; + } + + return -1; } static bool mirror_facecmp(const void *a, const void *b) { - return (mirror_facerotation((MFace *)a, (MFace *)b) == -1); + return (mirror_facerotation((MFace *)a, (MFace *)b) == -1); } /* This is a Mesh-based copy of mesh_get_x_mirror_faces() */ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval) { - Mesh *me = ob->data; - MVert *mv, *mvert; - MFace mirrormf, *mf, *hashmf, *mface; - GHash *fhash; - int *mirrorverts, *mirrorfaces; + Mesh *me = ob->data; + MVert *mv, *mvert; + MFace mirrormf, *mf, *hashmf, *mface; + GHash *fhash; + int *mirrorverts, *mirrorfaces; - BLI_assert(em == NULL); /* Does not work otherwise, currently... */ + BLI_assert(em == NULL); /* Does not work otherwise, currently... */ - const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - const int totvert = me_eval ? me_eval->totvert : me->totvert; - const int totface = me_eval ? me_eval->totface : me->totface; - int a; + const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + const int totvert = me_eval ? me_eval->totvert : me->totvert; + const int totface = me_eval ? me_eval->totface : me->totface; + int a; - mirrorverts = MEM_callocN(sizeof(int) * totvert, "MirrorVerts"); - mirrorfaces = MEM_callocN(sizeof(int) * 2 * totface, "MirrorFaces"); + mirrorverts = MEM_callocN(sizeof(int) * totvert, "MirrorVerts"); + mirrorfaces = MEM_callocN(sizeof(int) * 2 * totface, "MirrorFaces"); - mvert = me_eval ? me_eval->mvert : me->mvert; - mface = me_eval ? me_eval->mface : me->mface; + mvert = me_eval ? me_eval->mvert : me->mvert; + mface = me_eval ? me_eval->mface : me->mface; - ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's'); + ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's'); - for (a = 0, mv = mvert; a < totvert; a++, mv++) - mirrorverts[a] = mesh_get_x_mirror_vert(ob, me_eval, a, use_topology); + for (a = 0, mv = mvert; a < totvert; a++, mv++) + mirrorverts[a] = mesh_get_x_mirror_vert(ob, me_eval, a, use_topology); - ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 'e'); + ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 'e'); - fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface); - for (a = 0, mf = mface; a < totface; a++, mf++) - BLI_ghash_insert(fhash, mf, mf); + fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface); + for (a = 0, mf = mface; a < totface; a++, mf++) + BLI_ghash_insert(fhash, mf, mf); - for (a = 0, mf = mface; a < totface; a++, mf++) { - mirrormf.v1 = mirrorverts[mf->v3]; - mirrormf.v2 = mirrorverts[mf->v2]; - mirrormf.v3 = mirrorverts[mf->v1]; - mirrormf.v4 = (mf->v4) ? mirrorverts[mf->v4] : 0; + for (a = 0, mf = mface; a < totface; a++, mf++) { + mirrormf.v1 = mirrorverts[mf->v3]; + mirrormf.v2 = mirrorverts[mf->v2]; + mirrormf.v3 = mirrorverts[mf->v1]; + mirrormf.v4 = (mf->v4) ? mirrorverts[mf->v4] : 0; - /* make sure v4 is not 0 if a quad */ - if (mf->v4 && mirrormf.v4 == 0) { - SWAP(unsigned int, mirrormf.v1, mirrormf.v3); - SWAP(unsigned int, mirrormf.v2, mirrormf.v4); - } + /* make sure v4 is not 0 if a quad */ + if (mf->v4 && mirrormf.v4 == 0) { + SWAP(unsigned int, mirrormf.v1, mirrormf.v3); + SWAP(unsigned int, mirrormf.v2, mirrormf.v4); + } - hashmf = BLI_ghash_lookup(fhash, &mirrormf); - if (hashmf) { - mirrorfaces[a * 2] = hashmf - mface; - mirrorfaces[a * 2 + 1] = mirror_facerotation(&mirrormf, hashmf); - } - else - mirrorfaces[a * 2] = -1; - } + hashmf = BLI_ghash_lookup(fhash, &mirrormf); + if (hashmf) { + mirrorfaces[a * 2] = hashmf - mface; + mirrorfaces[a * 2 + 1] = mirror_facerotation(&mirrormf, hashmf); + } + else + mirrorfaces[a * 2] = -1; + } - BLI_ghash_free(fhash, NULL, NULL); - MEM_freeN(mirrorverts); + BLI_ghash_free(fhash, NULL, NULL); + MEM_freeN(mirrorverts); - return mirrorfaces; + return mirrorfaces; } /* selection, vertex and face */ @@ -1014,147 +1072,148 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval) * * \return boolean true == Found */ -bool ED_mesh_pick_face( - bContext *C, Object *ob, const int mval[2], uint dist_px, - uint *r_index) +bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index) { - ViewContext vc; - Mesh *me = ob->data; + ViewContext vc; + Mesh *me = ob->data; - BLI_assert(me && GS(me->id.name) == ID_ME); + BLI_assert(me && GS(me->id.name) == ID_ME); - if (!me || me->totpoly == 0) - return false; + if (!me || me->totpoly == 0) + return false; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc); - if (dist_px) { - /* sample rect to increase chances of selecting, so that when clicking - * on an edge in the backbuf, we can still select a face */ + if (dist_px) { + /* sample rect to increase chances of selecting, so that when clicking + * on an edge in the backbuf, we can still select a face */ - ED_view3d_select_id_validate(&vc); + ED_view3d_select_id_validate(&vc); - *r_index = ED_view3d_select_id_read_nearest( - &vc, mval, 1, me->totpoly + 1, &dist_px); - } - else { - /* sample only on the exact position */ - *r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]); - } + *r_index = ED_view3d_select_id_read_nearest(&vc, mval, 1, me->totpoly + 1, &dist_px); + } + else { + /* sample only on the exact position */ + *r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]); + } - if ((*r_index) == 0 || (*r_index) > (unsigned int)me->totpoly) { - return false; - } + if ((*r_index) == 0 || (*r_index) > (unsigned int)me->totpoly) { + return false; + } - (*r_index)--; + (*r_index)--; - return true; + return true; } static void ed_mesh_pick_face_vert__mpoly_find( - /* context */ - struct ARegion *ar, const float mval[2], - /* mesh data (evaluated) */ - const MPoly *mp, - const MVert *mvert, const MLoop *mloop, - /* return values */ - float *r_len_best, int *r_v_idx_best) + /* context */ + struct ARegion *ar, + const float mval[2], + /* mesh data (evaluated) */ + const MPoly *mp, + const MVert *mvert, + const MLoop *mloop, + /* return values */ + float *r_len_best, + int *r_v_idx_best) { - const MLoop *ml; - int j = mp->totloop; - for (ml = &mloop[mp->loopstart]; j--; ml++) { - float sco[2]; - const int v_idx = ml->v; - const float *co = mvert[v_idx].co; - if (ED_view3d_project_float_object(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - const float len_test = len_manhattan_v2v2(mval, sco); - if (len_test < *r_len_best) { - *r_len_best = len_test; - *r_v_idx_best = v_idx; - } - } - } + const MLoop *ml; + int j = mp->totloop; + for (ml = &mloop[mp->loopstart]; j--; ml++) { + float sco[2]; + const int v_idx = ml->v; + const float *co = mvert[v_idx].co; + if (ED_view3d_project_float_object(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + const float len_test = len_manhattan_v2v2(mval, sco); + if (len_test < *r_len_best) { + *r_len_best = len_test; + *r_v_idx_best = v_idx; + } + } + } } /** * Use when the back buffer stores face index values. but we want a vert. * This gets the face then finds the closest vertex to mval. */ bool ED_mesh_pick_face_vert( - bContext *C, Object *ob, const int mval[2], uint dist_px, - uint *r_index) + bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - unsigned int poly_index; - Mesh *me = ob->data; - - BLI_assert(me && GS(me->id.name) == ID_ME); - - if (ED_mesh_pick_face(C, ob, mval, dist_px, &poly_index)) { - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - struct ARegion *ar = CTX_wm_region(C); - - /* derived mesh to find deformed locations */ - Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH_ORIGINDEX); - - int v_idx_best = ORIGINDEX_NONE; - - /* find the vert closest to 'mval' */ - const float mval_f[2] = {UNPACK2(mval)}; - float len_best = FLT_MAX; - - MPoly *me_eval_mpoly; - MLoop *me_eval_mloop; - MVert *me_eval_mvert; - unsigned int me_eval_mpoly_len; - const int *index_mp_to_orig; - - me_eval_mpoly = me_eval->mpoly; - me_eval_mloop = me_eval->mloop; - me_eval_mvert = me_eval->mvert; - - me_eval_mpoly_len = me_eval->totpoly; - - index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX); - - /* tag all verts using this face */ - if (index_mp_to_orig) { - unsigned int i; - - for (i = 0; i < me_eval_mpoly_len; i++) { - if (index_mp_to_orig[i] == poly_index) { - ed_mesh_pick_face_vert__mpoly_find( - ar, mval_f, - &me_eval_mpoly[i], me_eval_mvert, me_eval_mloop, - &len_best, &v_idx_best); - } - } - } - else { - if (poly_index < me_eval_mpoly_len) { - ed_mesh_pick_face_vert__mpoly_find( - ar, mval_f, - &me_eval_mpoly[poly_index], me_eval_mvert, me_eval_mloop, - &len_best, &v_idx_best); - } - } - - /* map 'dm -> me' r_index if possible */ - if (v_idx_best != ORIGINDEX_NONE) { - const int *index_mv_to_orig; - index_mv_to_orig = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); - if (index_mv_to_orig) { - v_idx_best = index_mv_to_orig[v_idx_best]; - } - } - - if ((v_idx_best != ORIGINDEX_NONE) && (v_idx_best < me->totvert)) { - *r_index = v_idx_best; - return true; - } - } - - return false; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + unsigned int poly_index; + Mesh *me = ob->data; + + BLI_assert(me && GS(me->id.name) == ID_ME); + + if (ED_mesh_pick_face(C, ob, mval, dist_px, &poly_index)) { + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + struct ARegion *ar = CTX_wm_region(C); + + /* derived mesh to find deformed locations */ + Mesh *me_eval = mesh_get_eval_final( + depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH_ORIGINDEX); + + int v_idx_best = ORIGINDEX_NONE; + + /* find the vert closest to 'mval' */ + const float mval_f[2] = {UNPACK2(mval)}; + float len_best = FLT_MAX; + + MPoly *me_eval_mpoly; + MLoop *me_eval_mloop; + MVert *me_eval_mvert; + unsigned int me_eval_mpoly_len; + const int *index_mp_to_orig; + + me_eval_mpoly = me_eval->mpoly; + me_eval_mloop = me_eval->mloop; + me_eval_mvert = me_eval->mvert; + + me_eval_mpoly_len = me_eval->totpoly; + + index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX); + + /* tag all verts using this face */ + if (index_mp_to_orig) { + unsigned int i; + + for (i = 0; i < me_eval_mpoly_len; i++) { + if (index_mp_to_orig[i] == poly_index) { + ed_mesh_pick_face_vert__mpoly_find( + ar, mval_f, &me_eval_mpoly[i], me_eval_mvert, me_eval_mloop, &len_best, &v_idx_best); + } + } + } + else { + if (poly_index < me_eval_mpoly_len) { + ed_mesh_pick_face_vert__mpoly_find(ar, + mval_f, + &me_eval_mpoly[poly_index], + me_eval_mvert, + me_eval_mloop, + &len_best, + &v_idx_best); + } + } + + /* map 'dm -> me' r_index if possible */ + if (v_idx_best != ORIGINDEX_NONE) { + const int *index_mv_to_orig; + index_mv_to_orig = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); + if (index_mv_to_orig) { + v_idx_best = index_mv_to_orig[v_idx_best]; + } + } + + if ((v_idx_best != ORIGINDEX_NONE) && (v_idx_best < me->totvert)) { + *r_index = v_idx_best; + return true; + } + } + + return false; } /** @@ -1164,196 +1223,199 @@ bool ED_mesh_pick_face_vert( * \return boolean true == Found */ typedef struct VertPickData { - const MVert *mvert; - const float *mval_f; /* [2] */ - ARegion *ar; + const MVert *mvert; + const float *mval_f; /* [2] */ + ARegion *ar; - /* runtime */ - float len_best; - int v_idx_best; + /* runtime */ + float len_best; + int v_idx_best; } VertPickData; -static void ed_mesh_pick_vert__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +static void ed_mesh_pick_vert__mapFunc(void *userData, + int index, + const float co[3], + const float UNUSED(no_f[3]), + const short UNUSED(no_s[3])) { - VertPickData *data = userData; - if ((data->mvert[index].flag & ME_HIDE) == 0) { - float sco[2]; - - if (ED_view3d_project_float_object(data->ar, co, sco, V3D_PROJ_TEST_CLIP_DEFAULT) == V3D_PROJ_RET_OK) { - const float len = len_manhattan_v2v2(data->mval_f, sco); - if (len < data->len_best) { - data->len_best = len; - data->v_idx_best = index; - } - } - } + VertPickData *data = userData; + if ((data->mvert[index].flag & ME_HIDE) == 0) { + float sco[2]; + + if (ED_view3d_project_float_object(data->ar, co, sco, V3D_PROJ_TEST_CLIP_DEFAULT) == + V3D_PROJ_RET_OK) { + const float len = len_manhattan_v2v2(data->mval_f, sco); + if (len < data->len_best) { + data->len_best = len; + data->v_idx_best = index; + } + } + } } bool ED_mesh_pick_vert( - bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, - uint *r_index) + bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index) { - ViewContext vc; - Mesh *me = ob->data; + ViewContext vc; + Mesh *me = ob->data; - BLI_assert(me && GS(me->id.name) == ID_ME); + BLI_assert(me && GS(me->id.name) == ID_ME); - if (!me || me->totvert == 0) - return false; + if (!me || me->totvert == 0) + return false; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc); - if (use_zbuf) { - if (dist_px > 0) { - /* sample rect to increase chances of selecting, so that when clicking - * on an face in the backbuf, we can still select a vert */ + if (use_zbuf) { + if (dist_px > 0) { + /* sample rect to increase chances of selecting, so that when clicking + * on an face in the backbuf, we can still select a vert */ - ED_view3d_select_id_validate(&vc); + ED_view3d_select_id_validate(&vc); - *r_index = ED_view3d_select_id_read_nearest( - &vc, mval, 1, me->totvert + 1, &dist_px); - } - else { - /* sample only on the exact position */ - *r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]); - } + *r_index = ED_view3d_select_id_read_nearest(&vc, mval, 1, me->totvert + 1, &dist_px); + } + else { + /* sample only on the exact position */ + *r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]); + } - if ((*r_index) == 0 || (*r_index) > (uint)me->totvert) { - return false; - } + if ((*r_index) == 0 || (*r_index) > (uint)me->totvert) { + return false; + } - (*r_index)--; - } - else { - Scene *scene_eval = DEG_get_evaluated_scene(vc.depsgraph); - Object *ob_eval = DEG_get_evaluated_object(vc.depsgraph, ob); + (*r_index)--; + } + else { + Scene *scene_eval = DEG_get_evaluated_scene(vc.depsgraph); + Object *ob_eval = DEG_get_evaluated_object(vc.depsgraph, ob); - /* derived mesh to find deformed locations */ - Mesh *me_eval = mesh_get_eval_final(vc.depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); - ARegion *ar = vc.ar; - RegionView3D *rv3d = ar->regiondata; + /* derived mesh to find deformed locations */ + Mesh *me_eval = mesh_get_eval_final(vc.depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); + ARegion *ar = vc.ar; + RegionView3D *rv3d = ar->regiondata; - /* find the vert closest to 'mval' */ - const float mval_f[2] = {(float)mval[0], - (float)mval[1]}; + /* find the vert closest to 'mval' */ + const float mval_f[2] = {(float)mval[0], (float)mval[1]}; - VertPickData data = {NULL}; + VertPickData data = {NULL}; - ED_view3d_init_mats_rv3d(ob, rv3d); + ED_view3d_init_mats_rv3d(ob, rv3d); - if (me_eval == NULL) { - return false; - } + if (me_eval == NULL) { + return false; + } - /* setup data */ - data.mvert = me->mvert; - data.ar = ar; - data.mval_f = mval_f; - data.len_best = FLT_MAX; - data.v_idx_best = -1; + /* setup data */ + data.mvert = me->mvert; + data.ar = ar; + data.mval_f = mval_f; + data.len_best = FLT_MAX; + data.v_idx_best = -1; - BKE_mesh_foreach_mapped_vert(me_eval, ed_mesh_pick_vert__mapFunc, &data, MESH_FOREACH_NOP); + BKE_mesh_foreach_mapped_vert(me_eval, ed_mesh_pick_vert__mapFunc, &data, MESH_FOREACH_NOP); - if (data.v_idx_best == -1) { - return false; - } + if (data.v_idx_best == -1) { + return false; + } - *r_index = data.v_idx_best; - } + *r_index = data.v_idx_best; + } - return true; + return true; } - MDeformVert *ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve) { - if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH && ob->defbase.first) { - Mesh *me = ob->data; - BMesh *bm = me->edit_mesh->bm; - const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - - if (cd_dvert_offset != -1) { - BMVert *eve = BM_mesh_active_vert_get(bm); - - if (eve) { - if (r_eve) *r_eve = eve; - return BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - } - } - } - - if (r_eve) *r_eve = NULL; - return NULL; + if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH && ob->defbase.first) { + Mesh *me = ob->data; + BMesh *bm = me->edit_mesh->bm; + const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); + + if (cd_dvert_offset != -1) { + BMVert *eve = BM_mesh_active_vert_get(bm); + + if (eve) { + if (r_eve) + *r_eve = eve; + return BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + } + } + } + + if (r_eve) + *r_eve = NULL; + return NULL; } MDeformVert *ED_mesh_active_dvert_get_ob(Object *ob, int *r_index) { - Mesh *me = ob->data; - int index = BKE_mesh_mselect_active_get(me, ME_VSEL); - if (r_index) *r_index = index; - if (index == -1 || me->dvert == NULL) { - return NULL; - } - else { - return me->dvert + index; - } + Mesh *me = ob->data; + int index = BKE_mesh_mselect_active_get(me, ME_VSEL); + if (r_index) + *r_index = index; + if (index == -1 || me->dvert == NULL) { + return NULL; + } + else { + return me->dvert + index; + } } MDeformVert *ED_mesh_active_dvert_get_only(Object *ob) { - if (ob->type == OB_MESH) { - if (ob->mode & OB_MODE_EDIT) { - return ED_mesh_active_dvert_get_em(ob, NULL); - } - else { - return ED_mesh_active_dvert_get_ob(ob, NULL); - } - } - else { - return NULL; - } + if (ob->type == OB_MESH) { + if (ob->mode & OB_MODE_EDIT) { + return ED_mesh_active_dvert_get_em(ob, NULL); + } + else { + return ED_mesh_active_dvert_get_ob(ob, NULL); + } + } + else { + return NULL; + } } -void EDBM_mesh_stats_multi( - struct Object **objects, const uint objects_len, - int totelem[3], int totelem_sel[3]) +void EDBM_mesh_stats_multi(struct Object **objects, + const uint objects_len, + int totelem[3], + int totelem_sel[3]) { - if (totelem) { - totelem[0] = 0; - totelem[1] = 0; - totelem[2] = 0; - } - if (totelem_sel) { - totelem_sel[0] = 0; - totelem_sel[1] = 0; - totelem_sel[2] = 0; - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - if (totelem) { - totelem[0] += bm->totvert; - totelem[1] += bm->totedge; - totelem[2] += bm->totface; - } - if (totelem_sel) { - totelem_sel[0] += bm->totvertsel; - totelem_sel[1] += bm->totedgesel; - totelem_sel[2] += bm->totfacesel; - } - } + if (totelem) { + totelem[0] = 0; + totelem[1] = 0; + totelem[2] = 0; + } + if (totelem_sel) { + totelem_sel[0] = 0; + totelem_sel[1] = 0; + totelem_sel[2] = 0; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + if (totelem) { + totelem[0] += bm->totvert; + totelem[1] += bm->totedge; + totelem[2] += bm->totface; + } + if (totelem_sel) { + totelem_sel[0] += bm->totvertsel; + totelem_sel[1] += bm->totedgesel; + totelem_sel[2] += bm->totfacesel; + } + } } - void EDBM_mesh_elem_index_ensure_multi(Object **objects, const uint objects_len, const char htype) { - int elem_offset[4] = {0, 0, 0, 0}; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BM_mesh_elem_index_ensure_ex(bm, htype, elem_offset); - } + int elem_offset[4] = {0, 0, 0, 0}; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BM_mesh_elem_index_ensure_ex(bm, htype, elem_offset); + } } |