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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/mesh
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (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')
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt104
-rw-r--r--source/blender/editors/mesh/editface.c1060
-rw-r--r--source/blender/editors/mesh/editmesh_add.c1009
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c491
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c1575
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c1139
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c1262
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_screw.c308
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin.c291
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c1640
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c999
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c1538
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c4918
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c219
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c1130
-rw-r--r--source/blender/editors/mesh/editmesh_path.c1282
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c680
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_edgering.c465
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c224
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c1811
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c348
-rw-r--r--source/blender/editors/mesh/editmesh_select.c7811
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c2301
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c13785
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c1095
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c2256
-rw-r--r--source/blender/editors/mesh/mesh_data.c1651
-rw-r--r--source/blender/editors/mesh/mesh_intern.h39
-rw-r--r--source/blender/editors/mesh/mesh_mirror.c593
-rw-r--r--source/blender/editors/mesh/mesh_ops.c539
-rw-r--r--source/blender/editors/mesh/meshtools.c2250
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, &region_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, &region_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);
+ }
}