diff options
Diffstat (limited to 'source/blender/editors/mesh')
27 files changed, 6531 insertions, 2960 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index f1f0de3777e..5cd768b4fe3 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../blenkernel ../../blenlib ../../blentranslation + ../../depsgraph ../../bmesh ../../gpu ../../imbuf @@ -31,6 +32,7 @@ set(INC ../../makesrna ../../render/extern/include ../../windowmanager + ../../../../intern/clog ../../../../intern/guardedalloc ../../../../intern/glew-mx ) @@ -42,6 +44,7 @@ set(INC_SYS set(SRC editface.c editmesh_add.c + editmesh_add_manipulator.c editmesh_bevel.c editmesh_bisect.c editmesh_extrude.c @@ -53,6 +56,7 @@ set(SRC editmesh_knife_project.c editmesh_loopcut.c editmesh_path.c + editmesh_polybuild.c editmesh_rip.c editmesh_rip_edge.c editmesh_select.c @@ -67,18 +71,6 @@ set(SRC mesh_intern.h ) -if(WITH_GAMEENGINE) - add_definitions(-DWITH_GAMEENGINE) - - list(APPEND INC - ../../../../extern/recastnavigation - ) - - list(APPEND SRC - mesh_navmesh.c - ) -endif() - if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 899f1924222..405c19f1c1d 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -33,13 +33,14 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "DNA_meshdata_types.h" #include "DNA_mesh_types.h" #include "DNA_object_types.h" -#include "BKE_DerivedMesh.h" +#include "BKE_context.h" +#include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_mesh.h" -#include "BKE_context.h" #include "BIF_gl.h" @@ -51,7 +52,8 @@ #include "WM_types.h" #include "GPU_draw.h" -#include "GPU_buffers.h" + +#include "DEG_depsgraph.h" /* own include */ @@ -60,7 +62,7 @@ void paintface_flush_flags(Object *ob, short flag) { Mesh *me = BKE_mesh_from_object(ob); - DerivedMesh *dm = ob->derivedFinal; + Mesh *me_eval = ob->runtime.mesh_eval; MPoly *polys, *mp_orig; const int *index_array = NULL; int totpoly; @@ -79,14 +81,14 @@ void paintface_flush_flags(Object *ob, short flag) BKE_mesh_flush_select_from_polys(me); } - if (dm == NULL) + if (me_eval == NULL) return; /* Mesh polys => Final derived polys */ - if ((index_array = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX))) { - polys = dm->getPolyArray(dm); - totpoly = dm->getNumPolys(dm); + 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++) { @@ -99,10 +101,7 @@ void paintface_flush_flags(Object *ob, short flag) } } - if (flag & ME_HIDE) { - /* draw-object caches hidden faces, force re-generation T46867 */ - GPU_drawobject_free(dm); - } + BKE_mesh_batch_cache_dirty(me, BKE_MESH_BATCH_DIRTY_ALL); } void paintface_hide(Object *ob, const bool unselected) @@ -386,6 +385,7 @@ bool paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], b /* image window redraw */ paintface_flush_flags(ob, SELECT); + DEG_id_tag_update(ob->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views return true; @@ -475,8 +475,8 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten void paintvert_flush_flags(Object *ob) { Mesh *me = BKE_mesh_from_object(ob); - DerivedMesh *dm = ob->derivedFinal; - MVert *dm_mvert, *dm_mv; + Mesh *me_eval = ob->runtime.mesh_eval; + MVert *mvert_eval, *mv; const int *index_array = NULL; int totvert; int i; @@ -488,30 +488,32 @@ void paintvert_flush_flags(Object *ob) * since this could become slow for realtime updates (circle-select for eg) */ BKE_mesh_flush_select_from_verts(me); - if (dm == NULL) + if (me_eval == NULL) return; - index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); + index_array = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); - dm_mvert = dm->getVertArray(dm); - totvert = dm->getNumVerts(dm); + mvert_eval = me_eval->mvert; + totvert = me_eval->totvert; - dm_mv = dm_mvert; + mv = mvert_eval; if (index_array) { int orig_index; - for (i = 0; i < totvert; i++, dm_mv++) { + for (i = 0; i < totvert; i++, mv++) { orig_index = index_array[i]; if (orig_index != ORIGINDEX_NONE) { - dm_mv->flag = me->mvert[index_array[i]].flag; + mv->flag = me->mvert[index_array[i]].flag; } } } else { - for (i = 0; i < totvert; i++, dm_mv++) { - dm_mv->flag = me->mvert[i].flag; + for (i = 0; i < totvert; i++, mv++) { + mv->flag = me->mvert[i].flag; } } + + BKE_mesh_batch_cache_dirty(me, BKE_MESH_BATCH_DIRTY_ALL); } /* note: if the caller passes false to flush_flags, then they will need to run paintvert_flush_flags(ob) themselves */ void paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags) diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index 9bea203e67b..66ad057e3ec 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -60,31 +60,36 @@ /* ********* add primitive operators ************* */ +typedef struct MakePrimitiveData { + float mat[4][4]; + bool was_editmode; +} MakePrimitiveData; + static Object *make_prim_init( bContext *C, const char *idname, - float *dia, float mat[4][4], - bool *was_editmode, const float loc[3], const float rot[3], const unsigned int layer) + const float loc[3], const float rot[3], const unsigned int layer, + MakePrimitiveData *r_creation_data) { Object *obedit = CTX_data_edit_object(C); - *was_editmode = false; + 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, layer); /* create editmode */ ED_object_editmode_enter(C, EM_IGNORE_LAYER); /* rare cases the active layer is messed up */ - *was_editmode = true; + r_creation_data->was_editmode = true; } - *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); + ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); return obedit; } -static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, 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 = ((was_editmode == true) && (enter_editmode == false)); + 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. */ @@ -102,17 +107,17 @@ static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int static int add_primitive_plane_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; 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, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -122,12 +127,12 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op) 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, "radius"), mat, calc_uvs)) + 1, 1, RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -153,17 +158,17 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot) static int add_primitive_cube_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; 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, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -173,13 +178,13 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, "create_cube matrix=%m4 size=%f calc_uvs=%b", - mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs)) + creation_data.mat, RNA_float_get(op->ptr, "radius") * 2.0f, 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, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -211,13 +216,13 @@ static const EnumPropertyItem fill_type_items[] = { static int add_primitive_circle_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; int cap_end, cap_tri; unsigned int layer; - bool was_editmode; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); cap_end = RNA_enum_get(op->ptr, "fill_type"); @@ -225,7 +230,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -236,12 +241,12 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) 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, mat, calc_uvs)) + cap_end, cap_tri, creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -271,12 +276,12 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot) static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; unsigned int layer; - bool was_editmode; 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); @@ -284,7 +289,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -298,12 +303,12 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) RNA_float_get(op->ptr, "radius"), RNA_float_get(op->ptr, "radius"), cap_end, cap_tri, - RNA_float_get(op->ptr, "depth"), mat, calc_uvs)) + RNA_float_get(op->ptr, "depth"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -334,12 +339,12 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) static int add_primitive_cone_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; unsigned int layer; - bool was_editmode; 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); @@ -347,7 +352,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -358,12 +363,13 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) 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"), mat, calc_uvs)) + 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, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -395,17 +401,17 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot) static int add_primitive_grid_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; 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, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -417,12 +423,12 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) "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, "radius"), mat, calc_uvs)) + RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -454,22 +460,21 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot) static int add_primitive_monkey_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float mat[4][4]; float loc[3], rot[3]; float dia; bool enter_editmode; unsigned int layer; - bool was_editmode; 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, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, layer, &creation_data); dia = RNA_float_get(op->ptr, "radius"); - mul_mat3_m4_fl(mat, dia); + mul_mat3_m4_fl(creation_data.mat, dia); em = BKE_editmesh_from_object(obedit); @@ -479,12 +484,12 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_monkey matrix=%m4 calc_uvs=%b", mat, calc_uvs)) + "create_monkey matrix=%m4 calc_uvs=%b", creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -511,17 +516,17 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot) static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; 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, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -532,12 +537,12 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) 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, "size"), mat, calc_uvs)) + RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -567,17 +572,17 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; 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, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -588,12 +593,12 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) 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, "size"), mat, calc_uvs)) + RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_add_manipulator.c b/source/blender/editors/mesh/editmesh_add_manipulator.c new file mode 100644 index 00000000000..bfeccfe33a4 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_add_manipulator.c @@ -0,0 +1,426 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_add_manipulator.c + * \ingroup edmesh + * + * Creation manipulators. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_context.h" +#include "BKE_editmesh.h" + +#include "ED_manipulator_library.h" +#include "ED_mesh.h" +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_undo.h" +#include "ED_view3d.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_resources.h" + +#include "BLT_translation.h" + +#include "mesh_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Helper Functions + * \{ */ + +/** + * When we place a shape, pick a plane. + * + * 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]) +{ + + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(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, v3d, 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 ray_co[3], ray_no[3]; + if (ED_view3d_win_to_ray( + CTX_data_depsgraph(C), + ar, v3d, mval, + ray_co, ray_no, false)) + { + float plane[4]; + plane_from_point_normal_v3(plane, cursor_matrix[3], orient_matrix[2]); + float lambda; + if (isect_ray_plane_v3(ray_co, ray_no, plane, &lambda, true)) { + madd_v3_v3v3fl(r_location, ray_co, ray_no, lambda); + copy_m3_m3(r_rotation, orient_matrix); + return; + } + } + } + + /* fallback */ + copy_v3_v3(r_location, cursor_matrix[3]); + copy_m3_m3(r_rotation, orient_matrix); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Placement Manipulator + * \{ */ + +typedef struct ManipulatorPlacementGroup { + struct wmManipulator *cage; + struct { + bContext *context; + wmOperator *op; + PropertyRNA *prop_matrix; + } data; +} ManipulatorPlacementGroup; + +/** + * \warning Calling redo from property updates is not great. + * This is needed because changing the RNA doesn't cause a redo + * and we're not using operator UI which does just this. + */ +static void manipulator_placement_exec(ManipulatorPlacementGroup *man) +{ + wmOperator *op = man->data.op; + if (op == WM_operator_last_redo((bContext *)man->data.context)) { + ED_undo_operator_repeat((bContext *)man->data.context, op); + } +} + +static void manipulator_mesh_placement_update_from_op(ManipulatorPlacementGroup *man) +{ + wmOperator *op = man->data.op; + UNUSED_VARS(op); + /* For now don't read back from the operator. */ +#if 0 + RNA_property_float_get_array(op->ptr, man->data.prop_matrix, &man->cage->matrix_offset[0][0]); +#endif +} + +/* translate callbacks */ +static void manipulator_placement_prop_matrix_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + ManipulatorPlacementGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + float *value = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + UNUSED_VARS_NDEBUG(mpr_prop); + + if (value_p != man->cage->matrix_offset) { + mul_m4_m4m4(value_p, man->cage->matrix_basis, man->cage->matrix_offset); + RNA_property_float_get_array(op->ptr, man->data.prop_matrix, value); + } +} + +static void manipulator_placement_prop_matrix_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value) +{ + ManipulatorPlacementGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + + BLI_assert(mpr_prop->type->array_length == 16); + UNUSED_VARS_NDEBUG(mpr_prop); + + float mat[4][4]; + mul_m4_m4m4(mat, man->cage->matrix_basis, value); + + if (is_negative_m4(mat)) { + negate_mat3_m4(mat); + } + + RNA_property_float_set_array(op->ptr, man->data.prop_matrix, &mat[0][0]); + + manipulator_placement_exec(man); +} + +static bool manipulator_mesh_placement_poll(const bContext *C, wmManipulatorGroupType *wgt) +{ + wmOperator *op = WM_operator_last_redo(C); + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_manipulator")) { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; + } + return true; +} + +static void manipulator_mesh_placement_modal_from_setup( + const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorPlacementGroup *man = mgroup->customdata; + + /* Initial size. */ + { + wmManipulator *mpr = man->cage; + zero_m4(mpr->matrix_offset); + + /* TODO: support zero scaled matrix in 'MANIPULATOR_WT_cage_3d'. */ + mpr->matrix_offset[0][0] = 0.01; + mpr->matrix_offset[1][1] = 0.01; + mpr->matrix_offset[2][2] = 0.01; + mpr->matrix_offset[3][3] = 1.0f; + } + + /* Start off dragging. */ + { + wmWindow *win = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + wmManipulator *mpr = man->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(mpr->matrix_basis, mat3); + copy_v3_v3(mpr->matrix_basis[3], location); + } + + if (1) { + wmManipulatorMap *mmap = mgroup->parent_mmap; + WM_manipulator_modal_set_from_setup( + mmap, (bContext *)C, man->cage, ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, win->eventstate); + } + } +} + +static void manipulator_mesh_placement_setup(const bContext *C, wmManipulatorGroup *mgroup) +{ + wmOperator *op = WM_operator_last_redo(C); + + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_manipulator")) { + return; + } + + struct ManipulatorPlacementGroup *man = MEM_callocN(sizeof(ManipulatorPlacementGroup), __func__); + mgroup->customdata = man; + + const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_3d", true); + + man->cage = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->cage->color); + + RNA_enum_set(man->cage->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_SIGNED); + + WM_manipulator_set_flag(man->cage, WM_MANIPULATOR_DRAW_VALUE, true); + + man->data.context = (bContext *)C; + man->data.op = op; + man->data.prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); + + manipulator_mesh_placement_update_from_op(man); + + /* Setup property callbacks */ + { + WM_manipulator_target_property_def_func( + man->cage, "matrix", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_placement_prop_matrix_get, + .value_set_fn = manipulator_placement_prop_matrix_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + } + + manipulator_mesh_placement_modal_from_setup(C, mgroup); +} + +static void manipulator_mesh_placement_draw_prepare( + const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + ManipulatorPlacementGroup *man = mgroup->customdata; + if (man->data.op->next) { + man->data.op = WM_operator_last_redo((bContext *)man->data.context); + } + manipulator_mesh_placement_update_from_op(man); +} + +static void MESH_WGT_add_bounds(struct wmManipulatorGroupType *wgt) +{ + wgt->name = "Mesh Add Bounds"; + wgt->idname = "MESH_WGT_add_bounds"; + + wgt->flag = WM_MANIPULATORGROUPTYPE_3D; + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + + wgt->poll = manipulator_mesh_placement_poll; + wgt->setup = manipulator_mesh_placement_setup; + wgt->draw_prepare = manipulator_mesh_placement_draw_prepare; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Cube Manipulator-Operator + * + * For now we use a separate operator to add a cube, + * we can try to merge then however they are invoked differently + * and share the same BMesh creation code. + * \{ */ + + +static int add_primitive_cube_manipulator_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 manipulator 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_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + View3D *v3d = CTX_wm_view3d(C); + + int ret = add_primitive_cube_manipulator_exec(C, op); + if (ret & OPERATOR_FINISHED) { + /* Setup manipulators */ + if (v3d && (v3d->twflag & V3D_MANIPULATOR_DRAW)) { + ARegion *ar = CTX_wm_region(C); + wmManipulatorMap *mmap = ar->manipulator_map; + wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find("MESH_WGT_add_bounds", false); + wmManipulatorGroup *mgroup = WM_manipulatormap_group_find_ptr(mmap, wgt); + if (mgroup != NULL) { + ManipulatorPlacementGroup *man = mgroup->customdata; + man->data.op = op; + manipulator_mesh_placement_modal_from_setup(C, mgroup); + } + else { + WM_manipulator_group_type_ensure_ptr(wgt); + } + } + } + + return ret; +} + +void MESH_OT_primitive_cube_add_manipulator(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Cube"; + ot->description = "Construct a cube mesh"; + ot->idname = "MESH_OT_primitive_cube_add_manipulator"; + + /* api callbacks */ + ot->invoke = add_primitive_cube_manipulator_invoke; + ot->exec = add_primitive_cube_manipulator_exec; + ot->poll = ED_operator_editmesh_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + 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); + + WM_manipulatorgrouptype_append(MESH_WGT_add_bounds); +} + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index e44a43c4c3a..2041852c9ee 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -37,6 +37,7 @@ #include "BKE_global.h" #include "BKE_editmesh.h" #include "BKE_unit.h" +#include "BKE_layer.h" #include "RNA_define.h" #include "RNA_access.h" @@ -77,17 +78,24 @@ static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f, typedef struct { 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]; float shift_value[NUM_VALUE_KINDS]; /* The current value when shift is pressed. Negative when shift not active. */ bool is_modal; + BevelObjectStore *ob_store; + uint ob_store_len; + /* modal only */ float mcenter[2]; - BMBackup mesh_backup; void *draw_handle_pixel; - short twtype; + short twflag; 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; @@ -128,24 +136,35 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op) static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) { - Object *obedit = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); BevelData *opdata; + ViewLayer *view_layer = CTX_data_view_layer(C); float pixels_per_inch; int i; - if (em->bm->totvertsel == 0) { - return false; - } - if (is_modal) { RNA_float_set(op->ptr, "offset", 0.0f); } op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator"); + uint objects_used_len = 0; + + { + uint ob_store_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &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]; + 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->em = em; opdata->is_modal = is_modal; opdata->value_mode = OFFSET_VALUE; opdata->segments = (float) RNA_int_get(op->ptr, "segments"); @@ -174,14 +193,16 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); - opdata->mesh_backup = EDBM_redo_state_store(em); + 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->twtype = v3d->twtype; - v3d->twtype = 0; + opdata->twflag = v3d->twflag; + v3d->twflag = 0; } } @@ -191,8 +212,10 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) static bool edbm_bevel_calc(wmOperator *op) { BevelData *opdata = op->customdata; - BMEditMesh *em = opdata->em; + BMEditMesh *em; BMOperator bmop; + bool changed = false; + const float offset = RNA_float_get(op->ptr, "offset"); const int offset_type = RNA_enum_get(op->ptr, "offset_type"); const int segments = RNA_int_get(op->ptr, "segments"); @@ -202,40 +225,45 @@ static bool edbm_bevel_calc(wmOperator *op) int material = RNA_int_get(op->ptr, "material"); const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide"); - /* revert to original mesh */ - if (opdata->is_modal) { - EDBM_redo_state_restore(opdata->mesh_backup, em, false); - } - if (em->ob) { - material = CLAMPIS(material, -1, em->ob->totcol - 1); - } + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + em = opdata->ob_store[ob_index].em; - 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", - BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, - clamp_overlap, material, loop_slide); + /* revert to original mesh */ + if (opdata->is_modal) { + EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false); + } - BMO_op_exec(em->bm, &bmop); + if (em->ob) { + material = CLAMPIS(material, -1, em->ob->totcol - 1); + } - 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); - } + 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", + BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, + clamp_overlap, material, loop_slide); - /* no need to de-select existing geometry */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - return false; - } + BMO_op_exec(em->bm, &bmop); - EDBM_mesh_normals_update(opdata->em); + 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_update_generic(opdata->em, true, true); + EDBM_mesh_normals_update(em); - return true; + EDBM_update_generic(em, true, true); + changed = true; + } + return changed; } static void edbm_bevel_exit(bContext *C, wmOperator *op) @@ -251,14 +279,17 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op) if (opdata->is_modal) { View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); - EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); + 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->twtype = opdata->twtype; + v3d->twflag = opdata->twflag; } G.moving = 0; } - MEM_freeN(opdata); + MEM_SAFE_FREE(opdata->ob_store); + MEM_SAFE_FREE(op->customdata); op->customdata = NULL; } @@ -266,8 +297,10 @@ static void edbm_bevel_cancel(bContext *C, wmOperator *op) { BevelData *opdata = op->customdata; if (opdata->is_modal) { - EDBM_redo_state_free(&opdata->mesh_backup, opdata->em, true); - EDBM_update_generic(opdata->em, false, true); + 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); diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index 3a9e278f039..ee06f7abd2b 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -50,9 +50,17 @@ #include "ED_screen.h" #include "ED_view3d.h" +#include "UI_resources.h" #include "mesh_intern.h" /* own include */ +#define USE_MANIPULATOR + +#ifdef USE_MANIPULATOR +#include "ED_manipulator_library.h" +#include "ED_undo.h" +#endif + static int mesh_bisect_exec(bContext *C, wmOperator *op); /* -------------------------------------------------------------------- */ @@ -62,7 +70,7 @@ typedef struct { /* modal only */ BMBackup mesh_backup; bool is_first; - short twtype; + short twflag; } BisectData; static bool mesh_bisect_interactive_calc( @@ -148,8 +156,8 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* misc other vars */ G.moving = G_TRANSFORM_EDIT; - opdata->twtype = v3d->twtype; - v3d->twtype = 0; + opdata->twflag = v3d->twflag; + v3d->twflag = 0; /* initialize modal callout */ ED_area_headerprint(CTX_wm_area(C), IFACE_("LMB: Click and drag to draw cut line")); @@ -161,7 +169,7 @@ static void edbm_bisect_exit(bContext *C, BisectData *opdata) { View3D *v3d = CTX_wm_view3d(C); EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); - v3d->twtype = opdata->twtype; + v3d->twflag = opdata->twflag; G.moving = 0; } @@ -186,6 +194,16 @@ static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event) if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) { edbm_bisect_exit(C, &opdata_back); + +#ifdef USE_MANIPULATOR + /* Setup manipulators */ + { + View3D *v3d = CTX_wm_view3d(C); + if (v3d && (v3d->twflag & V3D_MANIPULATOR_DRAW)) { + WM_manipulator_group_type_ensure("MESH_WGT_bisect"); + } + } +#endif } return ret; @@ -225,7 +243,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op) RNA_property_float_get_array(op->ptr, prop_plane_co, plane_co); } else { - copy_v3_v3(plane_co, ED_view3d_cursor3d_get(scene, v3d)); + copy_v3_v3(plane_co, ED_view3d_cursor3d_get(scene, v3d)->location); RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); } @@ -315,6 +333,9 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op) } } +#ifdef USE_MANIPULATOR +static void MESH_WGT_bisect(struct wmManipulatorGroupType *wgt); +#endif void MESH_OT_bisect(struct wmOperatorType *ot) { @@ -350,4 +371,331 @@ void MESH_OT_bisect(struct wmOperatorType *ot) RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Axis Threshold", "", 0.00001, 0.1); WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); + +#ifdef USE_MANIPULATOR + WM_manipulatorgrouptype_append(MESH_WGT_bisect); +#endif +} + + +#ifdef USE_MANIPULATOR + +/* -------------------------------------------------------------------- */ + +/** \name Bisect Manipulator + * \{ */ + +typedef struct ManipulatorGroup { + /* Arrow to change plane depth. */ + struct wmManipulator *translate_z; + /* Translate XYZ */ + struct wmManipulator *translate_c; + /* For grabbing the manipulator and moving freely. */ + struct wmManipulator *rotate_c; + + /* 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; +} ManipulatorGroup; + +/** + * XXX. calling redo from property updates is not great. + * This is needed because changing the RNA doesn't cause a redo + * and we're not using operator UI which does just this. + */ +static void manipulator_bisect_exec(ManipulatorGroup *man) +{ + wmOperator *op = man->data.op; + if (op == WM_operator_last_redo((bContext *)man->data.context)) { + ED_undo_operator_repeat((bContext *)man->data.context, op); + } +} + +static void manipulator_mesh_bisect_update_from_op(ManipulatorGroup *man) +{ + wmOperator *op = man->data.op; + + float plane_co[3], plane_no[3]; + + RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co); + RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no); + + WM_manipulator_set_matrix_location(man->translate_z, plane_co); + WM_manipulator_set_matrix_location(man->rotate_c, plane_co); + /* translate_c location comes from the property. */ + + WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_z, plane_no); + + WM_manipulator_set_scale(man->translate_c, 0.2); + + RegionView3D *rv3d = ED_view3d_context_rv3d(man->data.context); + if (rv3d) { + normalize_v3_v3(man->data.rotate_axis, rv3d->viewinv[2]); + normalize_v3_v3(man->data.rotate_up, rv3d->viewinv[1]); + + /* ensure its orthogonal */ + project_plane_normalized_v3_v3v3(man->data.rotate_up, man->data.rotate_up, man->data.rotate_axis); + normalize_v3(man->data.rotate_up); + + WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_c, plane_no); + + float plane_no_cross[3]; + cross_v3_v3v3(plane_no_cross, plane_no, man->data.rotate_axis); + + WM_manipulator_set_matrix_offset_rotation_from_yz_axis(man->rotate_c, plane_no_cross, man->data.rotate_axis); + RNA_enum_set(man->rotate_c->ptr, "draw_options", + ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR | + ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y); + } +} + +/* depth callbacks */ +static void manipulator_bisect_prop_depth_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + ManipulatorGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + + float plane_co[3], plane_no[3]; + RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co); + RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no); + + value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, mpr->matrix_basis[3]); +} + +static void manipulator_bisect_prop_depth_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + ManipulatorGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + const float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + + float plane_co[3], plane[4]; + RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co); + RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane); + normalize_v3(plane); + + plane[3] = -value[0] - dot_v3v3(plane, mpr->matrix_basis[3]); + + /* Keep our location, may be offset simply to be inside the viewport. */ + closest_to_plane_normalized_v3(plane_co, plane, plane_co); + + RNA_property_float_set_array(op->ptr, man->data.prop_plane_co, plane_co); + + manipulator_bisect_exec(man); +} + +/* translate callbacks */ +static void manipulator_bisect_prop_translate_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + ManipulatorGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + + BLI_assert(mpr_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(mpr_prop); + + RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, value_p); +} + +static void manipulator_bisect_prop_translate_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + ManipulatorGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + + BLI_assert(mpr_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(mpr_prop); + + RNA_property_float_set_array(op->ptr, man->data.prop_plane_co, value_p); + + manipulator_bisect_exec(man); +} + +/* angle callbacks */ +static void manipulator_bisect_prop_angle_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + ManipulatorGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + + float plane_no[4]; + RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no); + normalize_v3(plane_no); + + float plane_no_proj[3]; + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis); + + if (!is_zero_v3(plane_no_proj)) { + const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis); + value[0] = angle; + } + else { + value[0] = 0.0f; + } +} + +static void manipulator_bisect_prop_angle_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + ManipulatorGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + const float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + + float plane_no[4]; + RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no); + normalize_v3(plane_no); + + float plane_no_proj[3]; + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis); + + if (!is_zero_v3(plane_no_proj)) { + const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis); + const float angle_delta = angle - angle_compat_rad(value[0], angle); + if (angle_delta != 0.0f) { + float mat[3][3]; + axis_angle_normalized_to_mat3(mat, man->data.rotate_axis, angle_delta); + mul_m3_v3(mat, plane_no); + + /* re-normalize - seems acceptable */ + RNA_property_float_set_array(op->ptr, man->data.prop_plane_no, plane_no); + + manipulator_bisect_exec(man); + } + } +} + +static bool manipulator_mesh_bisect_poll(const bContext *C, wmManipulatorGroupType *wgt) +{ + wmOperator *op = WM_operator_last_redo(C); + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; + } + return true; } + +static void manipulator_mesh_bisect_setup(const bContext *C, wmManipulatorGroup *mgroup) +{ + wmOperator *op = WM_operator_last_redo(C); + + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) { + return; + } + + struct ManipulatorGroup *man = MEM_callocN(sizeof(ManipulatorGroup), __func__); + mgroup->customdata = man; + + const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true); + const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", true); + const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true); + + man->translate_z = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + man->translate_c = WM_manipulator_new_ptr(wt_grab, mgroup, NULL); + man->rotate_c = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->translate_z->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->translate_c->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_SECONDARY, man->rotate_c->color); + + RNA_enum_set(man->translate_z->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_NORMAL); + RNA_enum_set(man->translate_c->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_RING_2D); + + WM_manipulator_set_flag(man->translate_c, WM_MANIPULATOR_DRAW_VALUE, true); + WM_manipulator_set_flag(man->rotate_c, WM_MANIPULATOR_DRAW_VALUE, true); + + { + man->data.context = (bContext *)C; + man->data.op = op; + man->data.prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co"); + man->data.prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no"); + } + + manipulator_mesh_bisect_update_from_op(man); + + /* Setup property callbacks */ + { + WM_manipulator_target_property_def_func( + man->translate_z, "offset", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_bisect_prop_depth_get, + .value_set_fn = manipulator_bisect_prop_depth_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + WM_manipulator_target_property_def_func( + man->translate_c, "offset", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_bisect_prop_translate_get, + .value_set_fn = manipulator_bisect_prop_translate_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + WM_manipulator_target_property_def_func( + man->rotate_c, "offset", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_bisect_prop_angle_get, + .value_set_fn = manipulator_bisect_prop_angle_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + } +} + +static void manipulator_mesh_bisect_draw_prepare( + const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man = mgroup->customdata; + if (man->data.op->next) { + man->data.op = WM_operator_last_redo((bContext *)man->data.context); + } + manipulator_mesh_bisect_update_from_op(man); +} + +static void MESH_WGT_bisect(struct wmManipulatorGroupType *wgt) +{ + wgt->name = "Mesh Bisect"; + wgt->idname = "MESH_WGT_bisect"; + + wgt->flag = WM_MANIPULATORGROUPTYPE_3D; + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + + wgt->poll = manipulator_mesh_bisect_poll; + wgt->setup = manipulator_mesh_bisect_setup; + wgt->draw_prepare = manipulator_mesh_bisect_draw_prepare; +} + +/** \} */ + +#endif /* USE_MANIPULATOR */ diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 9467c545bbf..4841de3c856 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -35,22 +35,34 @@ #include "BLI_math.h" #include "BLI_listbase.h" +#include "BKE_layer.h" #include "BKE_context.h" #include "BKE_report.h" #include "BKE_editmesh.h" +#include "BKE_global.h" +#include "BKE_idprop.h" #include "RNA_define.h" #include "RNA_access.h" +#include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "ED_mesh.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_view3d.h" +#include "ED_manipulator_library.h" + +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" #include "mesh_intern.h" /* own include */ +#define USE_MANIPULATOR + /* -------------------------------------------------------------------- */ /** \name Extrude Internal Utilities * \{ */ @@ -283,36 +295,44 @@ static bool edbm_extrude_ex( static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); 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; - /* dvec */ - normalize_v3_v3_length(dvec, rv3d->persinv[2], offs); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - /* base correction */ - copy_m3_m4(bmat, obedit->obmat); - invert_m3_m3(tmat, bmat); - mul_m3_v3(tmat, dvec); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - for (a = 0; a < steps; a++) { - edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false); + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMO_op_callf( - em->bm, BMO_FLAG_DEFAULTS, - "translate vec=%v verts=%hv", - dvec, BM_ELEM_SELECT); - } + /* 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); + + for (a = 0; a < steps; a++) { + edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false); + + 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); return OPERATOR_FINISHED; } @@ -338,6 +358,326 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Manipulator + * \{ */ + +#ifdef USE_MANIPULATOR + +const float extrude_button_scale = 0.15f; +const float extrude_button_offset_scale = 1.5f; +const float extrude_arrow_scale = 1.0f; +const float extrude_arrow_xyz_axis_scale = 1.0f; +const float extrude_arrow_normal_axis_scale = 1.75f; + +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, +}; + +typedef struct ManipulatorExtrudeGroup { + + /* XYZ & normal. */ + struct wmManipulator *invoke_xyz_no[4]; + struct wmManipulator *adjust_xyz_no[5]; + + struct { + float normal_mat3[3][3]; /* use Z axis for normal. */ + int orientation_type; + } data; + + wmOperatorType *ot_extrude; +} ManipulatorExtrudeGroup; + +static void manipulator_mesh_extrude_orientation_matrix_set( + struct ManipulatorExtrudeGroup *man, const float mat[3][3]) +{ + for (int i = 0; i < 3; i++) { + /* Set orientation without location. */ + for (int j = 0; j < 3; j++) { + copy_v3_v3(man->adjust_xyz_no[i]->matrix_basis[j], mat[j]); + } + /* nop when (i == 2). */ + swap_v3_v3(man->adjust_xyz_no[i]->matrix_basis[i], man->adjust_xyz_no[i]->matrix_basis[2]); + /* Orient to normal gives generally less awkward results. */ + if (man->data.orientation_type != V3D_MANIP_NORMAL) { + if (dot_v3v3(man->adjust_xyz_no[i]->matrix_basis[2], man->data.normal_mat3[2]) < 0.0f) { + negate_v3(man->adjust_xyz_no[i]->matrix_basis[2]); + } + } + mul_v3_v3fl( + man->invoke_xyz_no[i]->matrix_offset[3], + man->adjust_xyz_no[i]->matrix_basis[2], + (extrude_arrow_xyz_axis_scale * extrude_button_offset_scale) / extrude_button_scale); + } +} + +static bool manipulator_mesh_extrude_poll(const bContext *C, wmManipulatorGroupType *wgt) +{ + ScrArea *sa = CTX_wm_area(C); + bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL; + if ((tref_rt == NULL) || + !STREQ(wgt->idname, tref_rt->manipulator_group) || + !ED_operator_editmesh_view3d((bContext *)C)) + { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; + } + return true; +} + +static void manipulator_mesh_extrude_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct ManipulatorExtrudeGroup *man = MEM_callocN(sizeof(ManipulatorExtrudeGroup), __func__); + mgroup->customdata = man; + + const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true); + const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_button_2d", true); + + for (int i = 0; i < 4; i++) { + man->adjust_xyz_no[i] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + man->invoke_xyz_no[i] = WM_manipulator_new_ptr(wt_grab, mgroup, NULL); + man->invoke_xyz_no[i]->flag |= WM_MANIPULATOR_DRAW_OFFSET_SCALE; + } + + { + PropertyRNA *prop = RNA_struct_find_property(man->invoke_xyz_no[3]->ptr, "shape"); + for (int i = 0; i < 4; i++) { + RNA_property_string_set_bytes( + man->invoke_xyz_no[i]->ptr, prop, + (const char *)shape_plus, ARRAY_SIZE(shape_plus)); + } + } + + man->ot_extrude = WM_operatortype_find("MESH_OT_extrude_context_move", true); + + for (int i = 0; i < 3; i++) { + UI_GetThemeColor3fv(TH_AXIS_X + i, man->invoke_xyz_no[i]->color); + UI_GetThemeColor3fv(TH_AXIS_X + i, man->adjust_xyz_no[i]->color); + } + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->invoke_xyz_no[3]->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->adjust_xyz_no[3]->color); + + for (int i = 0; i < 4; i++) { + WM_manipulator_set_scale(man->invoke_xyz_no[i], extrude_button_scale); + WM_manipulator_set_scale(man->adjust_xyz_no[i], extrude_arrow_scale); + } + WM_manipulator_set_scale(man->adjust_xyz_no[3], extrude_arrow_normal_axis_scale); + + for (int i = 0; i < 4; i++) { + } + + for (int i = 0; i < 4; i++) { + WM_manipulator_set_flag(man->adjust_xyz_no[i], WM_MANIPULATOR_DRAW_VALUE, true); + } + + /* XYZ & normal axis extrude. */ + for (int i = 0; i < 4; i++) { + PointerRNA *ptr = WM_manipulator_operator_set(man->invoke_xyz_no[i], 0, man->ot_extrude, NULL); + { + int constraint[3] = {0, 0, 0}; + constraint[MIN2(i, 2)] = 1; + PointerRNA macroptr = RNA_pointer_get(ptr, "TRANSFORM_OT_translate"); + RNA_boolean_set(¯optr, "release_confirm", true); + RNA_boolean_set_array(¯optr, "constraint_axis", constraint); + } + } + + /* Adjust extrude. */ + for (int i = 0; i < 4; i++) { + PointerRNA *ptr = WM_manipulator_operator_set(man->adjust_xyz_no[i], 0, man->ot_extrude, NULL); + { + int constraint[3] = {0, 0, 0}; + constraint[MIN2(i, 2)] = 1; + PointerRNA macroptr = RNA_pointer_get(ptr, "TRANSFORM_OT_translate"); + RNA_boolean_set(¯optr, "release_confirm", true); + RNA_boolean_set_array(¯optr, "constraint_axis", constraint); + } + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(man->adjust_xyz_no[i], 0); + mpop->is_redo = true; + } +} + +static void manipulator_mesh_extrude_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorExtrudeGroup *man = mgroup->customdata; + + for (int i = 0; i < 4; i++) { + WM_manipulator_set_flag(man->invoke_xyz_no[i], WM_MANIPULATOR_HIDDEN, true); + WM_manipulator_set_flag(man->adjust_xyz_no[i], WM_MANIPULATOR_HIDDEN, true); + } + + if (G.moving) { + return; + } + + Scene *scene = CTX_data_scene(C); + man->data.orientation_type = scene->orientation_type; + bool use_normal = (man->data.orientation_type != V3D_MANIP_NORMAL); + const int axis_len_used = use_normal ? 4 : 3; + + struct TransformBounds tbounds; + + if (use_normal) { + struct TransformBounds tbounds_normal; + if (!ED_transform_calc_manipulator_stats( + C, &(struct TransformCalcParams){ + .orientation_type = V3D_MANIP_NORMAL + 1, + }, &tbounds_normal)) + { + unit_m3(tbounds_normal.axis); + } + copy_m3_m3(man->data.normal_mat3, tbounds_normal.axis); + } + + /* TODO(campbell): run second since this modifies the 3D view, it should not. */ + if (!ED_transform_calc_manipulator_stats( + C, &(struct TransformCalcParams){ + .orientation_type = man->data.orientation_type + 1, + }, &tbounds)) + { + return; + } + + /* Main axis is normal. */ + if (!use_normal) { + copy_m3_m3(man->data.normal_mat3, tbounds.axis); + } + + /* Offset the add icon. */ + mul_v3_v3fl( + man->invoke_xyz_no[3]->matrix_offset[3], + man->data.normal_mat3[2], + (extrude_arrow_normal_axis_scale * extrude_button_offset_scale) / extrude_button_scale); + + /* Needed for normal orientation. */ + manipulator_mesh_extrude_orientation_matrix_set(man, tbounds.axis); + if (use_normal) { + copy_m4_m3(man->adjust_xyz_no[3]->matrix_basis, man->data.normal_mat3); + } + + /* Location. */ + for (int i = 0; i < axis_len_used; i++) { + WM_manipulator_set_matrix_location(man->invoke_xyz_no[i], tbounds.center); + WM_manipulator_set_matrix_location(man->adjust_xyz_no[i], tbounds.center); + } + + wmOperator *op = WM_operator_last_redo(C); + bool has_redo = (op && op->type == man->ot_extrude); + + /* Un-hide. */ + for (int i = 0; i < axis_len_used; i++) { + WM_manipulator_set_flag(man->invoke_xyz_no[i], WM_MANIPULATOR_HIDDEN, false); + WM_manipulator_set_flag(man->adjust_xyz_no[i], WM_MANIPULATOR_HIDDEN, !has_redo); + } + + /* Operator properties. */ + if (use_normal) { + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(man->invoke_xyz_no[3], 0); + PointerRNA macroptr = RNA_pointer_get(&mpop->ptr, "TRANSFORM_OT_translate"); + RNA_enum_set(¯optr, "constraint_orientation", V3D_MANIP_NORMAL); + } + + /* Redo with current settings. */ + if (has_redo) { + wmOperator *op_transform = op->macro.last; + float value[4]; + RNA_float_get_array(op_transform->ptr, "value", value); + int constraint_axis[3]; + RNA_boolean_get_array(op_transform->ptr, "constraint_axis", constraint_axis); + int orientation_type = RNA_enum_get(op_transform->ptr, "constraint_orientation"); + + /* We could also access this from 'ot->last_properties' */ + for (int i = 0; i < 4; i++) { + if ((i != 3) ? + (orientation_type == man->data.orientation_type && constraint_axis[i]) : + (orientation_type == V3D_MANIP_NORMAL && constraint_axis[2])) + { + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(man->adjust_xyz_no[i], 0); + + PointerRNA macroptr = RNA_pointer_get(&mpop->ptr, "TRANSFORM_OT_translate"); + + RNA_float_set_array(¯optr, "value", value); + RNA_boolean_set_array(¯optr, "constraint_axis", constraint_axis); + RNA_enum_set(¯optr, "constraint_orientation", orientation_type); + } + else { + /* TODO(campbell): ideally we could adjust all, + * this is complicated by how operator redo and the transform macro works. */ + WM_manipulator_set_flag(man->adjust_xyz_no[i], WM_MANIPULATOR_HIDDEN, true); + } + } + } + + for (int i = 0; i < 4; i++) { + RNA_enum_set( + man->invoke_xyz_no[i]->ptr, + "draw_options", + (man->adjust_xyz_no[i]->flag & WM_MANIPULATOR_HIDDEN) ? + ED_MANIPULATOR_BUTTON_SHOW_HELPLINE : 0); + } +} + +static void manipulator_mesh_extrude_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorExtrudeGroup *man = mgroup->customdata; + switch (man->data.orientation_type) { + case V3D_MANIP_VIEW: + { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + float mat[3][3]; + copy_m3_m4(mat, rv3d->viewinv); + normalize_m3(mat); + manipulator_mesh_extrude_orientation_matrix_set(man, mat); + break; + } + } +} + +static void manipulator_mesh_extrude_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + ARegion *ar = CTX_wm_region(C); + + /* Subscribe to view properties */ + wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { + .owner = ar, + .user_data = mgroup->parent_mmap, + .notify = WM_manipulator_do_msg_notify_tag_refresh, + }; + + { + WM_msg_subscribe_rna_anon_prop(mbus, Scene, transform_orientation, &msg_sub_value_mpr_tag_refresh); + } + +} + +static void MESH_WGT_extrude(struct wmManipulatorGroupType *wgt) +{ + wgt->name = "Mesh Extrude"; + wgt->idname = "MESH_WGT_extrude"; + + wgt->flag = WM_MANIPULATORGROUPTYPE_3D; + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + + wgt->poll = manipulator_mesh_extrude_poll; + wgt->setup = manipulator_mesh_extrude_setup; + wgt->refresh = manipulator_mesh_extrude_refresh; + wgt->draw_prepare = manipulator_mesh_extrude_draw_prepare; + wgt->message_subscribe = manipulator_mesh_extrude_message_subscribe; +} + +#endif /* USE_MANIPULATOR */ + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Extrude Operator * \{ */ @@ -391,18 +731,28 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) /* extrude without transform */ static int edbm_extrude_region_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - 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); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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_update_generic(em, true, true); + 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; } @@ -427,17 +777,83 @@ void MESH_OT_extrude_region(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Extrude Context Operator + * + * Guess what to do based on selection. + * \{ */ + +/* 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, &objects_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"; + + /* api callbacks */ + ot->exec = edbm_extrude_context_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); + +#ifdef USE_MANIPULATOR + WM_manipulatorgrouptype_append(MESH_WGT_extrude); +#endif +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Extrude Verts Operator * \{ */ static int edbm_extrude_verts_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_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_verts_indiv(em, op, BM_ELEM_SELECT); + edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); - EDBM_update_generic(em, true, true); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -468,12 +884,22 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) static int edbm_extrude_edges_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_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); + edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT); - EDBM_update_generic(em, true, true); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -504,12 +930,22 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) static int edbm_extrude_faces_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_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; + } - edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT); + edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT); - EDBM_update_generic(em, true, true); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -671,7 +1107,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w BM_ELEM_SELECT, ofs); } else { - const float *cursor = ED_view3d_cursor3d_get(vc.scene, vc.v3d); + const float *cursor = ED_view3d_cursor3d_get(vc.scene, vc.v3d)->location; BMOperator bmop; BMOIter oiter; @@ -723,4 +1159,3 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) } /** \} */ - diff --git a/source/blender/editors/mesh/editmesh_extrude_screw.c b/source/blender/editors/mesh/editmesh_extrude_screw.c index ffbbae60949..3214f28412a 100644 --- a/source/blender/editors/mesh/editmesh_extrude_screw.c +++ b/source/blender/editors/mesh/editmesh_extrude_screw.c @@ -25,17 +25,20 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/editors/mesh/editmesh_extrude_spin.c +/** \file blender/editors/mesh/editmesh_extrude_screw.c * \ingroup edmesh */ +#include "MEM_guardedalloc.h" + #include "DNA_object_types.h" #include "BLI_math.h" #include "BKE_context.h" -#include "BKE_report.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" +#include "BKE_report.h" #include "RNA_define.h" #include "RNA_access.h" @@ -46,6 +49,8 @@ #include "ED_screen.h" #include "ED_view3d.h" + + #include "mesh_intern.h" /* own include */ /* -------------------------------------------------------------------- */ @@ -54,84 +59,110 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; BMEdge *eed; BMVert *eve, *v1, *v2; BMIter iter, eiter; - BMOperator spinop; 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); - if (is_zero_v3(axis)) { - BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis"); - return OPERATOR_CANCELLED; - } + 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, &objects_len); - /* find two vertices with valence count == 1, more or less is wrong */ - v1 = NULL; - v2 = NULL; + 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_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 (bm->totvertsel < 2) { + if (bm->totvertsel == 0) { + objects_empty_len++; } + continue; } - if (valence == 1) { - if (v1 == NULL) { - v1 = eve; - } - else if (v2 == NULL) { - v2 = eve; + 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++; + } } - else { - v1 = NULL; - break; + + if (valence == 1) { + if (v1 == NULL) { + v1 = eve; + } + else if (v2 == NULL) { + v2 = eve; + } + else { + v1 = NULL; + break; + } } } - } - if (v1 == NULL || v2 == NULL) { - BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too"); - return OPERATOR_CANCELLED; - } + if (v1 == NULL || v2 == NULL) { + failed_vertices_len++; + continue; + } - copy_v3_v3(nor, obedit->obmat[2]); + 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); + /* 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); + if (dot_v3v3(nor, dvec) > 0.0f) + negate_v3(dvec); - 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)) - { - return OPERATOR_CANCELLED; - } - 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)) { - return OPERATOR_CANCELLED; + 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); - EDBM_update_generic(em, true, true); + 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; } @@ -146,7 +177,7 @@ static int edbm_screw_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( 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, ED_view3d_cursor3d_get(scene, v3d)); + RNA_property_float_set_array(op->ptr, prop, ED_view3d_cursor3d_get(scene, v3d)->location); } if (rv3d) { prop = RNA_struct_find_property(op->ptr, "axis"); diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index 4cd3b033ca7..f98d7dacac8 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -36,18 +36,400 @@ #include "BKE_context.h" #include "BKE_report.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "RNA_define.h" #include "RNA_access.h" +#include "WM_api.h" #include "WM_types.h" #include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + #include "mesh_intern.h" /* own include */ +#define USE_MANIPULATOR + +#ifdef USE_MANIPULATOR +#include "ED_manipulator_library.h" +#include "ED_undo.h" +#endif + +/* -------------------------------------------------------------------- */ +/** \name Spin Manipulator + * \{ */ + +#ifdef USE_MANIPULATOR +typedef struct ManipulatorSpinGroup { + /* Arrow to change plane depth. */ + struct wmManipulator *translate_z; + /* Translate XYZ */ + struct wmManipulator *translate_c; + /* For grabbing the manipulator and moving freely. */ + struct wmManipulator *rotate_c; + /* Spin angle */ + struct wmManipulator *angle_z; + + /* We could store more vars here! */ + struct { + bContext *context; + wmOperator *op; + PropertyRNA *prop_axis_co; + PropertyRNA *prop_axis_no; + PropertyRNA *prop_angle; + + float rotate_axis[3]; + float rotate_up[3]; + } data; +} ManipulatorSpinGroup; + +/** + * XXX. calling redo from property updates is not great. + * This is needed because changing the RNA doesn't cause a redo + * and we're not using operator UI which does just this. + */ +static void manipulator_spin_exec(ManipulatorSpinGroup *man) +{ + wmOperator *op = man->data.op; + if (op == WM_operator_last_redo((bContext *)man->data.context)) { + ED_undo_operator_repeat((bContext *)man->data.context, op); + } +} + +static void manipulator_mesh_spin_update_from_op(ManipulatorSpinGroup *man) +{ + wmOperator *op = man->data.op; + + float plane_co[3], plane_no[3]; + + RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co); + RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no); + + WM_manipulator_set_matrix_location(man->translate_z, plane_co); + WM_manipulator_set_matrix_location(man->rotate_c, plane_co); + WM_manipulator_set_matrix_location(man->angle_z, plane_co); + /* translate_c location comes from the property. */ + + WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_z, plane_no); + WM_manipulator_set_matrix_rotation_from_z_axis(man->angle_z, plane_no); + + WM_manipulator_set_scale(man->translate_c, 0.2); + + RegionView3D *rv3d = ED_view3d_context_rv3d(man->data.context); + if (rv3d) { + normalize_v3_v3(man->data.rotate_axis, rv3d->viewinv[2]); + normalize_v3_v3(man->data.rotate_up, rv3d->viewinv[1]); + + /* ensure its orthogonal */ + project_plane_normalized_v3_v3v3(man->data.rotate_up, man->data.rotate_up, man->data.rotate_axis); + normalize_v3(man->data.rotate_up); + + WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_c, plane_no); + WM_manipulator_set_matrix_rotation_from_yz_axis(man->rotate_c, plane_no, man->data.rotate_axis); + + /* show the axis instead of mouse cursor */ + RNA_enum_set(man->rotate_c->ptr, "draw_options", + ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR | + ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y); + + } +} + +/* depth callbacks */ +static void manipulator_spin_prop_depth_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + + float plane_co[3], plane_no[3]; + RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co); + RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no); + + value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, mpr->matrix_basis[3]); +} + +static void manipulator_spin_prop_depth_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + const float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + + float plane_co[3], plane[4]; + RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co); + RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane); + normalize_v3(plane); + + plane[3] = -value[0] - dot_v3v3(plane, mpr->matrix_basis[3]); + + /* Keep our location, may be offset simply to be inside the viewport. */ + closest_to_plane_normalized_v3(plane_co, plane, plane_co); + + RNA_property_float_set_array(op->ptr, man->data.prop_axis_co, plane_co); + + manipulator_spin_exec(man); +} + +/* translate callbacks */ +static void manipulator_spin_prop_translate_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(mpr_prop); + + RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, value); +} + +static void manipulator_spin_prop_translate_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value) +{ + ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + + BLI_assert(mpr_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(mpr_prop); + + RNA_property_float_set_array(op->ptr, man->data.prop_axis_co, value); + + manipulator_spin_exec(man); +} + +/* angle callbacks */ +static void manipulator_spin_prop_axis_angle_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + + float plane_no[4]; + RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no); + normalize_v3(plane_no); + + float plane_no_proj[3]; + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis); + + if (!is_zero_v3(plane_no_proj)) { + const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis); + value[0] = angle; + } + else { + value[0] = 0.0f; + } +} + +static void manipulator_spin_prop_axis_angle_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + const float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + + float plane_no[4]; + RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no); + normalize_v3(plane_no); + + float plane_no_proj[3]; + project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis); + + if (!is_zero_v3(plane_no_proj)) { + const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis); + const float angle_delta = angle - angle_compat_rad(value[0], angle); + if (angle_delta != 0.0f) { + float mat[3][3]; + axis_angle_normalized_to_mat3(mat, man->data.rotate_axis, angle_delta); + mul_m3_v3(mat, plane_no); + + /* re-normalize - seems acceptable */ + RNA_property_float_set_array(op->ptr, man->data.prop_axis_no, plane_no); + + manipulator_spin_exec(man); + } + } +} + +/* angle callbacks */ +static void manipulator_spin_prop_angle_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + float *value = value_p; + + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + value[0] = RNA_property_float_get(op->ptr, man->data.prop_angle); +} + +static void manipulator_spin_prop_angle_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + BLI_assert(mpr_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(mpr_prop); + const float *value = value_p; + RNA_property_float_set(op->ptr, man->data.prop_angle, value[0]); + + manipulator_spin_exec(man); +} + +static bool manipulator_mesh_spin_poll(const bContext *C, wmManipulatorGroupType *wgt) +{ + wmOperator *op = WM_operator_last_redo(C); + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_spin")) { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; + } + return true; +} + +static void manipulator_mesh_spin_setup(const bContext *C, wmManipulatorGroup *mgroup) +{ + wmOperator *op = WM_operator_last_redo(C); + + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_spin")) { + return; + } + + struct ManipulatorSpinGroup *man = MEM_callocN(sizeof(ManipulatorSpinGroup), __func__); + mgroup->customdata = man; + + const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true); + const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", true); + const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true); + + man->translate_z = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + man->translate_c = WM_manipulator_new_ptr(wt_grab, mgroup, NULL); + man->rotate_c = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); + man->angle_z = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->translate_z->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->translate_c->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_SECONDARY, man->rotate_c->color); + UI_GetThemeColor3fv(TH_AXIS_Z, man->angle_z->color); + + + RNA_enum_set(man->translate_z->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_NORMAL); + RNA_enum_set(man->translate_c->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_RING_2D); + + WM_manipulator_set_flag(man->translate_c, WM_MANIPULATOR_DRAW_VALUE, true); + WM_manipulator_set_flag(man->rotate_c, WM_MANIPULATOR_DRAW_VALUE, true); + WM_manipulator_set_flag(man->angle_z, WM_MANIPULATOR_DRAW_VALUE, true); + + WM_manipulator_set_scale(man->angle_z, 0.5f); + + { + man->data.context = (bContext *)C; + man->data.op = op; + man->data.prop_axis_co = RNA_struct_find_property(op->ptr, "center"); + man->data.prop_axis_no = RNA_struct_find_property(op->ptr, "axis"); + man->data.prop_angle = RNA_struct_find_property(op->ptr, "angle"); + } + + manipulator_mesh_spin_update_from_op(man); + + /* Setup property callbacks */ + { + WM_manipulator_target_property_def_func( + man->translate_z, "offset", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_spin_prop_depth_get, + .value_set_fn = manipulator_spin_prop_depth_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + WM_manipulator_target_property_def_func( + man->translate_c, "offset", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_spin_prop_translate_get, + .value_set_fn = manipulator_spin_prop_translate_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + WM_manipulator_target_property_def_func( + man->rotate_c, "offset", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_spin_prop_axis_angle_get, + .value_set_fn = manipulator_spin_prop_axis_angle_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + WM_manipulator_target_property_def_func( + man->angle_z, "offset", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_spin_prop_angle_get, + .value_set_fn = manipulator_spin_prop_angle_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + + } +} + +static void manipulator_mesh_spin_draw_prepare( + const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + ManipulatorSpinGroup *man = mgroup->customdata; + if (man->data.op->next) { + man->data.op = WM_operator_last_redo((bContext *)man->data.context); + } + manipulator_mesh_spin_update_from_op(man); +} + +static void MESH_WGT_spin(struct wmManipulatorGroupType *wgt) +{ + wgt->name = "Mesh Spin"; + wgt->idname = "MESH_WGT_spin"; + + wgt->flag = WM_MANIPULATORGROUPTYPE_3D; + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + + wgt->poll = manipulator_mesh_spin_poll; + wgt->setup = manipulator_mesh_spin_setup; + wgt->draw_prepare = manipulator_mesh_spin_draw_prepare; +} + +/** \} */ + +#endif /* USE_MANIPULATOR */ /* -------------------------------------------------------------------- */ /** \name Spin Operator @@ -55,10 +437,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMOperator spinop; + ViewLayer *view_layer = CTX_data_view_layer(C); float cent[3], axis[3]; float d[3] = {0.0f, 0.0f, 0.0f}; int steps, dupli; @@ -77,21 +456,33 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* 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_duplicate=%b", - BM_ELEM_SELECT, cent, axis, d, steps, angle, obedit->obmat, dupli)) - { - return OPERATOR_CANCELLED; - } - 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)) { - return OPERATOR_CANCELLED; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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_duplicate=%b", + BM_ELEM_SELECT, cent, axis, d, steps, angle, obedit->obmat, dupli)) + { + 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); } - EDBM_update_generic(em, true, true); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -106,7 +497,7 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e 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, ED_view3d_cursor3d_get(scene, v3d)); + RNA_property_float_set_array(op->ptr, prop, ED_view3d_cursor3d_get(scene, v3d)->location); } if (rv3d) { prop = RNA_struct_find_property(op->ptr, "axis"); @@ -115,7 +506,18 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e } } - return edbm_spin_exec(C, op); + int ret = edbm_spin_exec(C, op); + +#ifdef USE_MANIPULATOR + if (ret & OPERATOR_FINISHED) { + /* Setup manipulators */ + if (v3d && (v3d->twflag & V3D_MANIPULATOR_DRAW)) { + WM_manipulator_group_type_ensure("MESH_WGT_spin"); + } + } +#endif + + return ret; } void MESH_OT_spin(wmOperatorType *ot) @@ -146,7 +548,7 @@ void MESH_OT_spin(wmOperatorType *ot) "Center", "Center in global view space", -1e4f, 1e4f); RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f); +#ifdef USE_MANIPULATOR + WM_manipulatorgrouptype_append(MESH_WGT_spin); +#endif } - -/** \} */ - diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 3833b84b5d2..985d873dfc2 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -37,6 +37,7 @@ #include "BKE_global.h" #include "BKE_editmesh.h" #include "BKE_unit.h" +#include "BKE_layer.h" #include "RNA_define.h" #include "RNA_access.h" @@ -55,6 +56,10 @@ #include "mesh_intern.h" /* own include */ +typedef struct { + BMEditMesh *em; + BMBackup mesh_backup; +} InsetObjectStore; typedef struct { float old_thickness; @@ -65,14 +70,15 @@ typedef struct { bool is_modal; bool shift; float shift_amount; - BMEditMesh *em; NumInput num_input; + InsetObjectStore *ob_store; + uint ob_store_len; + /* modal only */ float mcenter[2]; - BMBackup mesh_backup; void *draw_handle_pixel; - short twtype; + short twflag; } InsetData; @@ -115,12 +121,7 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) { InsetData *opdata; Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totvertsel == 0) { - return false; - } + ViewLayer *view_layer = CTX_data_view_layer(C); if (is_modal) { RNA_float_set(op->ptr, "thickness", 0.01f); @@ -129,13 +130,30 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) op->customdata = opdata = MEM_mallocN(sizeof(InsetData), "inset_operator_data"); + uint objects_used_len = 0; + + { + uint ob_store_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &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]; + 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.01; opdata->old_depth = 0.0; opdata->modify_depth = false; opdata->shift = false; opdata->shift_amount = 0.0f; opdata->is_modal = is_modal; - opdata->em = em; initNumInput(&opdata->num_input); opdata->num_input.idx_max = 1; /* Two elements. */ @@ -147,13 +165,16 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); - opdata->mesh_backup = EDBM_redo_state_store(em); + 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->twtype = v3d->twtype; - v3d->twtype = 0; + opdata->twflag = v3d->twflag; + v3d->twflag = 0; } } @@ -170,10 +191,12 @@ static void edbm_inset_exit(bContext *C, wmOperator *op) if (opdata->is_modal) { View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); - EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); + 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->twtype = opdata->twtype; + v3d->twflag = opdata->twflag; } G.moving = 0; } @@ -181,7 +204,9 @@ static void edbm_inset_exit(bContext *C, wmOperator *op) if (sa) { ED_area_headerprint(sa, NULL); } - MEM_freeN(op->customdata); + + MEM_SAFE_FREE(opdata->ob_store); + MEM_SAFE_FREE(op->customdata); } static void edbm_inset_cancel(bContext *C, wmOperator *op) @@ -190,8 +215,10 @@ static void edbm_inset_cancel(bContext *C, wmOperator *op) opdata = op->customdata; if (opdata->is_modal) { - EDBM_redo_state_free(&opdata->mesh_backup, opdata->em, true); - EDBM_update_generic(opdata->em, false, true); + 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); @@ -205,6 +232,7 @@ 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"); @@ -218,49 +246,55 @@ static bool edbm_inset_calc(wmOperator *op) const bool use_interpolate = RNA_boolean_get(op->ptr, "use_interpolate"); opdata = op->customdata; - em = opdata->em; - if (opdata->is_modal) { - EDBM_redo_state_restore(opdata->mesh_backup, em, false); - } + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + em = opdata->ob_store[ob_index].em; - 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); + if (opdata->is_modal) { + EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false); } - } - 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 (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 (!EDBM_op_finish(em, &bmop, op, true)) { - return false; - } - else { - EDBM_update_generic(em, true, true); - return true; + 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) @@ -378,7 +412,9 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) case LEFTMOUSE: case PADENTER: case RETKEY: - if (event->val == KM_PRESS) { + 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; @@ -540,4 +576,7 @@ void MESH_OT_inset(wmOperatorType *ot) 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 86b1a58dd1e..9af700aa6bf 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -33,6 +33,7 @@ #include "BLI_kdopbvh.h" #include "BLI_linklist_stack.h" +#include "BKE_layer.h" #include "BKE_editmesh_bvh.h" #include "BKE_context.h" #include "BKE_report.h" @@ -146,9 +147,6 @@ enum { static int edbm_intersect_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; const int mode = RNA_enum_get(op->ptr, "mode"); int (*test_fn)(BMFace *, void *); bool use_separate_all = false; @@ -186,29 +184,45 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op) 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, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - has_isect = BM_mesh_intersect( - 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( - bm, - BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT)); - } + 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); + if (has_isect) { + edbm_intersect_select(em); + } + else { + isect_len++; + } } - else { + MEM_freeN(objects); + + if (isect_len == objects_len) { BKE_report(op->reports, RPT_WARNING, "No intersections found"); } - return OPERATOR_FINISHED; } @@ -266,9 +280,6 @@ void MESH_OT_intersect(struct wmOperatorType *ot) static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; 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"); @@ -276,23 +287,39 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) 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, &objects_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( - bm, - em->looptris, em->tottri, - test_fn, NULL, - false, false, true, true, false, true, - boolean_operation, - eps); + 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); + if (has_isect) { + edbm_intersect_select(em); + } + else { + isect_len++; + } } - else { + MEM_freeN(objects); + + if (isect_len == objects_len) { BKE_report(op->reports, RPT_WARNING, "No intersections found"); } - return OPERATOR_FINISHED; } @@ -652,257 +679,270 @@ static BMEdge *bm_face_split_edge_find( static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; const char hflag = BM_ELEM_TAG; BMEdge *e; BMIter iter; - BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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; - { - BMVert *v; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(v, hflag); + if ((bm->totedgesel == 0) || + (bm->totfacesel == 0)) + { + continue; } - } - - /* edge index is set to -1 then used to assosiate 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); + BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); + { + BMVert *v; + BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(v, 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); + /* edge index is set to -1 then used to assosiate 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(f, hflag); + BM_elem_flag_disable(e, hflag); } - BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); - BM_elem_index_set(f, i); /* set_ok */ + BM_elem_index_set(e, -1); /* set_dirty */ } - } - 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++; - } - } + bm->elem_index_dirty |= BM_EDGE; - if (loop_stack_len == 0) { - /* pass */ - } - else if (loop_stack_len == 1) { - l_best = BLI_SMALLSTACK_POP(loop_stack); + { + 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 { - /* complicated case, match the edge with a face-loop */ + 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]; + BMVert *v_other = BM_edge_other_vert(e, v); + float e_dir[3]; - /* we want closest to zero */ - float dot_best = FLT_MAX; + /* we want closest to zero */ + float dot_best = FLT_MAX; - sub_v3_v3v3(e_dir, v_other->co, v->co); - normalize_v3(e_dir); + sub_v3_v3v3(e_dir, v_other->co, v->co); + normalize_v3(e_dir); - while ((l = BLI_SMALLSTACK_POP(loop_stack))) { - float dot_test; + 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 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; + /* 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 */ + 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); + { + 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); + 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); } - 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__); + /* 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__); + MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - BM_mesh_elem_index_ensure(bm, BM_FACE); + BM_mesh_elem_index_ensure(bm, BM_FACE); - { - BMBVHTree *bmbvh = BKE_bmbvh_new(bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false); + { + 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 */ - } + 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); + 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 */ + 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); - } + BKE_bmbvh_free(bmbvh); + } - bm->elem_index_dirty |= BM_EDGE; + bm->elem_index_dirty |= BM_EDGE; - BM_mesh_elem_table_ensure(bm, BM_FACE); + 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)); + /* 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)); + } while ((e_link = e_link->next)); + } } - } - { - MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + { + MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - GHashIterator gh_iter; + 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); + 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); + 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_clear(mem_arena_edgenet); + } - BLI_memarena_free(mem_arena_edgenet); - } + BLI_memarena_free(mem_arena_edgenet); + } - BLI_memarena_free(mem_arena); + BLI_memarena_free(mem_arena); - BLI_ghash_free(face_edge_map, NULL, NULL); + BLI_ghash_free(face_edge_map, NULL, NULL); - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - } + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + } - BLI_stack_free(edges_loose); + BLI_stack_free(edges_loose); #endif /* USE_NET_ISLAND_CONNECT */ + } + MEM_freeN(objects); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 8eb3ad84919..be54bba7aa4 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -54,8 +54,10 @@ #include "BKE_editmesh_bvh.h" #include "BKE_report.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" /* for paint cursor */ +#include "DEG_depsgraph.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" #include "ED_screen.h" #include "ED_space_api.h" @@ -1004,12 +1006,18 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) copy_v3_v3(v2, ray_hit_best[1]); } - UI_ThemeColor(TH_TRANSFORM); + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColor(TH_TRANSFORM); glLineWidth(2.0); - glBegin(GL_LINES); - glVertex3fv(v1); - glVertex3fv(v2); - glEnd(); + + immBegin(GWN_PRIM_LINES, 2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immEnd(); + + immUnbindProgram(); } static void knife_init_colors(KnifeColors *colors) @@ -1037,66 +1045,69 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) glPolygonOffset(1.0f, 1.0f); - glPushMatrix(); - glMultMatrixf(kcd->ob->obmat); + gpuPushMatrix(); + gpuMultMatrix(kcd->ob->obmat); + + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); if (kcd->mode == MODE_DRAGGING) { if (kcd->is_angle_snapping) knifetool_draw_angle_snapping(kcd); - glColor3ubv(kcd->colors.line); - + immUniformColor3ubv(kcd->colors.line); glLineWidth(2.0); - glBegin(GL_LINES); - glVertex3fv(kcd->prev.cage); - glVertex3fv(kcd->curr.cage); - glEnd(); + immBegin(GWN_PRIM_LINES, 2); + immVertex3fv(pos, kcd->prev.cage); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); } if (kcd->prev.vert) { - glColor3ubv(kcd->colors.point); + immUniformColor3ubv(kcd->colors.point); glPointSize(11); - glBegin(GL_POINTS); - glVertex3fv(kcd->prev.cage); - glEnd(); + immBegin(GWN_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->prev.cage); + immEnd(); } if (kcd->prev.bmface) { - glColor3ubv(kcd->colors.curpoint); + immUniformColor3ubv(kcd->colors.curpoint); glPointSize(9); - glBegin(GL_POINTS); - glVertex3fv(kcd->prev.cage); - glEnd(); + immBegin(GWN_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->prev.cage); + immEnd(); } if (kcd->curr.edge) { - glColor3ubv(kcd->colors.edge); + immUniformColor3ubv(kcd->colors.edge); glLineWidth(2.0); - glBegin(GL_LINES); - glVertex3fv(kcd->curr.edge->v1->cageco); - glVertex3fv(kcd->curr.edge->v2->cageco); - glEnd(); + immBegin(GWN_PRIM_LINES, 2); + immVertex3fv(pos, kcd->curr.edge->v1->cageco); + immVertex3fv(pos, kcd->curr.edge->v2->cageco); + immEnd(); } else if (kcd->curr.vert) { - glColor3ubv(kcd->colors.point); + immUniformColor3ubv(kcd->colors.point); glPointSize(11); - glBegin(GL_POINTS); - glVertex3fv(kcd->curr.cage); - glEnd(); + immBegin(GWN_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); } if (kcd->curr.bmface) { - glColor3ubv(kcd->colors.curpoint); + immUniformColor3ubv(kcd->colors.curpoint); glPointSize(9); - glBegin(GL_POINTS); - glVertex3fv(kcd->curr.cage); - glEnd(); + immBegin(GWN_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); } if (kcd->totlinehit > 0) { @@ -1104,29 +1115,38 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) int i; glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* draw any snapped verts first */ - glColor4ubv(kcd->colors.point_a); + immUniformColor4ubv(kcd->colors.point_a); glPointSize(11); - glBegin(GL_POINTS); + + immBeginAtMost(GWN_PRIM_POINTS, kcd->totlinehit); + lh = kcd->linehits; for (i = 0; i < kcd->totlinehit; i++, lh++) { - if (lh->v) - glVertex3fv(lh->cagehit); + if (lh->v) { + immVertex3fv(pos, lh->cagehit); + } } - glEnd(); + + immEnd(); /* now draw the rest */ - glColor4ubv(kcd->colors.curpoint_a); + immUniformColor4ubv(kcd->colors.curpoint_a); glPointSize(7); - glBegin(GL_POINTS); + + immBeginAtMost(GWN_PRIM_POINTS, kcd->totlinehit); + lh = kcd->linehits; for (i = 0; i < kcd->totlinehit; i++, lh++) { - if (!lh->v) - glVertex3fv(lh->cagehit); + if (!lh->v) { + immVertex3fv(pos, lh->cagehit); + } } - glEnd(); + + immEnd(); + glDisable(GL_BLEND); } @@ -1134,44 +1154,46 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) BLI_mempool_iter iter; KnifeEdge *kfe; + immUniformColor3ubv(kcd->colors.line); glLineWidth(1.0); - glBegin(GL_LINES); + + immBeginAtMost(GWN_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; - glColor3ubv(kcd->colors.line); - - glVertex3fv(kfe->v1->cageco); - glVertex3fv(kfe->v2->cageco); + immVertex3fv(pos, kfe->v1->cageco); + immVertex3fv(pos, kfe->v2->cageco); } - glEnd(); + immEnd(); } if (kcd->totkvert > 0) { BLI_mempool_iter iter; KnifeVert *kfv; + immUniformColor3ubv(kcd->colors.point); glPointSize(5.0); - glBegin(GL_POINTS); + immBeginAtMost(GWN_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; - glColor3ubv(kcd->colors.point); - - glVertex3fv(kfv->cageco); + immVertex3fv(pos, kfv->cageco); } - glEnd(); + immEnd(); } - glPopMatrix(); + immUnbindProgram(); + + gpuPopMatrix(); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } @@ -1394,7 +1416,7 @@ static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data) * 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], bglMats *mats, + KnifeTool_OpData *kcd, const float p[3], const float s[2], BMElem *ele_test) { BMFace *f_hit; @@ -1412,7 +1434,7 @@ static bool point_is_visible( float view[3], p_ofs[3]; /* TODO: I think there's a simpler way to get the required raycast ray */ - ED_view3d_unproject(mats, view, s[0], s[1], 0.0f); + ED_view3d_unproject(kcd->vc.ar, s[0], s[1], 0.0f, view); mul_m4_v3(kcd->ob->imat, view); @@ -1485,7 +1507,6 @@ static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh) /* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */ static void knife_find_line_hits(KnifeTool_OpData *kcd) { - bglMats mats; SmallHash faces, kfes, kfvs; float v1[3], v2[3], v3[3], v4[3], s1[2], s2[2]; BVHTree *planetree, *tree; @@ -1515,8 +1536,6 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) const bool use_hit_prev = true; const bool use_hit_curr = (kcd->is_drag_hold == false); - bgl_get_mats(&mats); - if (kcd->linehits) { MEM_freeN(kcd->linehits); kcd->linehits = NULL; @@ -1542,8 +1561,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } /* unproject screen line */ - ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s1, v1, v3, true); - ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s2, v2, v4, true); + ED_view3d_win_to_segment(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s1, v1, v3, true); + ED_view3d_win_to_segment(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); @@ -1645,7 +1664,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) 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, &mats, bm_elem_from_knife_vert(v, &kfe_hit)))) + (point_is_visible(kcd, v->cageco, s, bm_elem_from_knife_vert(v, &kfe_hit)))) { memset(&hit, 0, sizeof(hit)); hit.v = v; @@ -1708,7 +1727,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) * 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, &mats, bm_elem_from_knife_edge(kfe))) { + 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 */ @@ -1737,7 +1756,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) 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, &mats, (BMElem *)f)) { + if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) { memset(&hit, 0, sizeof(hit)); hit.f = f; copy_v3_v3(hit.hit, p); @@ -1749,7 +1768,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } 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, &mats, (BMElem *)f)) { + if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) { memset(&hit, 0, sizeof(hit)); hit.f = f; copy_v3_v3(hit.hit, p); @@ -1782,13 +1801,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) 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]) { - bglMats mats; - - bgl_get_mats(&mats); - /* unproject to find view ray */ - ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f); - ED_view3d_unproject(&mats, r_origin_ofs, mval[0], mval[1], ofs); + 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); @@ -2503,7 +2518,8 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd) 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.v3d, kcd->vc.rv3d, + kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.depsgraph, + kcd->vc.v3d, kcd->vc.rv3d, &kcd->clipsta, &kcd->clipend, true); } @@ -2574,7 +2590,7 @@ static void knifetool_init_bmbvh(KnifeTool_OpData *kcd) { BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT); - kcd->cagecos = (const float (*)[3])BKE_editmesh_vertexCos_get(kcd->em, kcd->scene, NULL); + kcd->cagecos = (const float (*)[3])BKE_editmesh_vertexCos_get(kcd->vc.depsgraph, kcd->em, kcd->scene, NULL); kcd->bmbvh = BKE_bmbvh_new_from_editmesh( kcd->em, @@ -3008,7 +3024,6 @@ 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; - bglMats mats; view3d_operator_needs_opengl(C); @@ -3027,10 +3042,6 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug if (use_tag) { BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false); } - - if (kcd->cut_through == false) { - bgl_get_mats(&mats); - } } /* execute */ @@ -3139,7 +3150,7 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug 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, &mats, (BMElem *)f)) && + 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); diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index 0d3cc07589b..5ccbcf063ad 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -40,8 +40,11 @@ #include "BKE_curve.h" #include "BKE_cdderivedmesh.h" #include "BKE_editmesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_report.h" +#include "DEG_depsgraph.h" + #include "RNA_define.h" #include "RNA_access.h" @@ -56,29 +59,32 @@ #include "mesh_intern.h" /* own include */ -static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object *ob, LinkNode *polys) +static LinkNode *knifeproject_poly_from_object(const bContext *C, Scene *scene, Object *ob, LinkNode *polys) { - DerivedMesh *dm; - bool dm_needsFree; + 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->derivedFinal) { - dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - dm_needsFree = false; + me_eval = (ob->runtime.mesh_eval ? + ob->runtime.mesh_eval : mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH)); + me_eval_needs_free = false; } else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - dm = CDDM_from_curve(ob); - dm_needsFree = true; + me_eval = BKE_mesh_new_nomain_from_curve(ob); + me_eval_needs_free = true; } else { - dm = NULL; + me_eval = NULL; } - if (dm) { + if (me_eval) { ListBase nurbslist = {NULL, NULL}; float projmat[4][4]; - BKE_mesh_to_curve_nurblist(dm, &nurbslist, 0); /* wire */ - BKE_mesh_to_curve_nurblist(dm, &nurbslist, 1); /* boundary */ + 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); @@ -105,18 +111,16 @@ static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object BKE_nurbList_free(&nurbslist); - if (dm_needsFree) { - dm->release(dm); + if (me_eval_needs_free) { + BKE_mesh_free(me_eval); } } - return polys; } static int knifeproject_exec(bContext *C, wmOperator *op) { - ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -127,7 +131,7 @@ static int knifeproject_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { if (ob != obedit) { - polys = knifeproject_poly_from_object(ar, scene, ob, polys); + polys = knifeproject_poly_from_object(C, scene, ob, polys); } } CTX_DATA_END; diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index a52bf41b9da..7dac9a09b97 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -44,8 +44,10 @@ #include "BKE_editmesh.h" #include "BKE_DerivedMesh.h" #include "BKE_unit.h" +#include "BKE_layer.h" -#include "BIF_gl.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" #include "UI_interface.h" @@ -62,6 +64,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "DEG_depsgraph.h" + #include "mesh_intern.h" /* own include */ #define SUBD_SMOOTH_MAX 4.0f @@ -82,9 +86,15 @@ typedef struct RingSelOpData { ViewContext vc; + 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; + NumInput num; bool extend; @@ -104,27 +114,41 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) if (v3d && v3d->zbuf) glDisable(GL_DEPTH_TEST); - glPushMatrix(); - glMultMatrixf(lcd->ob->obmat); + gpuPushMatrix(); + gpuMultMatrix(lcd->ob->obmat); + + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ub(255, 0, 255); - glColor3ub(255, 0, 255); if (lcd->totedge > 0) { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, lcd->edges); - glDrawArrays(GL_LINES, 0, lcd->totedge * 2); - glDisableClientState(GL_VERTEX_ARRAY); + immBegin(GWN_PRIM_LINES, lcd->totedge * 2); + + for (int i = 0; i < lcd->totedge; i++) { + immVertex3fv(pos, lcd->edges[i][0]); + immVertex3fv(pos, lcd->edges[i][1]); + } + + immEnd(); } if (lcd->totpoint > 0) { glPointSize(3.0f); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, lcd->points); - glDrawArrays(GL_POINTS, 0, lcd->totpoint); - glDisableClientState(GL_VERTEX_ARRAY); + immBegin(GWN_PRIM_POINTS, lcd->totpoint); + + for (int i = 0; i < lcd->totpoint; i++) { + immVertex3fv(pos, lcd->points[i]); + } + + immEnd(); } - glPopMatrix(); + immUnbindProgram(); + + gpuPopMatrix(); + if (v3d && v3d->zbuf) glEnable(GL_DEPTH_TEST); } @@ -367,18 +391,24 @@ static void edgering_preview_calc(RingSelOpData *lcd, const int previewlines) static void edgering_select(RingSelOpData *lcd) { - BMEditMesh *em = lcd->em; - BMEdge *eed_start = lcd->eed; - BMWalker walker; - BMEdge *eed; - - if (!eed_start) + if (!lcd->eed) { return; + } if (!lcd->extend) { - EDBM_flag_disable_all(lcd->em, BM_ELEM_SELECT); + 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, DEG_TAG_SELECT_UPDATE); + 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, @@ -467,6 +497,7 @@ static void ringsel_finish(bContext *C, wmOperator *op) BM_select_history_store(em->bm, lcd->eed); EDBM_selectmode_flush(lcd->em); + DEG_id_tag_update(lcd->ob->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, lcd->ob->data); } } @@ -482,6 +513,8 @@ static void ringsel_exit(bContext *UNUSED(C), wmOperator *op) edgering_preview_free(lcd); + MEM_freeN(lcd->objects); + ED_region_tag_redraw(lcd->ar); /* free the custom data */ @@ -499,11 +532,14 @@ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut) /* alloc new customdata */ lcd = op->customdata = MEM_callocN(sizeof(RingSelOpData), "ringsel Modal Op Data"); + em_setup_viewcontext(C, &lcd->vc); + /* 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->ob = CTX_data_edit_object(C); - lcd->em = BKE_editmesh_from_object(lcd->ob); + /* 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"); @@ -517,8 +553,6 @@ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut) lcd->num.unit_type[0] = B_UNIT_NONE; lcd->num.unit_type[1] = B_UNIT_NONE; - em_setup_viewcontext(C, &lcd->vc); - ED_region_tag_redraw(lcd->ar); return 1; @@ -530,44 +564,102 @@ static void ringcut_cancel(bContext *C, wmOperator *op) ringsel_exit(C, op); } -static void loopcut_update_edge(RingSelOpData *lcd, 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; + } } static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines) { - float dist = ED_view3d_select_dist_px(); - BMEdge *e = EDBM_edge_find_nearest(&lcd->vc, &dist); - loopcut_update_edge(lcd, e, 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); - Object *obedit = CTX_data_edit_object(C); - RingSelOpData *lcd; - if (modifiers_isDeformedByLattice(obedit) || modifiers_isDeformedByArmature(obedit)) - BKE_report(op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display"); + /* 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, &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) { - const int e_index = RNA_int_get(op->ptr, "edge_index"); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (UNLIKELY((e_index == -1) || (e_index >= em->bm->totedge))) { + 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 (!ringsel_init(C, op, true)) + 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) { @@ -575,18 +667,24 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) WM_event_add_modal_handler(C, op); } - lcd = op->customdata; + 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 { - const int e_index = RNA_int_get(op->ptr, "edge_index"); + + 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->em->bm, BM_EDGE); - e = BM_edge_at_index(lcd->em->bm, e_index); - loopcut_update_edge(lcd, e, 0); + 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 @@ -636,6 +734,7 @@ static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op) 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 */ @@ -855,12 +954,17 @@ void MESH_OT_loopcut(wmOperatorType *ot) "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); diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index bf5a7e3a053..64d890a7314 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -29,6 +29,8 @@ * \ingroup edmesh */ +#include "MEM_guardedalloc.h" + #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_mesh_types.h" @@ -41,6 +43,7 @@ #include "BLI_math.h" #include "BLI_linklist.h" +#include "BKE_layer.h" #include "BKE_context.h" #include "BKE_editmesh.h" #include "BKE_report.h" @@ -59,6 +62,8 @@ #include "bmesh.h" #include "bmesh_tools.h" +#include "DEG_depsgraph.h" + #include "mesh_intern.h" /* own include */ /* -------------------------------------------------------------------- */ @@ -126,10 +131,9 @@ static void verttag_set_cb(BMVert *v, bool val, void *user_data_v) } static void mouse_mesh_shortest_path_vert( - Scene *scene, const struct PathSelectParams *op_params, + Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params, BMVert *v_act, BMVert *v_dst) { - Object *obedit = scene->obedit; BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -286,11 +290,11 @@ static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v) } } -static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me) +static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode) { BMesh *bm = me->edit_btmesh->bm; - switch (scene->toolsettings->edge_mode) { + switch (edge_mode) { case EDGE_MODE_TAG_CREASE: BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE); break; @@ -313,10 +317,9 @@ static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me) /* since you want to create paths with multiple selects, it doesn't have extend option */ static void mouse_mesh_shortest_path_edge( - Scene *scene, const struct PathSelectParams *op_params, + Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMEdge *e_act, BMEdge *e_dst) { - Object *obedit = scene->obedit; BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -325,7 +328,7 @@ static void mouse_mesh_shortest_path_edge( Mesh *me = obedit->data; bool is_path_ordered = false; - edgetag_ensure_cd_flag(scene, obedit->data); + edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode); if (e_act && (e_act != e_dst)) { if (op_params->use_fill) { @@ -383,7 +386,7 @@ static void mouse_mesh_shortest_path_edge( } else { const bool is_act = !edgetag_test_cb(e_dst, &user_data); - edgetag_ensure_cd_flag(scene, obedit->data); + edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode); edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */ } @@ -459,10 +462,9 @@ static void facetag_set_cb(BMFace *f, bool val, void *user_data_v) } static void mouse_mesh_shortest_path_face( - Scene *scene, const struct PathSelectParams *op_params, + Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params, BMFace *f_act, BMFace *f_dst) { - Object *obedit = scene->obedit; BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -554,7 +556,7 @@ static void mouse_mesh_shortest_path_face( * \{ */ static bool edbm_shortest_path_pick_ex( - Scene *scene, const struct PathSelectParams *op_params, + Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMElem *ele_src, BMElem *ele_dst) { @@ -562,15 +564,15 @@ static bool edbm_shortest_path_pick_ex( /* pass */ } else if (ele_src->head.htype == BM_VERT) { - mouse_mesh_shortest_path_vert(scene, op_params, (BMVert *)ele_src, (BMVert *)ele_dst); + mouse_mesh_shortest_path_vert(scene, obedit, op_params, (BMVert *)ele_src, (BMVert *)ele_dst); return true; } else if (ele_src->head.htype == BM_EDGE) { - mouse_mesh_shortest_path_edge(scene, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst); + mouse_mesh_shortest_path_edge(scene, obedit, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst); return true; } else if (ele_src->head.htype == BM_FACE) { - mouse_mesh_shortest_path_face(scene, op_params, (BMFace *)ele_src, (BMFace *)ele_dst); + mouse_mesh_shortest_path_face(scene, obedit, op_params, (BMFace *)ele_src, (BMFace *)ele_dst); return true; } @@ -649,7 +651,7 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE op_params.track_active = track_active; op_params.edge_mode = vc.scene->toolsettings->edge_mode; - if (!edbm_shortest_path_pick_ex(vc.scene, &op_params, ele_src, ele_dst)) { + if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) { return OPERATOR_PASS_THROUGH; } @@ -686,7 +688,7 @@ static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op) op_params.track_active = true; op_params.edge_mode = scene->toolsettings->edge_mode; - if (!edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst)) { + if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) { return OPERATOR_CANCELLED; } @@ -727,67 +729,87 @@ 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); - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - BMIter iter; - BMEditSelection *ese_src, *ese_dst; - BMElem *ele_src = NULL, *ele_dst = NULL, *ele; + 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, &objects_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; + /* 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_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_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); + if (ele_src && ele_dst) { + struct PathSelectParams op_params; + path_select_params_from_op(op, &op_params); - edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst); + edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst); - return OPERATOR_FINISHED; + found_valid_elements = true; + } } - else { - BKE_report(op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected"); + 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) diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c new file mode 100644 index 00000000000..e8bcfb5eb08 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_polybuild.c @@ -0,0 +1,542 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_polybuild.c + * \ingroup edmesh + * + * Tools to implement polygon building tool, + * an experimental tool for quickly constructing/manipulating faces. + */ + +#include "DNA_object_types.h" + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_editmesh.h" +#include "BKE_mesh.h" + +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_transform.h" +#include "ED_view3d.h" + +#include "bmesh.h" + +#include "mesh_intern.h" /* own include */ + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" + +/* -------------------------------------------------------------------- */ +/** \name Local Utilities + * \{ */ + +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); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Face At Cursor + * \{ */ + +static int edbm_polybuild_face_at_cursor_invoke( + bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + ViewContext vc; + float center[3]; + bool changed = false; + + em_setup_viewcontext(C, &vc); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMElem *ele_act = BM_mesh_active_elem_get(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, ED_view3d_cursor3d_get(vc.scene, vc.v3d)->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(em, BM_ELEM_SELECT); + BM_vert_select_set(bm, v_new, true); + 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(em, BM_ELEM_SELECT); + BM_vert_select_set(bm, v_tri[2], true); + 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(em, BM_ELEM_SELECT); + BM_vert_select_set(bm, v_quad[2], true); + 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); + } + } + + if (changed) { + BM_select_history_clear(bm); + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + + 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"; + ot->description = ""; + + /* api callbacks */ + ot->invoke = edbm_polybuild_face_at_cursor_invoke; + ot->poll = EDBM_view3d_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* to give to transform */ + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split At Cursor + * \{ */ + +static int edbm_polybuild_split_at_cursor_invoke( + bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + ViewContext vc; + float center[3]; + bool changed = false; + + em_setup_viewcontext(C, &vc); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + 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); + + BMElem *ele_act = BM_mesh_active_elem_get(bm); + + 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(em, BM_ELEM_SELECT); + BM_vert_select_set(bm, v_new, true); + changed = true; + } + else if (ele_act->head.htype == BM_VERT) { + /* Just do nothing, allow dragging. */ + return OPERATOR_FINISHED; + } + + if (changed) { + BM_select_history_clear(bm); + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + + WM_event_add_mousemove(C); + + 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"; + ot->description = ""; + + /* api callbacks */ + ot->invoke = edbm_polybuild_split_at_cursor_invoke; + ot->poll = EDBM_view3d_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* to give to transform */ + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Dissolve At Cursor + * + * \{ */ + +static int edbm_polybuild_dissolve_at_cursor_invoke( + bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + ViewContext vc; + em_setup_viewcontext(C, &vc); + bool changed = false; + + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMVert *v_act = BM_mesh_active_vert_get(bm); + BMEdge *e_act = BM_mesh_active_edge_get(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 (e_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 (v_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 */ + if (!EDBM_op_callf(em, op, + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_SELECT, false, true)) + { + return OPERATOR_CANCELLED; + } + } + changed = true; + } + + if (changed) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BM_select_history_clear(bm); + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + + 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"; + ot->description = ""; + + /* api callbacks */ + ot->invoke = edbm_polybuild_dissolve_at_cursor_invoke; + ot->poll = EDBM_view3d_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Cursor Manipulator + * + * \note This may need its own file, for now not. + * \{ */ + +static BMElem *edbm_hover_preselect( + bContext *C, + const int mval[2], + bool use_boundary) +{ + ViewContext vc; + + em_setup_viewcontext(C, &vc); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); + + const float mval_fl[2] = {UNPACK2(mval)}; + float ray_origin[3], ray_direction[3]; + + BMElem *ele_best = NULL; + + if (ED_view3d_win_to_ray( + CTX_data_depsgraph(C), + vc.ar, vc.v3d, mval_fl, + ray_origin, ray_direction, true)) + { + BMEdge *e; + + BMIter eiter; + float dist_sq_best = FLT_MAX; + + BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) && + (!use_boundary || BM_edge_is_boundary(e))) + { + float dist_sq_test; + float point[3]; + float depth; +#if 0 + dist_sq_test = dist_squared_ray_to_seg_v3( + ray_origin, ray_direction, + e->v1->co, e->v2->co, + point, &depth); +#else + mid_v3_v3v3(point, e->v1->co, e->v2->co); + dist_sq_test = dist_squared_to_ray_v3( + ray_origin, ray_direction, + point, &depth); +#endif + + if (dist_sq_test < dist_sq_best) { + dist_sq_best = dist_sq_test; + ele_best = (BMElem *)e; + } + + dist_sq_test = dist_squared_to_ray_v3( + ray_origin, ray_direction, + e->v1->co, &depth); + if (dist_sq_test < dist_sq_best) { + dist_sq_best = dist_sq_test; + ele_best = (BMElem *)e->v1; + } + dist_sq_test = dist_squared_to_ray_v3( + ray_origin, ray_direction, + e->v2->co, &depth); + if (dist_sq_test < dist_sq_best) { + dist_sq_best = dist_sq_test; + ele_best = (BMElem *)e->v2; + } + } + } + } + return ele_best; +} + +/* + * Developer note: this is not advocating pre-selection highlighting. + * This is just a quick way to test how a tool for interactively editing polygons may work. */ +static int edbm_polybuild_hover_invoke( + bContext *C, wmOperator *op, const wmEvent *event) +{ + const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); + ViewContext vc; + + em_setup_viewcontext(C, &vc); + + /* Vertex selection is needed */ + if ((vc.scene->toolsettings->selectmode & SCE_SELECT_VERTEX) == 0) { + return OPERATOR_PASS_THROUGH; + } + + /* Don't overwrite click-drag events. */ + if (use_boundary == false) { + /* pass */ + } + else if (vc.win->tweak || + (vc.win->eventstate->check_click && + vc.win->eventstate->prevval == KM_PRESS && + ISMOUSE(vc.win->eventstate->prevtype))) + { + return OPERATOR_PASS_THROUGH; + } + + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMElem *ele_active = BM_mesh_active_elem_get(bm); + BMElem *ele_hover = edbm_hover_preselect(C, event->mval, use_boundary); + + if (ele_hover && (ele_hover != ele_active)) { + if (event->shift == 0) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BM_select_history_clear(bm); + } + BM_elem_select_set(bm, ele_hover, true); + BM_select_history_store(em->bm, ele_hover); + BKE_mesh_batch_cache_dirty(obedit->data, BKE_MESH_BATCH_DIRTY_SELECT); + + ED_region_tag_redraw(vc.ar); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void MESH_OT_polybuild_hover(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Poly Build Hover"; + ot->idname = "MESH_OT_polybuild_hover"; + ot->description = ""; + + /* api callbacks */ + ot->invoke = edbm_polybuild_hover_invoke; + ot->poll = EDBM_view3d_poll; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; + + /* properties */ + RNA_def_boolean(ot->srna, "use_boundary", false, "Boundary", "Select only boundary geometry"); +} + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 0c8bd560bb2..23011f835c1 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -39,6 +39,7 @@ #include "BKE_context.h" #include "BKE_report.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "RNA_define.h" #include "RNA_access.h" @@ -523,11 +524,9 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u /** * This is the main vert ripping function (rip when one vertex is selected) */ -static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *event) +static int edbm_rip_invoke__vert(bContext *C, const wmEvent *event, Object *obedit, bool do_fill) { - const bool do_fill = RNA_boolean_get(op->ptr, "use_fill"); UnorderedLoopPair *fill_uloop_pairs = NULL; - Object *obedit = CTX_data_edit_object(C); ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -672,7 +671,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve /* set selection back to avoid active-unselected vertex */ BM_vert_select_set(bm, v, true); /* should never happen */ - BKE_report(op->reports, RPT_ERROR, "Error ripping vertex from faces"); return OPERATOR_CANCELLED; } else { @@ -759,7 +757,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve } if (!e_best) { - BKE_report(op->reports, RPT_ERROR, "Selected vertex has no edge/face pairs attached"); return OPERATOR_CANCELLED; } @@ -875,7 +872,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve if (totvert_orig == bm->totvert) { - BKE_report(op->reports, RPT_ERROR, "No vertices could be ripped"); return OPERATOR_CANCELLED; } @@ -885,11 +881,9 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve /** * This is the main edge ripping function */ -static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *event) +static int edbm_rip_invoke__edge(bContext *C, const wmEvent *event, Object *obedit, bool do_fill) { - const bool do_fill = RNA_boolean_get(op->ptr, "use_fill"); UnorderedLoopPair *fill_uloop_pairs = NULL; - Object *obedit = CTX_data_edit_object(C); ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -1004,7 +998,6 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve } if (totedge_orig == bm->totedge) { - BKE_report(op->reports, RPT_ERROR, "No edges could be ripped"); return OPERATOR_CANCELLED; } @@ -1016,65 +1009,102 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve /* based on mouse cursor position, it defines how is being ripped */ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Object *obedit = CTX_data_edit_object(C); - 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; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + const bool do_fill = RNA_boolean_get(op->ptr, "use_fill"); - /* 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); + bool no_vertex_selected = true; + bool error_face_selected = true; + bool error_disconected_vertices = true; + bool error_rip_failed = true; - BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces"); - return OPERATOR_CANCELLED; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* we could support this, but not for now */ - if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) { - BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices"); - return OPERATOR_CANCELLED; - } + BMesh *bm = em->bm; + BMIter iter; + BMEdge *e; + const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0); + int ret; - /* 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. - */ + 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; - /* 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)); + /* we could support this, but not for now */ + if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) { + continue; + } + error_disconected_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); } - /* split 2 main parts of this operator out into vertex and edge ripping */ - if (singlesel) { - ret = edbm_rip_invoke__vert(C, op, event); + MEM_freeN(objects); + + if (no_vertex_selected) { + /* Ignore it. */ + return OPERATOR_CANCELLED; } - else { - ret = edbm_rip_invoke__edge(C, op, event); + else if (error_face_selected) { + BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces"); + return OPERATOR_CANCELLED; } - - if (ret == OPERATOR_CANCELLED) { + else if (error_disconected_vertices) { + BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices"); return OPERATOR_CANCELLED; } - - BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0)); - - if (bm->totvertsel == 0) { + else if (error_rip_failed) { + BKE_report(op->reports, RPT_ERROR, "Rip failed"); return OPERATOR_CANCELLED; } - - EDBM_update_generic(em, true, true); - + /* No errors, everything went fine. */ return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c index a501dfc8c2c..33dc252ab14 100644 --- a/source/blender/editors/mesh/editmesh_rip_edge.c +++ b/source/blender/editors/mesh/editmesh_rip_edge.c @@ -24,6 +24,8 @@ * based on mouse cursor position, split of vertices along the closest edge. */ +#include "MEM_guardedalloc.h" + #include "DNA_object_types.h" #include "BLI_math.h" @@ -31,6 +33,7 @@ #include "BKE_context.h" #include "BKE_report.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "WM_types.h" @@ -50,181 +53,187 @@ static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve { ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); - Object *obedit = CTX_data_edit_object(C); - 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; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - /* mouse direction to view center */ - float mval_dir[2]; + 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; - float projectMat[4][4]; + BMIter viter; + BMVert *v; + const float mval_fl[2] = { UNPACK2(event->mval) }; + float cent_sco[2]; + int cent_tot; + bool changed = false; - if (bm->totvertsel == 0) - return OPERATOR_CANCELLED; + /* mouse direction to view center */ + float mval_dir[2]; - ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); + float projectMat[4][4]; - zero_v2(cent_sco); - cent_tot = 0; + if (bm->totvertsel == 0) + continue; - /* clear tags and calc screen center */ - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(v, BM_ELEM_TAG); + ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); - 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); + 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; + 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); + 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); + 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]; + /* 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; + 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; + /* 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; } - tot += 1; } - } - if (tot_sel != 1) { - e_best = NULL; - } + 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; - } + /* 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); - BM_mesh_select_mode_flush(bm); + if (changed) { + BM_select_history_clear(bm); - EDBM_update_generic(em, true, true); + BM_mesh_select_mode_flush(bm); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; + EDBM_update_generic(em, true, true); + } } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 019aa6d4201..99a95c27b7b 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -45,6 +45,7 @@ #include "BKE_report.h" #include "BKE_paint.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -68,6 +69,9 @@ #include "bmesh_tools.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "mesh_intern.h" /* own include */ /* use bmesh operator flags for a few operators */ @@ -209,7 +213,9 @@ static BLI_bitmap *edbm_backbuf_alloc(const int size) /* 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) { struct ImBuf *buf; unsigned int *dr; @@ -332,7 +338,9 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short } /* 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) { struct ImBuf *buf; unsigned int *dr; @@ -389,6 +397,18 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) * to avoid the bias interfering with distance comparisons when mixing types. * \{ */ +#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) + +#define FAKE_SELECT_MODE_END(vc, fake_select_mode) \ + 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 @@ -462,11 +482,16 @@ BMVert *EDBM_vert_find_nearest_ex( BMVert *eve; /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ - ED_view3d_backbuf_validate(vc); + { + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX); + ED_view3d_backbuf_validate_with_select_mode(vc, select_mode); - index = ED_view3d_backbuf_sample_rect( - vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test); - eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL; + index = ED_view3d_backbuf_sample_rect( + vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test); + 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_test < *r_dist) { @@ -649,19 +674,16 @@ BMEdge *EDBM_edge_find_nearest_ex( unsigned int index; BMEdge *eed; - /* Make sure that the edges are considered for selection. - * TODO: cleanup: add `selectmode` as a parameter */ - const short ts_selectmode = vc->scene->toolsettings->selectmode; - vc->scene->toolsettings->selectmode |= SCE_SELECT_EDGE; - /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ - ED_view3d_backbuf_validate(vc); + { + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_EDGE); + ED_view3d_backbuf_validate_with_select_mode(vc, select_mode); - /* restore `selectmode` */ - vc->scene->toolsettings->selectmode = ts_selectmode; + index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test); + eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL; - index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test); - 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; @@ -822,10 +844,15 @@ BMFace *EDBM_face_find_nearest_ex( unsigned int index; BMFace *efa; - ED_view3d_backbuf_validate(vc); + { + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_FACE); + ED_view3d_backbuf_validate_with_select_mode(vc, select_mode); + + index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]); + efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL; - index = ED_view3d_backbuf_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; @@ -909,7 +936,9 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist) * selected vertices and edges get disadvantage * return 1 if found one */ -static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) +static bool unified_findnearest( + ViewContext *vc, + Base **r_base, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) { BMEditMesh *em = vc->em; static short mval_prev[2] = {-1, -1}; @@ -919,68 +948,143 @@ static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, /* since edges select lines, we give dots advantage of ~20 pix */ const float dist_margin = (dist_init / 2); float dist = dist_init; - BMFace *efa_zbuf = NULL; - BMEdge *eed_zbuf = NULL; - - BMVert *eve = NULL; - BMEdge *eed = NULL; - BMFace *efa = NULL; + struct { + struct { + BMVert *ele; + Base *base; + } v; + struct { + BMEdge *ele; + Base *base; + } e, e_zbuf; + struct { + BMFace *ele; + Base *base; + } f, f_zbuf; + } hit = {{NULL}}; + + /* TODO(campbell): perform selection as one pass + * instead of many smaller passes (which doesn't work for zbuf occlusion). */ + uint bases_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc->view_layer, &bases_len); /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - ED_view3d_backbuf_validate(vc); 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; - efa = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf); - if (efa && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } + + 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); + ED_view3d_backbuf_validate(vc); + BMFace *efa_zbuf = NULL; + BMFace *efa_test = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf); + if (hit.f.ele && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (efa_test) { + hit.f.base = base_iter; + hit.f.ele = efa_test; + } + if (efa_zbuf) { + hit.f_zbuf.base = base_iter; + 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; - eed = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf); - if (eed && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } + + 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); + ED_view3d_backbuf_validate(vc); + BMEdge *eed_zbuf = NULL; + BMEdge *eed_test = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf); + if (hit.e.ele && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (eed_test) { + hit.e.base = base_iter; + hit.e.ele = eed_test; + } + if (eed_zbuf) { + hit.e_zbuf.base = base_iter; + hit.e_zbuf.ele = eed_zbuf; + } + } /* bases */ } if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) { - eve = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle); + 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); + ED_view3d_backbuf_validate(vc); + BMVert *eve_test = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle); + if (eve_test) { + hit.v.base = base_iter; + hit.v.ele = eve_test; + } + } /* bases */ } + MEM_SAFE_FREE(bases); + /* return only one of 3 pointers, for frontbuffer redraws */ - if (eve) { - efa = NULL; eed = NULL; + if (hit.v.ele) { + hit.f.ele = NULL; + hit.e.ele = NULL; } - else if (eed) { - efa = 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 ((eve || eed || efa) == 0) { - if (eed_zbuf) { - eed = eed_zbuf; + if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) { + if (hit.e_zbuf.ele) { + hit.e.base = hit.e_zbuf.base; + hit.e.ele = hit.e_zbuf.ele; } - else if (efa_zbuf) { - efa = efa_zbuf; + else if (hit.f_zbuf.ele) { + hit.f.base = hit.f_zbuf.base; + hit.f.ele = hit.f_zbuf.ele; } } mval_prev[0] = vc->mval[0]; mval_prev[1] = vc->mval[1]; - *r_eve = eve; - *r_eed = eed; - *r_efa = efa; + /* 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 = hit.v.base; + } + if (hit.e.ele) { + *r_base = hit.e.base; + } + if (hit.f.ele) { + *r_base = hit.f.base; + } - return (eve || eed || efa); + *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 + /** \} */ /* -------------------------------------------------------------------- */ @@ -1014,13 +1118,13 @@ static const EnumPropertyItem prop_similar_types[] = { #endif {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""}, - {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""}, {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", ""}, #endif @@ -1199,7 +1303,7 @@ static const EnumPropertyItem *select_similar_type_itemf( #ifdef WITH_FREESTYLE const int a_end = SIMFACE_FREESTYLE; #else - const int a_end = SIMFACE_SMOOTH; + 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); @@ -1310,6 +1414,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) MEM_freeN(group_index); if (changed) { + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } else { @@ -1466,50 +1571,61 @@ static void walker_select(BMEditMesh *em, int walkercode, void *start, const boo static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMEdge *eed; - BMEdge **edarray; - int edindex; 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, &objects_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 totedgesel = 0; + if (em->bm->totedgesel == 0) { + continue; + } - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - totedgesel++; + 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; + 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++; + 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); + if (is_ring) { + for (edindex = 0; edindex < totedgesel; edindex += 1) { + eed = edarray[edindex]; + walker_select(em, BMW_EDGERING, eed, true); + } + EDBM_selectmode_flush(em); } - EDBM_selectmode_flush(em); - } - else { - for (edindex = 0; edindex < totedgesel; edindex += 1) { - eed = edarray[edindex]; - walker_select(em, BMW_EDGELOOP, eed, true); + else { + for (edindex = 0; edindex < totedgesel; edindex += 1) { + eed = edarray[edindex]; + walker_select(em, BMW_EDGELOOP, eed, true); + } + EDBM_selectmode_flush(em); } - EDBM_selectmode_flush(em); - } - MEM_freeN(edarray); -// if (EM_texFaceCheck()) + MEM_freeN(edarray); + // if (EM_texFaceCheck()) - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1607,17 +1723,6 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de mvalf[1] = (float)(vc.mval[1] = mval[1]); em = vc.em; - /* Make sure that the edges are also considered for selection. - * TODO: cleanup: add `selectmode` as a parameter */ - const short ts_selectmode = vc.scene->toolsettings->selectmode; - vc.scene->toolsettings->selectmode |= SCE_SELECT_EDGE; - - /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */ - ED_view3d_backbuf_validate(&vc); - - /* restore `selectmode` */ - vc.scene->toolsettings->selectmode = ts_selectmode; - eed = EDBM_edge_find_nearest_ex(&vc, &dist, NULL, true, true, NULL); if (eed == NULL) { return false; @@ -1721,6 +1826,7 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de } } + DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); return true; @@ -1794,27 +1900,44 @@ void MESH_OT_edgering_select(wmOperatorType *ot) static int edbm_select_all_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int action = RNA_enum_get(op->ptr, "action"); + 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, &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; + } + } + } - switch (action) { - case SEL_TOGGLE: - EDBM_select_toggle_all(em); - break; - 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; + 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, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1844,18 +1967,24 @@ void MESH_OT_select_all(wmOperatorType *ot) static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_len); - if (EDBM_select_interior_faces(em)) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; + if (!EDBM_select_interior_faces(em)) { + continue; + } + + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_select_interior_faces(wmOperatorType *ot) @@ -1885,6 +2014,8 @@ 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; + + Base *basact = NULL; BMVert *eve = NULL; BMEdge *eed = NULL; BMFace *efa = NULL; @@ -1894,11 +2025,24 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect vc.mval[0] = mval[0]; vc.mval[1] = mval[1]; - if (unified_findnearest(&vc, &eve, &eed, &efa)) { + if (unified_findnearest(&vc, &basact, &eve, &eed, &efa)) { + ED_view3d_viewcontext_init_object(&vc, basact->object); /* Deselect everything */ - if (extend == false && deselect == false && toggle == false) - EDBM_flag_disable_all(vc.em, BM_ELEM_SELECT); + if (extend == false && deselect == false && toggle == false) { + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + 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, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); + } + } + MEM_freeN(objects); + } if (efa) { if (extend) { @@ -1981,16 +2125,43 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect EDBM_selectmode_flush(vc.em); - /* change active material on object */ - if (efa && efa->mat_nr != vc.obedit->actcol - 1) { - vc.obedit->actcol = efa->mat_nr + 1; - vc.em->mat_nr = efa->mat_nr; + 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); + } - 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) { + vc.view_layer->basact = basact; + DEG_id_tag_update(&vc.scene->id, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, vc.scene); + } + DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); + return true; } @@ -2212,6 +2383,8 @@ 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; @@ -2225,6 +2398,7 @@ bool EDBM_selectmode_toggle( return ret; } + bool only_update = false; switch (action) { case -1: /* already set */ @@ -2232,21 +2406,24 @@ bool EDBM_selectmode_toggle( case 0: /* disable */ /* check we have something to do */ if ((em->selectmode & selectmode_new) == 0) { - return false; + only_update = true; + break; } em->selectmode &= ~selectmode_new; break; case 1: /* enable */ /* check we have something to do */ if ((em->selectmode & selectmode_new) != 0) { - return false; + 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) { - return false; + only_update = true; + break; } em->selectmode ^= selectmode_new; break; @@ -2255,10 +2432,30 @@ bool EDBM_selectmode_toggle( break; } + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &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); - EDBM_selectmode_convert(em, selmode_max, selectmode_new); + 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); + } } } @@ -2267,24 +2464,18 @@ bool EDBM_selectmode_toggle( if (use_extend == 0 || em->selectmode == 0) { em->selectmode = SCE_SELECT_VERTEX; } - ts->selectmode = em->selectmode; - EDBM_selectmode_set(em); ret = true; break; case SCE_SELECT_EDGE: if (use_extend == 0 || em->selectmode == 0) { em->selectmode = SCE_SELECT_EDGE; } - ts->selectmode = em->selectmode; - EDBM_selectmode_set(em); ret = true; break; case SCE_SELECT_FACE: if (use_extend == 0 || em->selectmode == 0) { em->selectmode = SCE_SELECT_FACE; } - ts->selectmode = em->selectmode; - EDBM_selectmode_set(em); ret = true; break; default: @@ -2293,10 +2484,20 @@ bool EDBM_selectmode_toggle( } if (ret == true) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + 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); + EDBM_selectmode_set(em_iter); + DEG_id_tag_update(ob_iter->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE); + 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, DEG_TAG_COPY_ON_WRITE); } + MEM_freeN(objects); return ret; } @@ -2498,7 +2699,7 @@ static bool select_linked_delimit_test( * Gets the default from the operator fallback to own last-used value * (selected based on mode) */ -static int select_linked_delimit_default_from_op(wmOperator *op, int select_mode) +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; @@ -2564,172 +2765,187 @@ static void select_linked_delimit_end(BMEditMesh *em) static int edbm_select_linked_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter; - BMWalker walker; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em->selectmode); + const int delimit_init = select_linked_delimit_default_from_op(op, scene->toolsettings->selectmode); #else - int delimit = RNA_enum_get(op->ptr, "delimit"); + const int delimit_init = RNA_enum_get(op->ptr, "delimit"); #endif - select_linked_delimit_validate(bm, &delimit); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (delimit) { - select_linked_delimit_begin(em->bm, delimit); - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; - if (em->selectmode & SCE_SELECT_VERTEX) { - BMVert *v; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter iter; + BMWalker walker; - 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)); - } + int delimit = delimit_init; + + select_linked_delimit_validate(bm, &delimit); - /* 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); - } - } + select_linked_delimit_begin(em->bm, delimit); } - 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 (em->selectmode & SCE_SELECT_VERTEX) { + BMVert *v; - 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); + 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); + 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); + BMW_end(&walker); - EDBM_selectmode_flush(em); - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *e; + 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))); + 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)); + 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); + 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); + 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); + 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)); + EDBM_selectmode_flush(em); } + else { + BMFace *f; - 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) { + BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT)); + } - 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_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); } - BMW_end(&walker); - } + if (delimit) { + select_linked_delimit_end(em); + } + + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - if (delimit) { - select_linked_delimit_end(em); } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -2872,10 +3088,8 @@ static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, in static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Object *obedit = CTX_data_edit_object(C); ViewContext vc; - BMEditMesh *em; - BMesh *bm; + Base *basact = NULL; BMVert *eve; BMEdge *eed; BMFace *efa; @@ -2891,25 +3105,37 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE /* setup view context for argument to callbacks */ em_setup_viewcontext(C, &vc); - em = vc.em; - bm = em->bm; - if (bm->totedge == 0) { - return OPERATOR_CANCELLED; + { + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, &objects_len); + bool has_edges = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + ED_view3d_viewcontext_init_object(&vc, ob_iter); + if (vc.em->bm->totedge) { + has_edges = true; + } + } + MEM_freeN(objects); + if (has_edges == false) { + return OPERATOR_CANCELLED; + } } vc.mval[0] = event->mval[0]; vc.mval[1] = event->mval[1]; /* return warning! */ - if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - + if (unified_findnearest(&vc, &basact, &eve, &eed, &efa) == 0) { return OPERATOR_CANCELLED; } + 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, em->selectmode); + int delimit = select_linked_delimit_default_from_op(op, vc.scene->toolsettings->selectmode); #else int delimit = RNA_enum_get(op->ptr, "delimit"); #endif @@ -2922,9 +3148,12 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE 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); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(basact->object->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data); return OPERATOR_FINISHED; } @@ -2953,6 +3182,7 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op) edbm_select_linked_pick_ex(em, ele, sel, delimit); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -2995,47 +3225,57 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot) static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMIter iter; + 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, &objects_len); - if (!RNA_boolean_get(op->ptr, "extend")) - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + 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; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!extend) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } - bool 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; - } + 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); + if (select) { + BM_face_select_set(em->bm, efa, true); + } } - } - EDBM_selectmode_flush(em); + EDBM_selectmode_flush(em); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3075,53 +3315,66 @@ void MESH_OT_select_face_by_sides(wmOperatorType *ot) static int edbm_select_loose_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter; + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool extend = RNA_boolean_get(op->ptr, "extend"); - if (!RNA_boolean_get(op->ptr, "extend")) - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - 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); - } + 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_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_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_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 (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 (is_loose) { - BM_face_select_set(bm, efa, 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, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } - EDBM_selectmode_flush(em); + MEM_freeN(objects); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -3151,28 +3404,48 @@ void MESH_OT_select_loose(wmOperatorType *ot) static int edbm_select_mirror_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + 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, &objects_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->totvert && em->bm->totvertsel) { - int totmirr, totfail; + 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, &totmirr, &totfail); + EDBM_select_mirrored(em, axis, extend, &tot_mirr_iter, &tot_fail_iter); } } - if (totmirr) { + if (tot_mirr_iter) { EDBM_selectmode_flush(em); + + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } - ED_mesh_report_mirror_ex(op, totmirr, totfail, em->bm->selectmode); + 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; } @@ -3204,13 +3477,29 @@ void MESH_OT_select_mirror(wmOperatorType *ot) static int edbm_select_more_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); - EDBM_select_more(em, use_face_step); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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; - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + if ((bm->totvertsel == 0) && + (bm->totedgesel == 0) && + (bm->totfacesel == 0)) + { + continue; + } + + EDBM_select_more(em, use_face_step); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3239,13 +3528,29 @@ void MESH_OT_select_more(wmOperatorType *ot) static int edbm_select_less_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); - EDBM_select_less(em, use_face_step); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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; - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + if ((bm->totvertsel == 0) && + (bm->totedgesel == 0) && + (bm->totfacesel == 0)) + { + continue; + } + + EDBM_select_less(em, use_face_step); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3458,18 +3763,39 @@ static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams static int edbm_select_nth_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + 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; - if (edbm_deselect_nth(em, &op_params) == false) { - BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face"); - return OPERATOR_CANCELLED; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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); - EDBM_update_generic(em, false, false); + 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; } @@ -3513,34 +3839,43 @@ static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op) * check the angle between those faces, and if angle is * small enough, select the edge */ - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - BMEdge *e; - BMLoop *l1, *l2; const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness")); - 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); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (angle_cos < angle_limit_cos) { - BM_edge_select_set(em->bm, e, true); + 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); + 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, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3575,59 +3910,71 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot) static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - BLI_LINKSTACK_DECLARE(stack, BMFace *); - - BMIter iter, liter, liter2; - BMFace *f; - BMLoop *l, *l2; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness")); - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - - BLI_LINKSTACK_INIT(stack); + 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_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)) - { + if (bm->totfacesel == 0) { continue; } - BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); + BLI_LINKSTACK_DECLARE(stack, BMFace *); - do { - BM_face_select_set(bm, f, true); + BMIter iter, liter, liter2; + BMFace *f; + BMLoop *l, *l2; - BM_elem_flag_enable(f, BM_ELEM_TAG); + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { - float angle_cos; + BLI_LINKSTACK_INIT(stack); - if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || - BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) - { - 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); + + do { + BM_face_select_set(bm, f, true); + + BM_elem_flag_enable(f, BM_ELEM_TAG); - angle_cos = dot_v3v3(f->no, l2->f->no); + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { + float angle_cos; - if (angle_cos > angle_limit_cos) { - BLI_LINKSTACK_PUSH(stack, l2->f); + 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); + + if (angle_cos > angle_limit_cos) { + BLI_LINKSTACK_PUSH(stack, l2->f); + } } } - } - } while ((f = BLI_LINKSTACK_POP(stack))); - } + } while ((f = BLI_LINKSTACK_POP(stack))); + } - BLI_LINKSTACK_FREE(stack); + BLI_LINKSTACK_FREE(stack); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3662,61 +4009,71 @@ void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMVert *v; - BMEdge *e; - BMIter iter; - + 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, &objects_len); - if (!RNA_boolean_get(op->ptr, "extend")) - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + 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; - /* Selects isolated verts, and edges that do not have 2 neighboring - * faces - */ + if (!use_extend) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } - if (em->selectmode == SCE_SELECT_FACE) { - BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode"); - return OPERATOR_CANCELLED; - } + /* Selects isolated verts, and edges that do not have 2 neighboring + * faces + */ - 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 (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))); + 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); + BM_edge_select_set(em->bm, e, true); + } } } } - } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - EDBM_selectmode_flush(em); + EDBM_selectmode_flush(em); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3759,53 +4116,67 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) static int edbm_select_random_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); 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); - BMIter iter; + ViewLayer *view_layer = CTX_data_view_layer(C); - RNG *rng = BLI_rng_new_srandom(seed); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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; - 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); + /* 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 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); + 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); + 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); - } + if (select) { + /* was EDBM_select_flush, but it over select in edge/face mode */ + EDBM_selectmode_flush(em); + } + else { + EDBM_deselect_flush(em); + } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3855,30 +4226,52 @@ static int edbm_select_ungrouped_poll(bContext *C) static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op) { - 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); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + ViewLayer *view_layer = CTX_data_view_layer(C); - BMVert *eve; - BMIter iter; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (!RNA_boolean_get(op->ptr, "extend")) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - } + 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; + } - 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); + BMVert *eve; + BMIter iter; + + bool changed = false; + + if (!extend) { + if (em->bm->totvertsel) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + changed = true; } } - } - EDBM_selectmode_flush(em); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + 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, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3998,48 +4391,59 @@ void MESH_OT_select_axis(wmOperatorType *ot) static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *f; - 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, &objects_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_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_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(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; - } + 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); + 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); + 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); + 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); - } + /* 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); + } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -4210,31 +4614,45 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) static int edbm_loop_to_region_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - BMFace *f; const bool select_bigger = RNA_boolean_get(op->ptr, "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); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - 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); + if (em->bm->totedgesel == 0) { + continue; + } - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + 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); + + 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); - 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, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 70c4f341bd8..3fdca4562d1 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -47,15 +47,18 @@ #include "BLI_rand.h" #include "BLI_sort_utils.h" +#include "BKE_layer.h" #include "BKE_material.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_report.h" #include "BKE_texture.h" #include "BKE_main.h" #include "BKE_editmesh.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "BLT_translation.h" #include "RNA_define.h" @@ -90,29 +93,45 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); const int cuts = RNA_int_get(op->ptr, "number_cuts"); - float smooth = RNA_float_get(op->ptr, "smoothness"); + 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, "quadtri") && + 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"); - BM_mesh_esubdivide( - em->bm, BM_ELEM_SELECT, - smooth, SUBD_FALLOFF_LIN, false, - fractal, along_normal, - cuts, - SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"), - RNA_boolean_get(op->ptr, "quadtri"), true, false, - 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, &objects_len); - EDBM_update_generic(em, true, true); + 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; } @@ -149,7 +168,9 @@ void MESH_OT_subdivide(wmOperatorType *ot) RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f); - RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons"); + 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)"); @@ -222,24 +243,36 @@ static void mesh_operator_edgering_props_get(wmOperator *op, struct EdgeRingOpSu static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_len); struct EdgeRingOpSubdProps op_props; mesh_operator_edgering_props_get(op, &op_props); - 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)) - { - return OPERATOR_CANCELLED; - } + 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, true); + 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; + } + + EDBM_update_generic(em, true, true); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -269,27 +302,39 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot) static int edbm_unsubdivide_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMOperator bmop; - 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, &objects_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_op_init(em, &bmop, op, - "unsubdivide verts=%hv iterations=%i", BM_ELEM_SELECT, iterations); + if ((em->bm->totvertsel == 0) && + (em->bm->totedgesel == 0) && + (em->bm->totfacesel == 0)) + { + continue; + } - BMO_op_exec(em->bm, &bmop); + BMOperator bmop; + EDBM_op_init(em, &bmop, op, + "unsubdivide verts=%hv iterations=%i", BM_ELEM_SELECT, iterations); - if (!EDBM_op_finish(em, &bmop, op, true)) { - return 0; - } + BMO_op_exec(em->bm, &bmop); - 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 (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - EDBM_update_generic(em, true, true); + 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); return OPERATOR_FINISHED; } @@ -314,6 +359,7 @@ void MESH_OT_unsubdivide(wmOperatorType *ot) void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) { + Main *bmain = CTX_data_main(C); Object *obedit = em->ob; BMIter iter; BMVert *eve; @@ -321,21 +367,22 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) ED_view3d_init_mats_rv3d(obedit, ar->regiondata); struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), 0, + 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_mixed( + if (ED_transform_snap_object_project_view3d( snap_context, - SCE_SELECT_FACE, + SCE_SNAP_MODE_FACE, &(const struct SnapObjectParams){ .snap_select = SNAP_NOT_ACTIVE, .use_object_edit_cage = false, + .use_occlusion_test = true, }, - mval, NULL, true, + mval, NULL, co_proj, NULL)) { mul_v3_m4v3(eve->co, obedit->imat, co_proj); @@ -362,52 +409,79 @@ enum { MESH_DELETE_ONLY_FACE = 4, }; -static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int totelem[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[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface); + 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) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int type = RNA_enum_get(op->ptr, "type"); + ViewLayer *view_layer = CTX_data_view_layer(C); - switch (type) { - case MESH_DELETE_VERT: - if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */ - return OPERATOR_CANCELLED; - break; - case MESH_DELETE_EDGE: - if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */ - return OPERATOR_CANCELLED; - break; - case MESH_DELETE_FACE: - if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */ - return OPERATOR_CANCELLED; - break; - case MESH_DELETE_EDGE_FACE: - /* Edges and Faces */ - if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)) - return OPERATOR_CANCELLED; - break; - case MESH_DELETE_ONLY_FACE: - /* Only faces. */ - if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES)) - return OPERATOR_CANCELLED; - 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, &objects_len); + bool changed_multi = false; - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + 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"); - EDBM_update_generic(em, true, true); + 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; + } - return OPERATOR_FINISHED; + 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) @@ -438,6 +512,7 @@ void MESH_OT_delete(wmOperatorType *ot) /* 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); } /** \} */ @@ -462,61 +537,75 @@ static bool bm_face_is_loose(BMFace *f) static int edbm_delete_loose_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter; + ViewLayer *view_layer = CTX_data_view_layer(C); + int totelem_old_sel[3]; + int totelem_old[3]; - const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && bm->totvertsel); - const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && bm->totedgesel); - const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && bm->totfacesel); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - const int totelem[3] = {bm->totvert, bm->totedge, bm->totface}; + 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]); - BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; - if (use_faces) { - BMFace *f; + 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); + + 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_update_generic(em, true, true); } - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + int totelem_new[3]; + EDBM_mesh_stats_multi(objects, objects_len, totelem_new, NULL); - EDBM_update_generic(em, true, true); + edbm_report_delete_info(op->reports, totelem_old, totelem_new); - edbm_report_delete_info(op->reports, bm, totelem); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -551,13 +640,24 @@ void MESH_OT_delete_loose(wmOperatorType *ot) static int edbm_collapse_edge_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_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_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true)) - return OPERATOR_CANCELLED; + if (em->bm->totedgesel == 0) { + continue; + } - EDBM_update_generic(em, true, true); + 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); return OPERATOR_FINISHED; } @@ -760,70 +860,83 @@ static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) { - BMOperator bmop; - Object *obedit = CTX_data_edit_object(C); - 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; /* when this is used to dissolve we could avoid this, but checking isnt too slow */ -#ifdef USE_FACE_CREATE_SEL_EXTEND - BMElem *ele_desel; - BMFace *ele_desel_face; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* 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 ((em->bm->totvertsel == 0) && + (em->bm->totedgesel == 0) && + (em->bm->totvertsel == 0)) + { + 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)) - { - return OPERATOR_CANCELLED; - } + bool use_smooth = edbm_add_edge_face__smooth_get(em->bm); + int totedge_orig = em->bm->totedge; + int totface_orig = em->bm->totface; - BMO_op_exec(em->bm, &bmop); + BMOperator bmop; +#ifdef USE_FACE_CREATE_SEL_EXTEND + BMElem *ele_desel; + BMFace *ele_desel_face; - /* cancel if nothing was done */ - if ((totedge_orig == em->bm->totedge) && - (totface_orig == em->bm->totface)) - { - EDBM_op_finish(em, &bmop, op, true); - return OPERATOR_CANCELLED; - } + /* 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; + } #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); + { + /* 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); - } + 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)) { - return OPERATOR_CANCELLED; - } + 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; } @@ -852,37 +965,51 @@ void MESH_OT_edge_face_add(wmOperatorType *ot) static int edbm_mark_seam_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - Mesh *me = ((Mesh *)obedit->data); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; + ViewLayer *view_layer = CTX_data_view_layer(C); BMEdge *eed; BMIter iter; const bool clear = RNA_boolean_get(op->ptr, "clear"); - /* auto-enable seams drawing */ - if (clear == 0) { - me->drawflag |= ME_DRAWSEAMS; - } + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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 (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; + if (bm->totedgesel == 0) { + continue; + } - BM_elem_flag_disable(eed, BM_ELEM_SEAM); + Mesh *me = ((Mesh *)obedit->data); + + /* auto-enable seams drawing */ + if (clear == 0) { + me->drawflag |= ME_DRAWSEAMS; } - } - 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); + + 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, obedit); - EDBM_update_generic(em, true, false); + ED_uvedit_live_unwrap(scene, obedit); + EDBM_update_generic(em, true, false); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -904,7 +1031,9 @@ void MESH_OT_mark_seam(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + WM_operatortype_props_advanced_begin(ot); } /** \} */ @@ -915,34 +1044,45 @@ void MESH_OT_mark_seam(wmOperatorType *ot) static int edbm_mark_sharp_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - Mesh *me = ((Mesh *)obedit->data); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; 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); - /* auto-enable sharp edge drawing */ - if (clear == 0) { - me->drawflag |= ME_DRAWSHARP; - } + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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; + Mesh *me = ((Mesh *)obedit->data); - 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))) { + if (bm->totedgesel == 0) { + continue; + } + + /* auto-enable sharp edge drawing */ + if (clear == 0) { + me->drawflag |= ME_DRAWSHARP; + } + + 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; } - } - else if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - continue; + + BM_elem_flag_set(eed, BM_ELEM_SMOOTH, clear); } - BM_elem_flag_set(eed, BM_ELEM_SMOOTH, clear); + EDBM_update_generic(em, true, false); } - - EDBM_update_generic(em, true, false); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -964,23 +1104,28 @@ void MESH_OT_mark_sharp(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + 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 int edbm_vert_connect_exec(bContext *C, wmOperator *op) +static bool edbm_connect_vert_pair(BMEditMesh *em, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; BMOperator bmop; - bool is_pair = (bm->totvertsel == 2); + const int verts_len = bm->totvertsel; + bool is_pair = (verts_len == 2); int len = 0; bool check_degenerate = true; - const int verts_len = bm->totvertsel; + BMVert **verts; + bool checks_succeded = true; + + /* sanity check */ + if (!is_pair) { + return false; + } verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__); { @@ -988,20 +1133,18 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) BMVert *v; int i = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { verts[i++] = v; } } - if (is_pair) { - 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 (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; } } @@ -1011,7 +1154,7 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf", verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN)) { - goto finally; + checks_succeded = false; } } else { @@ -1020,33 +1163,49 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b", verts, verts_len, BM_ELEM_HIDDEN, check_degenerate)) { - goto finally; + checks_succeded = false; } } + if (checks_succeded) { + BMO_op_exec(bm, &bmop); + len = BMO_slot_get(bmop.slots_out, "edges.out")->len; - BMO_op_exec(bm, &bmop); - len = BMO_slot_get(bmop.slots_out, "edges.out")->len; - - if (len) { - if (is_pair) { + 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 { - EDBM_selectmode_flush(em); /* so newly created edges get the selection state from the vertex */ + if (!EDBM_op_finish(em, &bmop, op, true)) { + len = 0; + } + else { + EDBM_selectmode_flush(em); /* so newly created edges get the selection state from the vertex */ - EDBM_update_generic(em, true, true); + EDBM_update_generic(em, true, true); + } } + MEM_freeN(verts); + return len; +} -finally: - MEM_freeN(verts); - return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +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, &objects_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_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) @@ -1285,43 +1444,66 @@ static bool bm_vert_connect_select_history_edge_to_vert_path(BMesh *bm, ListBase static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - bool is_pair = (em->bm->totvertsel == 2); - ListBase selected_orig = {NULL, NULL}; - int retval; + 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, &objects_len); - /* when there is only 2 vertices, we can ignore selection order */ - if (is_pair) { - return edbm_vert_connect_exec(C, op); - } + 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->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->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_vert_connect_select_history(bm)) { - EDBM_selectmode_flush(em); - EDBM_update_generic(em, true, true); - retval = OPERATOR_FINISHED; + 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; + } } - else { + + MEM_freeN(objects); + + if (failed_selection_order_len == objects_len) { BKE_report(op->reports, RPT_ERROR, "Invalid selection order"); - retval = OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } - - if (!BLI_listbase_is_empty(&selected_orig)) { - BM_select_history_clear(bm); - bm->selected = selected_orig; + else if (failed_connect_len == objects_len) { + BKE_report(op->reports, RPT_ERROR, "Could not connect vertices"); + return OPERATOR_CANCELLED; } - return retval; + return OPERATOR_FINISHED; } void MESH_OT_vert_connect_path(wmOperatorType *ot) @@ -1341,20 +1523,29 @@ void MESH_OT_vert_connect_path(wmOperatorType *ot) static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_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_op_call_and_selectf( - em, op, - "faces.out", true, - "connect_verts_concave faces=%hf", - BM_ELEM_SELECT)) - { - return OPERATOR_CANCELLED; - } + 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); + } - EDBM_update_generic(em, true, true); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1381,22 +1572,32 @@ void MESH_OT_vert_connect_concave(wmOperatorType *ot) static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - + 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, &objects_len); - if (!EDBM_op_call_and_selectf( - em, op, - "faces.out", true, - "connect_verts_nonplanar faces=%hf angle_limit=%f", - BM_ELEM_SELECT, angle_limit)) - { - return OPERATOR_CANCELLED; - } + 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_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); return OPERATOR_FINISHED; } @@ -1430,19 +1631,31 @@ void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot) static int edbm_face_make_planar_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_len); + const int repeat = RNA_int_get(op->ptr, "repeat"); const float fac = RNA_float_get(op->ptr, "factor"); - if (!EDBM_op_callf( - em, op, "planar_faces faces=%hf iterations=%i factor=%f", - BM_ELEM_SELECT, repeat, fac)) - { - return OPERATOR_CANCELLED; + 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; + } + + EDBM_update_generic(em, true, true); } + MEM_freeN(objects); - EDBM_update_generic(em, true, true); return OPERATOR_FINISHED; } @@ -1473,23 +1686,32 @@ void MESH_OT_face_make_planar(wmOperatorType *ot) static int edbm_edge_split_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_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)) - { - return OPERATOR_CANCELLED; - } + 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); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1517,33 +1739,43 @@ void MESH_OT_edge_split(wmOperatorType *ot) static int edbm_duplicate_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - BMOperator bmop; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - EDBM_op_init( - em, &bmop, op, - "duplicate geom=%hvef use_select_history=%b", - BM_ELEM_SELECT, true); + 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; + } - BMO_op_exec(bm, &bmop); + BMOperator bmop; + BMesh *bm = em->bm; - /* de-select all would clear otherwise */ - BM_SELECT_HISTORY_BACKUP(bm); + EDBM_op_init( + em, &bmop, op, + "duplicate geom=%hvef use_select_history=%b", + BM_ELEM_SELECT, true); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_op_exec(bm, &bmop); - BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + /* de-select all would clear otherwise */ + BM_SELECT_HISTORY_BACKUP(bm); - /* rebuild editselection */ - BM_SELECT_HISTORY_RESTORE(bm); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); - EDBM_update_generic(em, true, true); + /* 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); return OPERATOR_FINISHED; } @@ -1581,18 +1813,29 @@ void MESH_OT_duplicate(wmOperatorType *ot) * \{ */ static int edbm_flip_normals_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_len); - if (!EDBM_op_callf( - em, op, "reverse_faces faces=%hf flip_multires=%b", - BM_ELEM_SELECT, true)) - { - return OPERATOR_CANCELLED; - } + 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); + if (em->bm->totfacesel == 0) { + 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); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1622,71 +1865,99 @@ void MESH_OT_flip_normals(wmOperatorType *ot) */ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMOperator bmop; BMEdge *eed; BMIter iter; const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw"); - int tot = 0; - if (em->bm->totedgesel == 0) { - BKE_report(op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about"); - return OPERATOR_CANCELLED; - } + 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, &objects_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++; + /* 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) { - BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated"); - return OPERATOR_CANCELLED; - } + /* 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; - EDBM_op_init(em, &bmop, op, "rotate_edges edges=%he use_ccw=%b", BM_ELEM_TAG, use_ccw); + 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); + /* 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 ilogical 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); + BMO_op_exec(em->bm, &bmop); + /* edges may rotate into hidden vertices, if this does _not_ run we get an ilogical 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; - 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); + 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); + } - BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed); + EDBM_selectmode_flush(em); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_update_generic(em, true, true); } + MEM_freeN(objects); - EDBM_selectmode_flush(em); + if (no_selected_edges) { + BKE_report(op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about"); + return OPERATOR_CANCELLED; + } - if (!EDBM_op_finish(em, &bmop, op, true)) { + /* 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; } - EDBM_update_generic(em, true, true); + if (tot_failed_all != 0) { + BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all); + } return OPERATOR_FINISHED; } @@ -1717,13 +1988,28 @@ void MESH_OT_edge_rotate(wmOperatorType *ot) static int edbm_hide_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + const bool unselected = RNA_boolean_get(op->ptr, "unselected"); + ViewLayer *view_layer = CTX_data_view_layer(C); - EDBM_mesh_hide(em, RNA_boolean_get(op->ptr, "unselected")); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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; - EDBM_update_generic(em, true, false); + if ((bm->totvertsel == 0) && + (bm->totedgesel == 0) && + (bm->totfacesel == 0)) + { + continue; + } + EDBM_mesh_hide(em, unselected); + EDBM_update_generic(em, true, false); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1753,13 +2039,19 @@ void MESH_OT_hide(wmOperatorType *ot) static int edbm_reveal_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); const bool select = RNA_boolean_get(op->ptr, "select"); + ViewLayer *view_layer = CTX_data_view_layer(C); - EDBM_mesh_reveal(em, select); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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); + EDBM_mesh_reveal(em, select); + EDBM_update_generic(em, true, false); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1789,19 +2081,28 @@ void MESH_OT_reveal(wmOperatorType *ot) static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); - /* doflip has to do with bmesh_rationalize_normals, it's an internal - * thing */ - if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) - return OPERATOR_CANCELLED; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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 (RNA_boolean_get(op->ptr, "inside")) { - EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true); - } + if (em->bm->totfacesel == 0) { + continue; + } - EDBM_update_generic(em, true, false); + 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); return OPERATOR_FINISHED; } @@ -1831,72 +2132,83 @@ void MESH_OT_normals_make_consistent(wmOperatorType *ot) static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - Mesh *me = obedit->data; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - ModifierData *md; - bool mirrx = false, mirry = false, mirrz = false; - int i, repeat; - float clip_dist = 0.0f; const float fac = RNA_float_get(op->ptr, "factor"); - const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; 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"); - /* mirror before smooth */ - if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { - EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology); + if (!repeat) { + repeat = 1; } - /* 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; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &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; + } } } - } - repeat = RNA_int_get(op->ptr, "repeat"); - if (!repeat) - repeat = 1; + 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; + } + } - 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)) - { - return OPERATOR_CANCELLED; + /* 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); } - } - /* 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); } - - EDBM_update_generic(em, true, false); + MEM_freeN(objects); return OPERATOR_FINISHED; } - void MESH_OT_vertices_smooth(wmOperatorType *ot) { /* identifiers */ @@ -1913,6 +2225,9 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot) RNA_def_float(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); + 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"); @@ -1999,10 +2314,13 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot) 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", 5e-5f, 1e-7f, 1000.0f, + 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"); @@ -2031,12 +2349,21 @@ static void mesh_set_smooth_faces(BMEditMesh *em, short smooth) static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_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_set_smooth_faces(em, 1); + if (em->bm->totfacesel == 0) { + continue; + } - EDBM_update_generic(em, false, false); + mesh_set_smooth_faces(em, 1); + EDBM_update_generic(em, false, false); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -2064,12 +2391,21 @@ void MESH_OT_faces_shade_smooth(wmOperatorType *ot) static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_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_set_smooth_faces(em, 0); + if (em->bm->totfacesel == 0) { + continue; + } - EDBM_update_generic(em, false, false); + mesh_set_smooth_faces(em, 0); + EDBM_update_generic(em, false, false); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -2097,73 +2433,105 @@ void MESH_OT_faces_shade_flat(wmOperatorType *ot) static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMOperator bmop; - /* get the direction from RNA */ const bool use_ccw = RNA_boolean_get(op->ptr, "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); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* execute the operator */ - BMO_op_exec(em->bm, &bmop); + if (em->bm->totfacesel == 0) { + continue; + } - /* finish the operator */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } + BMOperator bmop; - EDBM_update_generic(em, false, false); + /* 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); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_update_generic(em, false, false); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMOperator bmop; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* 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); + if (em->bm->totfacesel == 0) { + continue; + } - /* execute the operator */ - BMO_op_exec(em->bm, &bmop); + BMOperator bmop; - /* finish the operator */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } + /* 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); - EDBM_update_generic(em, false, false); + /* 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); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } static int edbm_rotate_colors_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMOperator bmop; - - /* get the direction from RNA */ + /* get the direction from RNA */ const bool use_ccw = RNA_boolean_get(op->ptr, "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); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - /* execute the operator */ - BMO_op_exec(em->bm, &bmop); + 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; + } - /* finish the operator */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; + 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); + + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); + + /* 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); return OPERATOR_FINISHED; } @@ -2326,7 +2694,7 @@ static bool merge_target( const float *vco = NULL; if (use_cursor) { - vco = ED_view3d_cursor3d_get(scene, v3d); + vco = ED_view3d_cursor3d_get(scene, v3d)->location; copy_v3_v3(co, vco); invert_m4_m4(ob->imat, ob->obmat); mul_m4_v3(ob->imat, co); @@ -2368,44 +2736,60 @@ static int edbm_merge_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); - Object *obedit = CTX_data_edit_object(C); - 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, &objects_len); const int type = RNA_enum_get(op->ptr, "type"); const bool uvs = RNA_boolean_get(op->ptr, "uvs"); - bool ok = false; - switch (type) { - case MESH_MERGE_CENTER: - ok = merge_target(em, scene, v3d, obedit, false, uvs, op); - break; - case MESH_MERGE_CURSOR: - ok = merge_target(em, scene, v3d, 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; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (!ok) { - return OPERATOR_CANCELLED; - } + if (em->bm->totvertsel == 0) { + continue; + } - EDBM_update_generic(em, true, true); + bool ok = false; + switch (type) { + case MESH_MERGE_CENTER: + ok = merge_target(em, scene, v3d, obedit, false, uvs, op); + break; + case MESH_MERGE_CURSOR: + ok = merge_target(em, scene, v3d, 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; + } - /* once collapsed, we can't have edge/face selection */ - if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + 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; } @@ -2431,6 +2815,10 @@ static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED( 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 && @@ -2478,6 +2866,9 @@ void MESH_OT_merge(wmOperatorType *ot) /* 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); + RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge"); } @@ -2489,60 +2880,79 @@ void MESH_OT_merge(wmOperatorType *ot) static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMOperator bmop; const float threshold = RNA_float_get(op->ptr, "threshold"); const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected"); - const int totvert_orig = em->bm->totvert; - int count; - char htype_select; + int count_multi = 0; - /* avoid loosing selection state (select -> tags) */ - 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; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - /* store selection as tags */ - BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT); + 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; + } - if (use_unselected) { - EDBM_op_init( - em, &bmop, op, - "automerge verts=%hv dist=%f", - BM_ELEM_SELECT, threshold); - BMO_op_exec(em->bm, &bmop); + BMOperator bmop; + const int totvert_orig = em->bm->totvert; - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } - } - else { - EDBM_op_init( - em, &bmop, op, - "find_doubles verts=%hv dist=%f", - BM_ELEM_SELECT, threshold); - BMO_op_exec(em->bm, &bmop); + /* avoid loosing 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; - if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) { - BMO_op_finish(em->bm, &bmop); - return OPERATOR_CANCELLED; + /* 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 (!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)) { - return OPERATOR_CANCELLED; + 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_finish(em, &bmop, op, true)) { + continue; + } } - } - count = totvert_orig - em->bm->totvert; - BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count); + 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); - EDBM_update_generic(em, true, true); + 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); return OPERATOR_FINISHED; } @@ -2599,7 +3009,7 @@ static void shape_propagate(BMEditMesh *em, wmOperator *op) //TAG Mesh Objects that share this data for (base = scene->base.first; base; base = base->next) { if (base->object && base->object->data == me) { - DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); + DEG_id_tag_update(&base->object->id, OB_RECALC_DATA); } } #endif @@ -2779,39 +3189,48 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot) static int edbm_solidify_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - Mesh *me = obedit->data; - BMEditMesh *em = me->edit_btmesh; - BMesh *bm = em->bm; - BMOperator bmop; - const float thickness = RNA_float_get(op->ptr, "thickness"); - if (!EDBM_op_init(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) { - return 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, &objects_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; - /* 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); + if (em->bm->totfacesel == 0) { + continue; + } - /* run the solidify operator */ - BMO_op_exec(bm, &bmop); + BMOperator bmop; - /* 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_init(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) { + continue; + } - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } + /* 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); - EDBM_update_generic(em, true, true); + /* 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); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_update_generic(em, true, true); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } - void MESH_OT_solidify(wmOperatorType *ot) { PropertyRNA *prop; @@ -3184,7 +3603,7 @@ enum { MESH_SEPARATE_LOOSE = 2, }; -static Base *mesh_separate_tagged(Main *bmain, Scene *scene, 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; @@ -3205,11 +3624,11 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe 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, base_old, USER_DUP_MESH); + base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, USER_DUP_MESH); /* DAG_relations_tag_update(bmain); */ /* normally would call directly after but in this case delay recalc */ assign_matarar(bmain, base_new->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ - ED_base_object_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); @@ -3231,7 +3650,7 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe return base_new; } -static bool mesh_separate_selected(Main *bmain, Scene *scene, 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); @@ -3239,7 +3658,7 @@ static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BM /* 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, 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 */ @@ -3338,7 +3757,7 @@ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const } } -static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) +static bool mesh_separate_material(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) { BMFace *f_cmp, *f; BMIter iter; @@ -3379,7 +3798,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM } /* Move selection into a separate object */ - base_new = mesh_separate_tagged(bmain, scene, base_old, bm_old); + 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); } @@ -3390,7 +3809,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM return result; } -static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) +static bool mesh_separate_loose(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) { int i; BMEdge *e; @@ -3443,7 +3862,7 @@ static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG); /* Move selection into a separate object */ - result |= (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL); + result |= (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL); } return result; @@ -3453,42 +3872,52 @@ 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)) { - Base *base = CTX_data_active_base(C); - BMEditMesh *em = BKE_editmesh_from_object(base->object); - - if (type == 0) { - if ((em->bm->totvertsel == 0) && - (em->bm->totedgesel == 0) && - (em->bm->totfacesel == 0)) - { - BKE_report(op->reports, RPT_ERROR, "Nothing selected"); - return OPERATOR_CANCELLED; + uint bases_len = 0; + uint empty_selection_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, &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, base, em->bm); - break; - case MESH_SEPARATE_MATERIAL: - retval = mesh_separate_material(bmain, scene, base, em->bm); - break; - case MESH_SEPARATE_LOOSE: - retval = mesh_separate_loose(bmain, scene, base, em->bm); - break; - default: - BLI_assert(0); - break; - } + /* 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); + if (retval) { + EDBM_update_generic(em, true, true); + } } + MEM_freeN(bases); } else { if (type == MESH_SEPARATE_SELECTED) { @@ -3514,10 +3943,10 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) switch (type) { case MESH_SEPARATE_MATERIAL: - retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old); + 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, base_iter, bm_old); + retval_iter = mesh_separate_loose(bmain, scene, view_layer, base_iter, bm_old); break; default: BLI_assert(0); @@ -3531,7 +3960,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) .calc_object_remap = true, })); - DAG_id_tag_update(&me->id, OB_RECALC_DATA); + DEG_id_tag_update(&me->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); } @@ -3546,7 +3975,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) if (retval) { /* delay depsgraph recalc until all objects are duplicated */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); return OPERATOR_FINISHED; @@ -3588,45 +4017,64 @@ void MESH_OT_separate(wmOperatorType *ot) static int edbm_fill_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty"); - BMOperator bmop; - const int totface_orig = em->bm->totface; - int ret; - if (em->bm->totedgesel == 0) { - BKE_report(op->reports, RPT_WARNING, "No edges selected"); - return OPERATOR_CANCELLED; - } + bool has_selected_edges = false, has_faces_filled = false; - if (!EDBM_op_init(em, &bmop, op, - "triangle_fill edges=%he use_beauty=%b", - BM_ELEM_SELECT, use_beauty)) - { - return 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, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMO_op_exec(em->bm, &bmop); + const int totface_orig = em->bm->totface; + + 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; + } + + 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; - if (totface_orig != em->bm->totface) { /* select new geometry */ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true); - EDBM_update_generic(em, true, true); + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - ret = OPERATOR_FINISHED; + EDBM_update_generic(em, true, true); } - else { - BKE_report(op->reports, RPT_WARNING, "No faces filled"); - ret = OPERATOR_CANCELLED; + MEM_freeN(objects); + + if (!has_selected_edges) { + BKE_report(op->reports, RPT_ERROR, "No edges selected"); + return OPERATOR_CANCELLED; } - if (!EDBM_op_finish(em, &bmop, op, true)) { - ret = OPERATOR_CANCELLED; + if (!has_faces_filled) { + BKE_report(op->reports, RPT_WARNING, "No faces filled"); + return OPERATOR_CANCELLED; } - return ret; + return OPERATOR_FINISHED; } void MESH_OT_fill(wmOperatorType *ot) @@ -3800,73 +4248,91 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span static int edbm_fill_grid_exec(bContext *C, wmOperator *op) { - BMOperator bmop; - Object *obedit = CTX_data_edit_object(C); - 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; - const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple"); 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, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - 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; + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int clamp = em->bm->totvertsel; - int span; - int offset; + 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 (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; + if (em->bm->totedgesel == 0) { + continue; } - offset = RNA_property_int_get(op->ptr, prop_offset); - offset = clamp ? mod_i(offset, clamp) : 0; + 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; - /* in simple cases, move selection for tags, but also support more advanced cases */ - edbm_fill_grid_prepare(em->bm, offset, &span, calc_span); + const int clamp = em->bm->totvertsel; + int span; + int offset; - RNA_property_int_set(op->ptr, prop_span, span); - } - /* end tricky prepare code */ + if (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; - 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)) - { - return OPERATOR_CANCELLED; - } + /* in simple cases, move selection for tags, but also support more advanced cases */ + edbm_fill_grid_prepare(em->bm, offset, &span, calc_span); - BMO_op_exec(em->bm, &bmop); + RNA_property_int_set(op->ptr, prop_span, span); + } + /* end tricky prepare code */ - /* cancel if nothing was done */ - if ((totedge_orig == em->bm->totedge) && - (totface_orig == em->bm->totface)) - { - EDBM_op_finish(em, &bmop, op, true); - return OPERATOR_CANCELLED; - } + 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_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + BMO_op_exec(em->bm, &bmop); - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; + /* 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); } - EDBM_update_generic(em, true, true); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3903,20 +4369,32 @@ void MESH_OT_fill_grid(wmOperatorType *ot) static int edbm_fill_holes_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); const int sides = RNA_int_get(op->ptr, "sides"); - if (!EDBM_op_call_and_selectf( - em, op, - "faces.out", true, - "holes_fill edges=%he sides=%i", - BM_ELEM_SELECT, sides)) - { - return 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, &objects_len); - EDBM_update_generic(em, true, true); + 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, + "faces.out", true, + "holes_fill edges=%he sides=%i", + BM_ELEM_SELECT, sides)) + { + continue; + } + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); return OPERATOR_FINISHED; @@ -3948,40 +4426,51 @@ void MESH_OT_fill_holes(wmOperatorType *ot) static int edbm_beautify_fill_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_len); const float angle_max = M_PI; const float angle_limit = RNA_float_get(op->ptr, "angle_limit"); char hflag; - if (angle_limit >= angle_max) { - hflag = BM_ELEM_SELECT; - } - else { - BMIter iter; - BMEdge *e; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - 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)); + if (em->bm->totfacesel == 0) { + continue; + } + if (angle_limit >= angle_max) { + hflag = BM_ELEM_SELECT; } + else { + BMIter iter; + BMEdge *e; - hflag = BM_ELEM_TAG; - } + 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)); - if (!EDBM_op_call_and_selectf( - em, op, "geom.out", true, - "beautify_fill faces=%hf edges=%he", - BM_ELEM_SELECT, hflag)) - { - return OPERATOR_CANCELLED; + } + 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); } - EDBM_update_generic(em, true, true); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -4016,30 +4505,40 @@ void MESH_OT_beautify_fill(wmOperatorType *ot) static int edbm_poke_face_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMOperator bmop; - 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"); - 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); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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_flag_disable_all(em, BM_ELEM_SELECT); + if (em->bm->totfacesel == 0) { + continue; + } - 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); + 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); - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - EDBM_mesh_normals_update(em); + 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); - EDBM_update_generic(em, true, true); + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_mesh_normals_update(em); + + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); return OPERATOR_FINISHED; @@ -4080,32 +4579,48 @@ void MESH_OT_poke(wmOperatorType *ot) static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMOperator bmop; const int quad_method = RNA_enum_get(op->ptr, "quad_method"); const int ngon_method = RNA_enum_get(op->ptr, "ngon_method"); - BMOIter oiter; - BMFace *f; + ViewLayer *view_layer = CTX_data_view_layer(C); - 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); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* select the output */ - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + if (em->bm->totfacesel == 0) { + continue; + } - /* remove the doubles */ - BMO_ITER (f, &oiter, bmop.slots_out, "face_map_double.out", BM_FACE) { - BM_face_kill(em->bm, f); - } + BMOperator bmop; + BMOIter oiter; + BMFace *f; - EDBM_selectmode_flush(em); + 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); - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; + /* 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); + } + + EDBM_selectmode_flush(em); + + 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; } @@ -4139,52 +4654,69 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot) static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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; + ViewLayer *view_layer = CTX_data_view_layer(C); - /* 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 ((em->bm->totfacesel == 2) && - (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); - } + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + bool is_face_pair; - prop = RNA_struct_find_property(op->ptr, "shape_threshold"); - if ((em->bm->totfacesel == 2) && - (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)) { - return OPERATOR_CANCELLED; + int totelem_sel[3]; + EDBM_mesh_stats_multi(objects, objects_len, NULL, totelem_sel); + is_face_pair = (totelem_sel[2] == 2); } - EDBM_update_generic(em, true, true); + 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; } @@ -4240,10 +4772,6 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot) static int edbm_decimate_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - 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"); @@ -4257,95 +4785,108 @@ static int edbm_decimate_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } - 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; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (use_vertex_group && (cd_dvert_offset == -1)) { - BKE_report(op->reports, RPT_WARNING, "No active vertex group"); - use_vertex_group = false; + 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; } - 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; + 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; } } - else { - weight = 1.0f; - } - } - vweights[i] = weight; - BM_elem_index_set(v, i); /* set_inline */ + vweights[i] = weight; + BM_elem_index_set(v, i); /* set_inline */ + } + bm->elem_index_dirty &= ~BM_VERT; } - bm->elem_index_dirty &= ~BM_VERT; - } - float ratio_adjust; + 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 remoevd 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); + if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) { + ratio_adjust = ratio; } + else { + /** + * Calculate a new ratio based on faces that could be remoevd 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; - } + 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); + BM_mesh_decimate_collapse( + em->bm, ratio_adjust, vweights, vertex_group_factor, false, + symmetry_axis, symmetry_eps); - MEM_freeN(vweights); + 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; + { + 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_selectmode_flush_ex(em, selectmode); + EDBM_update_generic(em, true, true); } - - EDBM_update_generic(em, true, true); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -4444,22 +4985,32 @@ static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot) static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - 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"); - 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)) - { - return 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, &objects_len); - EDBM_update_generic(em, true, true); + 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_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; } @@ -4489,21 +5040,32 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot) static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); - 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)) - { - return 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, &objects_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_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); return OPERATOR_FINISHED; } @@ -4534,21 +5096,30 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot) static int edbm_dissolve_faces_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - 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, &objects_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_op_call_and_selectf( - em, op, - "region.out", true, - "dissolve_faces faces=%hf use_verts=%b", - BM_ELEM_SELECT, use_verts)) - { - return OPERATOR_CANCELLED; - } + if (em->bm->totfacesel == 0) { + continue; + } - EDBM_update_generic(em, true, true); + 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); return OPERATOR_FINISHED; } @@ -4628,52 +5199,65 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot) static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; 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; - 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; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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; - 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)); + if ((bm->totvertsel == 0) && + (bm->totedgesel == 0) && + (bm->totfacesel == 0)) + { + continue; } - 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); + 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; - } + 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_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); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -4711,26 +5295,48 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot) static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + 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, &objects_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 */ + const float thresh = RNA_float_get(op->ptr, "threshold"); - BMesh *bm = em->bm; - const int totelem[3] = {bm->totvert, bm->totedge, bm->totface}; - if (!EDBM_op_callf( - em, op, - "dissolve_degenerate edges=%he dist=%f", - BM_ELEM_SELECT, thresh)) - { - return OPERATOR_CANCELLED; - } + 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; + } - /* 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); - edbm_report_delete_info(op->reports, bm, totelem); + totelem_new[0] += bm->totvert; + totelem_new[1] += bm->totedge; + totelem_new[2] += bm->totface; + } + + edbm_report_delete_info(op->reports, totelem_old, totelem_new); return OPERATOR_FINISHED; } @@ -4762,42 +5368,52 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot) /* internally uses dissolve */ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); + ViewLayer *view_layer = CTX_data_view_layer(C); - /* deal with selection */ - { - BMEdge *e; - BMIter iter; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + if (em->bm->totedgesel == 0) { + continue; + } - 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); + /* deal with selection */ + { + BMEdge *e; + BMIter iter; + + 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); + } } } - } - if (!EDBM_op_callf( - em, op, - "dissolve_edges edges=%he use_verts=%b use_face_split=%b", - BM_ELEM_SELECT, true, use_face_split)) - { - return OPERATOR_CANCELLED; - } + 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; } @@ -4827,22 +5443,34 @@ void MESH_OT_delete_edgeloop(wmOperatorType *ot) static int edbm_split_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMOperator bmop; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_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); - 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)) { - return OPERATOR_CANCELLED; - } + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - /* Geometry has changed, need to recalc normals and looptris */ - EDBM_mesh_normals_update(em); + /* Geometry has changed, need to recalc normals and looptris */ + EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); + EDBM_update_generic(em, true, true); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -5000,9 +5628,9 @@ static void sort_bmelem_flag( float fact = reverse ? -1.0 : 1.0; if (v3d && v3d->localvd) - copy_v3_v3(cur, v3d->cursor); + copy_v3_v3(cur, v3d->cursor.location); else - copy_v3_v3(cur, scene->cursor); + copy_v3_v3(cur, scene->cursor.location); invert_m4_m4(mat, ob->obmat); mul_m4_v3(mat, cur); @@ -5320,7 +5948,7 @@ static void sort_bmelem_flag( } BM_mesh_remap(em->bm, map[0], map[1], map[2]); -/* DAG_id_tag_update(ob->data, 0);*/ +/* DEG_id_tag_update(ob->data, 0);*/ for (j = 3; j--; ) { if (map[j]) @@ -5404,7 +6032,7 @@ static void edbm_sort_elements_ui(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* Main auto-draw call. */ - uiDefAutoButsRNA(layout, &ptr, edbm_sort_elements_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, edbm_sort_elements_draw_check_prop, UI_BUT_LABEL_ALIGN_NONE, false); } void MESH_OT_sort_elements(wmOperatorType *ot) @@ -5459,84 +6087,6 @@ void MESH_OT_sort_elements(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Noise (Deform Vertices) Operator - * \{ */ - -static int edbm_noise_exec(bContext *C, wmOperator *op) -{ - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - Material *ma; - Tex *tex; - BMVert *eve; - BMIter iter; - const float fac = RNA_float_get(op->ptr, "factor"); - - if (em == NULL) { - return OPERATOR_FINISHED; - } - - if ((ma = give_current_material(obedit, obedit->actcol)) == NULL || - (tex = give_current_material_texture(ma)) == NULL) - { - BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned"); - return OPERATOR_FINISHED; - } - - if (tex->type == TEX_STUCCI) { - float b2, vec[3]; - float ofs = tex->turbul / 200.0f; - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - b2 = BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]); - if (tex->stype) ofs *= (b2 * b2); - vec[0] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0] + ofs, eve->co[1], eve->co[2])); - vec[1] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1] + ofs, eve->co[2])); - vec[2] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2] + ofs)); - - add_v3_v3(eve->co, vec); - } - } - } - else { - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - float tin = 0.0f, dum; - if (ma->mtex[ma->texact] != NULL) { - externtex(ma->mtex[ma->texact], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false, false); - } - eve->co[2] += fac * tin; - } - } - } - - EDBM_mesh_normals_update(em); - - EDBM_update_generic(em, true, false); - - return OPERATOR_FINISHED; -} - -void MESH_OT_noise(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Noise"; - ot->description = "Use vertex coordinate as texture coordinate"; - ot->idname = "MESH_OT_noise"; - - /* api callbacks */ - ot->exec = edbm_noise_exec; - ot->poll = ED_operator_editmesh; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_float(ot->srna, "factor", 0.1f, -1e4f, 1e4f, "Factor", "", 0.0f, 1.0f); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Bridge Operator * \{ */ @@ -5731,9 +6281,6 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot) static int edbm_wireframe_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMOperator bmop; 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"); @@ -5743,25 +6290,41 @@ static int edbm_wireframe_exec(bContext *C, wmOperator *op) const float thickness = RNA_float_get(op->ptr, "thickness"); const float offset = RNA_float_get(op->ptr, "offset"); - 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); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMO_op_exec(em->bm, &bmop); + if (em->bm->totfacesel == 0) { + continue; + } - 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); + 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; + } - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } - else { EDBM_update_generic(em, true, true); - return OPERATOR_FINISHED; } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void MESH_OT_wireframe(wmOperatorType *ot) @@ -5863,73 +6426,89 @@ void MESH_OT_offset_edge_loops(wmOperatorType *ot) #ifdef WITH_BULLET static int edbm_convex_hull_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMOperator bmop; + 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"); - EDBM_op_init( - em, &bmop, op, "convex_hull input=%hvef " - "use_existing_faces=%b", - BM_ELEM_SELECT, - RNA_boolean_get(op->ptr, "use_existing_faces")); - BMO_op_exec(em->bm, &bmop); + float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold"); + float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold"); - /* Hull fails if input is coplanar */ - if (BMO_error_occurred(em->bm)) { - EDBM_op_finish(em, &bmop, op, true); - return 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, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); + if (em->bm->totvertsel == 0) { + continue; + } - /* Delete unused vertices, edges, and faces */ - if (RNA_boolean_get(op->ptr, "delete_unused")) { - if (!EDBM_op_callf( - em, op, "delete geom=%S context=%i", - &bmop, "geom_unused.out", DEL_ONLYTAGGED)) - { + 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); - return OPERATOR_CANCELLED; + continue; } - } - /* Delete hole edges/faces */ - if (RNA_boolean_get(op->ptr, "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); - return OPERATOR_CANCELLED; + 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; + } } - } - /* Merge adjacent triangles */ - if (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"); + /* 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; + } + } - 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); - return OPERATOR_CANCELLED; + /* 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; } - } - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } - else { EDBM_update_generic(em, true, true); EDBM_selectmode_flush(em); - return OPERATOR_FINISHED; } + + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_convex_hull(wmOperatorType *ot) @@ -5975,30 +6554,42 @@ void MESH_OT_convex_hull(wmOperatorType *ot) static int mesh_symmetrize_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMOperator bmop; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - 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); - 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); + if (em->bm->totvertsel == 0 ) { + continue; + } + BMOperator bmop; - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + const float thresh = RNA_float_get(op->ptr, "threshold"); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + 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); - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - } - else { - EDBM_update_generic(em, true, true); - EDBM_selectmode_flush(em); - return OPERATOR_FINISHED; + 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); + + 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; } void MESH_OT_symmetrize(struct wmOperatorType *ot) @@ -6165,45 +6756,59 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot) static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - Mesh *me = (Mesh *)obedit->data; - BMEditMesh *em = BKE_editmesh_from_object(obedit); BMEdge *eed; BMIter iter; FreestyleEdge *fed; const bool clear = RNA_boolean_get(op->ptr, "clear"); + ViewLayer *view_layer = CTX_data_view_layer(C); - if (em == NULL) - return OPERATOR_FINISHED; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* auto-enable Freestyle edge mark drawing */ - if (clear == 0) { - me->drawflag |= ME_DRAW_FREESTYLE_EDGE; - } + if (em == NULL) { + continue; + } - if (!CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) { - BM_data_layer_add(em->bm, &em->bm->edata, CD_FREESTYLE_EDGE); - } + BMesh *bm = em->bm; + Mesh *me = ((Mesh *)obedit->data); - 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; + if (bm->totedgesel == 0) { + continue; + } + + /* auto-enable Freestyle edge mark drawing */ + if (clear == 0) { + me->drawflag |= ME_DRAW_FREESTYLE_EDGE; + } + + 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; + 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; + } } } - } - DAG_id_tag_update(obedit->data, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -6225,7 +6830,7 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /** \} */ @@ -6236,44 +6841,57 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot) static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - Mesh *me = (Mesh *)obedit->data; - BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMIter iter; FreestyleFace *ffa; const bool clear = RNA_boolean_get(op->ptr, "clear"); + ViewLayer *view_layer = CTX_data_view_layer(C); - if (em == NULL) return OPERATOR_FINISHED; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + Mesh *me = (Mesh *)obedit->data; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - /* auto-enable Freestyle face mark drawing */ - if (!clear) { - me->drawflag |= ME_DRAW_FREESTYLE_FACE; - } + if (em == NULL) { + continue; + } - if (!CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE)) { - BM_data_layer_add(em->bm, &em->bm->pdata, CD_FREESTYLE_FACE); - } + if (em->bm->totfacesel == 0) { + continue; + } - 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; + /* auto-enable Freestyle face mark drawing */ + if (!clear) { + me->drawflag |= ME_DRAW_FREESTYLE_FACE; + } + + 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; + 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; + } } } - } - DAG_id_tag_update(obedit->data, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -6295,7 +6913,7 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 18c383deff0..97445ebc9e0 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -24,9 +24,12 @@ #include "MEM_guardedalloc.h" +#include "CLG_log.h" + #include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_key_types.h" +#include "DNA_layer_types.h" #include "BLI_listbase.h" #include "BLI_array_utils.h" @@ -35,14 +38,17 @@ #include "BKE_DerivedMesh.h" #include "BKE_context.h" #include "BKE_key.h" +#include "BKE_layer.h" #include "BKE_mesh.h" #include "BKE_editmesh.h" -#include "BKE_depsgraph.h" #include "BKE_undo_system.h" +#include "DEG_depsgraph.h" + #include "ED_object.h" #include "ED_mesh.h" #include "ED_util.h" +#include "ED_undo.h" #include "WM_types.h" #include "WM_api.h" @@ -68,6 +74,9 @@ # include "BLI_task.h" #endif +/** We only need this locally. */ +static CLG_LogRef LOG = {"ed.undo.mesh"}; + /* -------------------------------------------------------------------- */ /** \name Undo Conversion * \{ */ @@ -667,80 +676,23 @@ static Object *editmesh_object_from_context(bContext *C) /* -------------------------------------------------------------------- */ /** \name Implements ED Undo System + * + * \note This is similar for all edit-mode types. * \{ */ +typedef struct MeshUndoStep_Elem { + struct MeshUndoStep_Elem *next, *prev; + UndoRefID_Object obedit_ref; + UndoMesh data; +} MeshUndoStep_Elem; + typedef struct MeshUndoStep { UndoStep step; - /* Use for all ID lookups (can be NULL). */ struct UndoIDPtrMap *id_map; - - /* note: will split out into list for multi-object-editmode. */ - UndoRefID_Object obedit_ref; - /* Needed for MTexPoly's image use. */ - UndoRefID_Object *image_array_ref; - UndoMesh data; + MeshUndoStep_Elem *elems; + uint elems_len; } MeshUndoStep; -static void mesh_undosys_step_encode_store_ids(MeshUndoStep *us) -{ - Mesh *me = us->obedit_ref.ptr->data; - BMesh *bm = me->edit_btmesh->bm; - const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); - if (mtex_len != 0) { - ID **id_prev_array = BLI_array_alloca(id_prev_array, mtex_len); - memset(id_prev_array, 0x0, sizeof(*id_prev_array) * mtex_len); - - BMIter iter; - BMFace *efa; - - if (us->id_map == NULL) { - us->id_map = BKE_undosys_ID_map_create(); - } - - uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0); - uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len); - BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0; - cd_poly_tex_offset < cd_poly_tex_offset_end; - cd_poly_tex_offset += sizeof(MTexPoly), i++) - { - const MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (tf->tpage != NULL) { - BKE_undosys_ID_map_add_with_prev(us->id_map, (ID *)tf->tpage, &id_prev_array[i]); - } - } - } - } -} - -static void mesh_undosys_step_decode_restore_ids(MeshUndoStep *us) -{ - Mesh *me = us->obedit_ref.ptr->data; - BMesh *bm = me->edit_btmesh->bm; - const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); - if (mtex_len != 0 && us->id_map) { - BMIter iter; - BMFace *efa; - - ID *(*id_prev_array)[2] = BLI_array_alloca(id_prev_array, mtex_len); - memset(id_prev_array, 0x0, sizeof(*id_prev_array) * mtex_len); - - uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0); - uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len); - BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0; - cd_poly_tex_offset < cd_poly_tex_offset_end; - cd_poly_tex_offset += sizeof(MTexPoly), i++) - { - MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (tf->tpage != NULL) { - tf->tpage = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, (ID *)tf->tpage, id_prev_array[i]); - } - } - } - } -} - static bool mesh_undosys_poll(bContext *C) { return editmesh_object_from_context(C) != NULL; @@ -749,11 +701,24 @@ static bool mesh_undosys_poll(bContext *C) static bool mesh_undosys_step_encode(struct bContext *C, UndoStep *us_p) { MeshUndoStep *us = (MeshUndoStep *)us_p; - us->obedit_ref.ptr = editmesh_object_from_context(C); - Mesh *me = us->obedit_ref.ptr->data; - undomesh_from_editmesh(&us->data, me->edit_btmesh, me->key); - mesh_undosys_step_encode_store_ids(us); - us->step.data_size = us->data.undo_size; + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &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_btmesh, me->key); + us->step.data_size += elem->data.undo_size; + } + MEM_freeN(objects); return true; } @@ -764,19 +729,37 @@ static void mesh_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNU BLI_assert(mesh_undosys_poll(C)); MeshUndoStep *us = (MeshUndoStep *)us_p; - Object *obedit = us->obedit_ref.ptr; - Mesh *me = obedit->data; - BMEditMesh *em = me->edit_btmesh; - undomesh_to_editmesh(&us->data, em, obedit->data); - mesh_undosys_step_decode_restore_ids(us); - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + + 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_btmesh == 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_btmesh; + undomesh_to_editmesh(&elem->data, em, obedit->data); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); + } + + /* 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); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } static void mesh_undosys_step_free(UndoStep *us_p) { MeshUndoStep *us = (MeshUndoStep *)us_p; - undomesh_free_data(&us->data); + + 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); @@ -787,7 +770,12 @@ static void mesh_undosys_foreach_ID_ref( UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) { MeshUndoStep *us = (MeshUndoStep *)us_p; - foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->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); } diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 4500aeda70a..5481c52269d 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -43,7 +43,6 @@ #include "BKE_DerivedMesh.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" @@ -51,6 +50,8 @@ #include "BKE_editmesh.h" #include "BKE_editmesh_bvh.h" +#include "DEG_depsgraph.h" + #include "BKE_object.h" /* XXX. only for EDBM_mesh_load(). */ #include "WM_api.h" @@ -172,6 +173,10 @@ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool BKE_editmesh_tessface_calc(em); } + if (em->ob) { + DEG_id_tag_update(&((Mesh *)em->ob->data)->id, DEG_TAG_COPY_ON_WRITE); + } + return false; } else { @@ -324,7 +329,7 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index) /** * \warning This can invalidate the #DerivedMesh cache of other objects (for linked duplicates). - * Most callers should run #DAG_id_tag_update on \a ob->data, see: T46738, T46913 + * Most callers should run #DEG_id_tag_update on \a ob->data, see: T46738, T46913 */ void EDBM_mesh_load(Main *bmain, Object *ob) { @@ -512,7 +517,6 @@ UvVertMap *BM_uv_vert_map_create( /* vars from original func */ UvVertMap *vmap; UvMapVert *buf; - /* MTexPoly *tf; */ /* UNUSED */ MLoopUV *luv; unsigned int a; int totverts, i, totuv, totfaces; @@ -554,7 +558,7 @@ UvVertMap *BM_uv_vert_map_create( 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]; + float (*tf_uv)[2] = NULL; if (use_winding) { tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len); @@ -594,7 +598,6 @@ UvVertMap *BM_uv_vert_map_create( newvlist = v; efa = BM_face_at_index(bm, v->f); - /* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -606,8 +609,6 @@ UvVertMap *BM_uv_vert_map_create( while (iterv) { next = iterv->next; efa = BM_face_at_index(bm, iterv->f); - /* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ - l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv2 = luv->uv; @@ -661,7 +662,7 @@ UvElementMap *BM_uv_element_map_create( /* vars from original func */ UvElementMap *element_map; UvElement *buf; - bool *winding; + bool *winding = NULL; BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); MLoopUV *luv; @@ -702,7 +703,7 @@ UvElementMap *BM_uv_element_map_create( } if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - float (*tf_uv)[2]; + float (*tf_uv)[2] = NULL; if (use_winding) { tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len); @@ -926,7 +927,7 @@ UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l) /* last_sel, use em->act_face otherwise get the last selected face in the editselections * at the moment, last_sel is mainly useful for making sure the space image dosnt flicker */ -BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected, MTexPoly **r_tf) +BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected) { BMFace *efa = NULL; @@ -937,11 +938,9 @@ BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool se efa = BM_mesh_active_face_get(em->bm, sloppy, selected); if (efa) { - if (r_tf) *r_tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); return efa; } - if (r_tf) *r_tf = NULL; return NULL; } @@ -950,7 +949,6 @@ 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->pdata, CD_MTEXPOLY) && CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV); } @@ -1009,7 +1007,7 @@ void EDBM_verts_mirror_cache_begin_ex( BMesh *bm = em->bm; BMIter iter; BMVert *v; - int cd_vmirr_offset; + int cd_vmirr_offset = 0; int i; const float maxdist_sq = SQUARE(maxdist); @@ -1037,7 +1035,7 @@ void EDBM_verts_mirror_cache_begin_ex( BM_mesh_elem_index_ensure(bm, BM_VERT); if (use_topology) { - ED_mesh_mirrtopo_init(me, NULL, -1, &mesh_topo_store, true); + ED_mesh_mirrtopo_init(me, NULL, &mesh_topo_store, true); } else { tree = BLI_kdtree_new(bm->totvert); @@ -1335,7 +1333,7 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d { Object *ob = em->ob; /* order of calling isn't important */ - DAG_id_tag_update(ob->data, OB_RECALC_DATA); + DEG_id_tag_update(ob->data, OB_RECALC_DATA); WM_main_add_notifier(NC_GEOM | ND_DATA, ob->data); if (do_tessface) { @@ -1487,7 +1485,9 @@ static void scale_point(float c1[3], const float p[3], const float s) add_v3_v3(c1, p); } -bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v3d, Object *obedit) +bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, + struct Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, Object *obedit) { BMFace *f; float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3]; @@ -1499,7 +1499,7 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v ar->winy / 2.0f, }; - ED_view3d_win_to_segment(ar, v3d, mval_f, origin, end, false); + ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false); invert_m4_m4(invmat, obedit->obmat); mul_m4_v3(invmat, origin); diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index fc74397010c..b4588257412 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -42,7 +42,6 @@ #include "BLI_math.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh.h" @@ -50,6 +49,8 @@ #include "BKE_report.h" #include "BKE_editmesh.h" +#include "DEG_depsgraph.h" + #include "RNA_define.h" #include "WM_api.h" @@ -245,14 +246,14 @@ void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum) } } - DAG_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 *pdata = GET_CD_DATA(me, pdata); - const int layernum = CustomData_get_active_layer(pdata, CD_MTEXPOLY); + 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); @@ -269,21 +270,10 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set) if (me->edit_btmesh) { em = me->edit_btmesh; - layernum_dst = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY); + layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV); if (layernum_dst >= MAX_MTFACE) return -1; - /* CD_MTEXPOLY */ - BM_data_layer_add_named(em->bm, &em->bm->pdata, CD_MTEXPOLY, name); - /* copy data from active UV */ - if (layernum_dst) { - const int layernum_src = CustomData_get_active_layer(&em->bm->pdata, CD_MTEXPOLY); - BM_data_layer_copy(em->bm, &em->bm->pdata, CD_MTEXPOLY, layernum_src, layernum_dst); - } - if (active_set || layernum_dst == 0) { - CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum_dst); - } - /* CD_MLOOPUV */ BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_MLOOPUV, name); /* copy data from active UV */ @@ -298,26 +288,22 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set) } } else { - layernum_dst = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); + layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); if (layernum_dst >= MAX_MTFACE) return -1; - if (me->mtpoly) { - CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DUPLICATE, me->mtpoly, me->totpoly, name); + if (me->mloopuv) { 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->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, name); 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->pdata, CD_MTEXPOLY, layernum_dst); CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, layernum_dst); - CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum_dst); } @@ -329,7 +315,7 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set) ED_mesh_uv_loop_reset_ex(me, layernum_dst); } - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); WM_main_add_notifier(NC_GEOM | ND_DATA, me); return layernum_dst; @@ -343,12 +329,12 @@ void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name) if (me->edit_btmesh) { em = me->edit_btmesh; - layernum_dst = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY); + layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV); if (layernum_dst == 0) ED_mesh_uv_texture_add(me, name, true); } else { - layernum_dst = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); + layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); if (layernum_dst == 0) ED_mesh_uv_texture_add(me, name, true); } @@ -357,23 +343,19 @@ void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name) bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n) { - CustomData *pdata = GET_CD_DATA(me, pdata), *ldata = GET_CD_DATA(me, ldata); - CustomDataLayer *cdlp, *cdlu; + CustomData *ldata = GET_CD_DATA(me, ldata); + CustomDataLayer *cdlu; int index; - index = CustomData_get_layer_index_n(pdata, CD_MTEXPOLY, n); - cdlp = (index == -1) ? NULL : &pdata->layers[index]; - index = CustomData_get_layer_index_n(ldata, CD_MLOOPUV, n); cdlu = (index == -1) ? NULL : &ldata->layers[index]; - if (!cdlp || !cdlu) + if (!cdlu) return false; - delete_customdata_layer(me, cdlp); delete_customdata_layer(me, cdlu); - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); WM_main_add_notifier(NC_GEOM | ND_DATA, me); return true; @@ -381,14 +363,8 @@ bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n) bool ED_mesh_uv_texture_remove_active(Mesh *me) { /* texpoly/uv are assumed to be in sync */ - CustomData *pdata = GET_CD_DATA(me, pdata); - const int n = CustomData_get_active_layer(pdata, CD_MTEXPOLY); - - /* double check active layers align! */ -#ifdef DEBUG CustomData *ldata = GET_CD_DATA(me, ldata); - BLI_assert(CustomData_get_active_layer(ldata, CD_MLOOPUV) == n); -#endif + const int n = CustomData_get_active_layer(ldata, CD_MLOOPUV); if (n != -1) { return ED_mesh_uv_texture_remove_index(me, n); @@ -400,8 +376,8 @@ bool ED_mesh_uv_texture_remove_active(Mesh *me) bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name) { /* texpoly/uv are assumed to be in sync */ - CustomData *pdata = GET_CD_DATA(me, pdata); - const int n = CustomData_get_named_layer(pdata, CD_MTEXPOLY, name); + 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); } @@ -458,7 +434,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set) BKE_mesh_update_customdata_pointers(me, true); } - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); WM_main_add_notifier(NC_GEOM | ND_DATA, me); return layernum; @@ -473,7 +449,7 @@ bool ED_mesh_color_ensure(struct Mesh *me, const char *name) BKE_mesh_update_customdata_pointers(me, true); } - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); return (me->mloopcol != NULL); } @@ -491,7 +467,7 @@ bool ED_mesh_color_remove_index(Mesh *me, const int n) return false; delete_customdata_layer(me, cdl); - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); WM_main_add_notifier(NC_GEOM | ND_DATA, me); return true; @@ -602,17 +578,15 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e if (me->edit_btmesh == NULL) return OPERATOR_CANCELLED; - ED_uvedit_assign_image(bmain, scene, obedit, ima, NULL); - if (exitmode) { EDBM_mesh_load(bmain, obedit); EDBM_mesh_free(me->edit_btmesh); MEM_freeN(me->edit_btmesh); me->edit_btmesh = NULL; - /* load_editMesh free's pointers used by CustomData layers which might be used by DerivedMesh too, - * so signal to re-create DerivedMesh here (sergey) */ - DAG_id_tag_update(&me->id, 0); + /* load_editMesh free's pointers used by CustomData layers which might be used by evaluated mesh too, + * so signal to re-create evaluated mesh here (sergey) */ + DEG_id_tag_update(&me->id, 0); } /* dummie drop support; ensure view shows a result :) */ @@ -751,7 +725,7 @@ static int mesh_customdata_clear_exec__internal(bContext *C, CustomData_free_layers(data, type, tot); } - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); return OPERATOR_FINISHED; @@ -847,7 +821,7 @@ static int mesh_customdata_skin_add_exec(bContext *C, wmOperator *UNUSED(op)) BKE_mesh_ensure_skin_customdata(me); - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); return OPERATOR_FINISHED; @@ -938,7 +912,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop); } - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); return OPERATOR_FINISHED; @@ -1015,7 +989,7 @@ void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges, int calc_tessface) BKE_mesh_calc_normals(mesh); - DAG_id_tag_update(&mesh->id, 0); + DEG_id_tag_update(&mesh->id, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, mesh); } @@ -1335,7 +1309,6 @@ void ED_mesh_calc_tessface(Mesh *mesh, bool free_mpoly) mesh->mloopcol = NULL; mesh->mloopuv = NULL; mesh->mpoly = NULL; - mesh->mtpoly = NULL; } } diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 74da7405d05..75fead00534 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -92,6 +92,8 @@ void MESH_OT_primitive_monkey_add(struct wmOperatorType *ot); void MESH_OT_primitive_uv_sphere_add(struct wmOperatorType *ot); void MESH_OT_primitive_ico_sphere_add(struct wmOperatorType *ot); +/* *** editmesh_add_manipulator.c *** */ +void MESH_OT_primitive_cube_add_manipulator(struct wmOperatorType *ot); /* *** editmesh_bevel.c *** */ void MESH_OT_bevel(struct wmOperatorType *ot); @@ -102,6 +104,7 @@ void MESH_OT_bisect(struct wmOperatorType *ot); /* *** editmesh_extrude.c *** */ void MESH_OT_extrude_repeat(struct wmOperatorType *ot); void MESH_OT_extrude_region(struct wmOperatorType *ot); +void MESH_OT_extrude_context(struct wmOperatorType *ot); void MESH_OT_extrude_verts_indiv(struct wmOperatorType *ot); void MESH_OT_extrude_edges_indiv(struct wmOperatorType *ot); void MESH_OT_extrude_faces_indiv(struct wmOperatorType *ot); @@ -113,6 +116,12 @@ void MESH_OT_screw(struct wmOperatorType *ot); /* *** editmesh_extrude_spin.c *** */ void MESH_OT_spin(struct wmOperatorType *ot); +/* *** editmesh_polybuild.c *** */ +void MESH_OT_polybuild_face_at_cursor(struct wmOperatorType *ot); +void MESH_OT_polybuild_split_at_cursor(struct wmOperatorType *ot); +void MESH_OT_polybuild_dissolve_at_cursor(struct wmOperatorType *ot); +void MESH_OT_polybuild_hover(struct wmOperatorType *ot); + /* *** editmesh_inset.c *** */ void MESH_OT_inset(struct wmOperatorType *ot); @@ -208,7 +217,6 @@ void MESH_OT_hide(struct wmOperatorType *ot); void MESH_OT_reveal(struct wmOperatorType *ot); void MESH_OT_mark_seam(struct wmOperatorType *ot); void MESH_OT_mark_sharp(struct wmOperatorType *ot); -void MESH_OT_noise(struct wmOperatorType *ot); void MESH_OT_flip_normals(struct wmOperatorType *ot); void MESH_OT_solidify(struct wmOperatorType *ot); void MESH_OT_knife_cut(struct wmOperatorType *ot); @@ -252,12 +260,4 @@ void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot); void MESH_OT_drop_named_image(struct wmOperatorType *ot); -/* *** mesh_navmesh.c *** */ -void MESH_OT_navmesh_make(struct wmOperatorType *ot); -void MESH_OT_navmesh_face_copy(struct wmOperatorType *ot); -void MESH_OT_navmesh_face_add(struct wmOperatorType *ot); -void MESH_OT_navmesh_reset(struct wmOperatorType *ot); -void MESH_OT_navmesh_clear(struct wmOperatorType *ot); - - #endif /* __MESH_INTERN_H__ */ diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c index 20ece9c3336..4b526915551 100644 --- a/source/blender/editors/mesh/mesh_mirror.c +++ b/source/blender/editors/mesh/mesh_mirror.c @@ -32,11 +32,13 @@ #include "BLI_bitmap.h" #include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "BKE_DerivedMesh.h" #include "BLI_kdtree.h" #include "BKE_editmesh.h" +#include "BKE_library.h" +#include "BKE_mesh.h" #include "ED_mesh.h" @@ -50,11 +52,11 @@ static struct { void *tree; } MirrKdStore = {NULL}; /* mode is 's' start, or 'e' end, or 'u' use */ /* if end, ob can be NULL */ -int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode) +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, dm, NULL, 's'); + ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's'); if (MirrKdStore.tree) { KDTreeNearest nearest; @@ -70,11 +72,11 @@ int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, co } else if (mode == 's') { /* start table */ Mesh *me = ob->data; - const bool use_em = (!dm && em && me->edit_btmesh == em); - const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert; + const bool use_em = (!me_eval && em && me->edit_btmesh == 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, dm, co, 'e'); + ED_mesh_mirror_spatial_table(ob, em, me_eval, co, 'e'); MirrKdStore.tree = BLI_kdtree_new(totvert); @@ -91,7 +93,7 @@ int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, co } } else { - MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert; + MVert *mvert = me_eval ? me_eval->mvert : me->mvert; int i; for (i = 0; i < totvert; i++, mvert++) { @@ -141,14 +143,15 @@ static int mirrtopo_vert_sort(const void *v1, const void *v2) return 0; } -bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store) +bool ED_mesh_mirrtopo_recalc_check(Mesh *me, Mesh *me_eval, MirrTopoStore_t *mesh_topo_store) { + const bool is_editmode = (me->edit_btmesh != NULL); int totvert; int totedge; - if (dm) { - totvert = dm->getNumVerts(dm); - totedge = dm->getNumEdges(dm); + if (me_eval) { + totvert = me_eval->totvert; + totedge = me_eval->totedge; } else if (me->edit_btmesh) { totvert = me->edit_btmesh->bm->totvert; @@ -160,7 +163,7 @@ bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode, } if ((mesh_topo_store->index_lookup == NULL) || - (mesh_topo_store->prev_ob_mode != ob_mode) || + (mesh_topo_store->prev_is_editmode != is_editmode) || (totvert != mesh_topo_store->prev_vert_tot) || (totedge != mesh_topo_store->prev_edge_tot)) { @@ -172,11 +175,13 @@ bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode, } -void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store, - const bool skip_em_vert_array_init) +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_btmesh != NULL); MEdge *medge = NULL, *med; - BMEditMesh *em = dm ? NULL : me->edit_btmesh; + BMEditMesh *em = me_eval ? NULL : me->edit_btmesh; /* editmode*/ BMEdge *eed; @@ -197,7 +202,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTop /* reallocate if needed */ ED_mesh_mirrtopo_free(mesh_topo_store); - mesh_topo_store->prev_ob_mode = ob_mode; + mesh_topo_store->prev_is_editmode = is_editmode; if (em) { BM_mesh_elem_index_ensure(em->bm, BM_VERT); @@ -205,7 +210,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTop totvert = em->bm->totvert; } else { - totvert = dm ? dm->getNumVerts(dm) : me->totvert; + totvert = me_eval ? me_eval->totvert : me->totvert; } topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); @@ -221,8 +226,8 @@ void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTop } } else { - totedge = dm ? dm->getNumEdges(dm) : me->totedge; - medge = dm ? dm->getEdgeArray(dm) : me->medge; + 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; diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 3c8e18027f4..f5c5a85d5ca 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -77,12 +77,16 @@ void ED_operatortypes_mesh(void) 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_manipulator); + 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); @@ -141,13 +145,18 @@ void ED_operatortypes_mesh(void) #endif WM_operatortype_append(MESH_OT_vertices_smooth); WM_operatortype_append(MESH_OT_vertices_smooth_laplacian); - WM_operatortype_append(MESH_OT_noise); 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_polybuild_hover); + WM_operatortype_append(MESH_OT_uv_texture_add); WM_operatortype_append(MESH_OT_uv_texture_remove); WM_operatortype_append(MESH_OT_vertex_color_add); @@ -191,14 +200,6 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_bisect); WM_operatortype_append(MESH_OT_symmetrize); WM_operatortype_append(MESH_OT_symmetry_snap); - -#ifdef WITH_GAMEENGINE - WM_operatortype_append(MESH_OT_navmesh_make); - WM_operatortype_append(MESH_OT_navmesh_face_copy); - WM_operatortype_append(MESH_OT_navmesh_face_add); - WM_operatortype_append(MESH_OT_navmesh_reset); - WM_operatortype_append(MESH_OT_navmesh_clear); -#endif } #if 0 /* UNUSED, remove? */ @@ -261,6 +262,13 @@ void ED_operatormacros_mesh(void) 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 region and move result", OPTYPE_UNDO | OPTYPE_REGISTER); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); @@ -288,6 +296,23 @@ void ED_operatormacros_mesh(void) 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? */ @@ -310,6 +335,24 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "vertex_only", true); /* selecting */ + + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", ONEKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_VERTEX); + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", TWOKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_EDGE); + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", THREEKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_FACE); + + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", ONEKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_VERTEX); + RNA_boolean_set(kmi->ptr, "use_extend", true); + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", TWOKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_EDGE); + RNA_boolean_set(kmi->ptr, "use_extend", true); + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", THREEKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_FACE); + RNA_boolean_set(kmi->ptr, "use_extend", true); + /* standard mouse selection goes via space_view3d */ kmi = WM_keymap_add_item(keymap, "MESH_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "extend", false); @@ -358,9 +401,6 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0); - /* selection mode */ - WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_select_mode", TABKEY, KM_PRESS, KM_CTRL, 0); - /* hide */ kmi = WM_keymap_add_item(keymap, "MESH_OT_hide", HKEY, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "unselected", false); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 8980e1830cf..537056cd1ba 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -34,32 +34,38 @@ #include "MEM_guardedalloc.h" -#include "DNA_mesh_types.h" #include "DNA_key_types.h" #include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" +#include "DNA_workspace_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_deform.h" -#include "BKE_DerivedMesh.h" #include "BKE_key.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_iterators.h" +#include "BKE_mesh_runtime.h" #include "BKE_material.h" #include "BKE_object.h" #include "BKE_object_deform.h" #include "BKE_report.h" #include "BKE_editmesh.h" #include "BKE_multires.h" +#include "BKE_layer.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "ED_mesh.h" #include "ED_object.h" @@ -76,7 +82,7 @@ * return 0 if no join is made (error) and 1 if the join is done */ static void join_mesh_single( - Main *bmain, Scene *scene, + 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, @@ -204,7 +210,7 @@ static void join_mesh_single( if (ob_src != ob_dst) { MultiresModifierData *mmd; - multiresModifier_prepare_join(scene, ob_src, ob_dst); + 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, @@ -278,7 +284,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) bDeformGroup *dg, *odg; CustomData vdata, edata, fdata, ldata, pdata; - if (scene->obedit) { + if (ob->mode & OB_MODE_EDIT) { BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode"); return OPERATOR_CANCELLED; } @@ -289,6 +295,8 @@ int join_mesh_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + Depsgraph *depsgraph = CTX_data_depsgraph(C); + /* count & check */ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { @@ -483,7 +491,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) * 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( - bmain, scene, + depsgraph, bmain, scene, ob, ob, imat, &mvert, &medge, &mloop, &mpoly, &vdata, &edata, &ldata, &pdata, @@ -500,7 +508,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) /* only join if this is a mesh */ if (base->object->type == OB_MESH) { join_mesh_single( - bmain, scene, + depsgraph, bmain, scene, ob, base->object, imat, &mvert, &medge, &mloop, &mpoly, &vdata, &edata, &ldata, &pdata, @@ -511,7 +519,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) /* free base, now that data is merged */ if (base->object != ob) { - ED_base_object_free_and_unlink(bmain, scene, base); + ED_object_base_free_and_unlink(bmain, scene, base->object); } } } @@ -582,10 +590,11 @@ int join_mesh_exec(bContext *C, wmOperator *op) /* Due to dependnecy cycle some other object might access old derived data. */ BKE_object_free_derived_caches(ob); - DAG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */ + DEG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */ - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; @@ -601,9 +610,10 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); Mesh *me = (Mesh *)ob->data; Mesh *selme = NULL; - DerivedMesh *dm = NULL; + Mesh *me_deformed = NULL; Key *key = me->key; KeyBlock *kb; bool ok = false, nonequal_verts = false; @@ -637,7 +647,7 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op) /* 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, kb); + BKE_keyblock_convert_from_mesh(me, key, kb); } /* now ready to add new keys from selected meshes */ @@ -649,20 +659,21 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op) selme = (Mesh *)base->object->data; if (selme->totvert == me->totvert) { - dm = mesh_get_derived_deform(scene, base->object, CD_MASK_BAREMESH); + me_deformed = mesh_get_eval_deform(depsgraph, scene, base->object, CD_MASK_BAREMESH); - if (!dm) continue; + if (!me_deformed) { + continue; + } kb = BKE_keyblock_add(key, base->object->id.name + 2); - DM_to_meshkey(dm, me, kb); - - dm->release(dm); + BKE_mesh_runtime_eval_to_meshkey(me_deformed, me, kb); } } } CTX_DATA_END; + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; @@ -680,15 +691,15 @@ static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1}; /* mode is 's' start, or 'e' end, or 'u' use */ /* if end, ob can be NULL */ /* 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, DerivedMesh *dm, char mode) +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, dm, ob->mode, &mesh_topo_store)) { - ED_mesh_mirror_topo_table(ob, dm, 's'); + 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, dm, ob->mode, &mesh_topo_store, false); + 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); @@ -703,10 +714,10 @@ int ED_mesh_mirror_topo_table(Object *ob, DerivedMesh *dm, char mode) /** \} */ -static int mesh_get_x_mirror_vert_spatial(Object *ob, DerivedMesh *dm, int index) +static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh, int index) { Mesh *me = ob->data; - MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert; + MVert *mvert = mesh ? mesh->mvert : me->mvert; float vec[3]; mvert = &mvert[index]; @@ -714,24 +725,24 @@ static int mesh_get_x_mirror_vert_spatial(Object *ob, DerivedMesh *dm, int index vec[1] = mvert->co[1]; vec[2] = mvert->co[2]; - return ED_mesh_mirror_spatial_table(ob, NULL, dm, vec, 'u'); + return ED_mesh_mirror_spatial_table(ob, NULL, mesh, vec, 'u'); } -static int mesh_get_x_mirror_vert_topo(Object *ob, DerivedMesh *dm, int index) +static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index) { - if (ED_mesh_mirror_topo_table(ob, dm, 'u') == -1) + if (ED_mesh_mirror_topo_table(ob, mesh, 'u') == -1) return -1; return mesh_topo_store.index_lookup[index]; } -int mesh_get_x_mirror_vert(Object *ob, DerivedMesh *dm, int index, const bool use_topology) +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, dm, index); + return mesh_get_x_mirror_vert_topo(ob, me_eval, index); } else { - return mesh_get_x_mirror_vert_spatial(ob, dm, index); + return mesh_get_x_mirror_vert_spatial(ob, me_eval, index); } } @@ -928,8 +939,8 @@ static bool mirror_facecmp(const void *a, const void *b) return (mirror_facerotation((MFace *)a, (MFace *)b) == -1); } -/* BMESH_TODO, convert to MPoly (functions above also) */ -int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, DerivedMesh *dm) +/* 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; @@ -940,22 +951,22 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, DerivedMesh *dm) BLI_assert(em == NULL); /* Does not work otherwise, currently... */ const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - const int totvert = dm ? dm->getNumVerts(dm) : me->totvert; - const int totface = dm ? dm->getNumTessFaces(dm) : me->totface; + 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"); - mvert = dm ? dm->getVertArray(dm) : me->mvert; - mface = dm ? dm->getTessFaceArray(dm) : 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, dm, 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, dm, a, use_topology); + mirrorverts[a] = mesh_get_x_mirror_vert(ob, me_eval, a, use_topology); - ED_mesh_mirror_spatial_table(ob, em, dm, 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++) @@ -1031,21 +1042,22 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int static void ed_mesh_pick_face_vert__mpoly_find( /* context */ struct ARegion *ar, const float mval[2], - /* mesh data */ - DerivedMesh *dm, MPoly *mp, MLoop *mloop, + /* 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 co[3], sco[2], len; + float sco[2]; const int v_idx = ml->v; - dm->getVertCo(dm, v_idx, co); + const float *co = mvert[v_idx].co; if (ED_view3d_project_float_object(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - len = len_manhattan_v2v2(mval, sco); - if (len < *r_len_best) { - *r_len_best = len; + 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; } } @@ -1057,6 +1069,7 @@ static void ed_mesh_pick_face_vert__mpoly_find( */ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); unsigned int poly_index; Mesh *me = ob->data; @@ -1067,7 +1080,7 @@ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned struct ARegion *ar = CTX_wm_region(C); /* derived mesh to find deformed locations */ - DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); + Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); int v_idx_best = ORIGINDEX_NONE; @@ -1075,36 +1088,38 @@ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned const float mval_f[2] = {UNPACK2(mval)}; float len_best = FLT_MAX; - MPoly *dm_mpoly; - MLoop *dm_mloop; - unsigned int dm_mpoly_tot; + MPoly *me_eval_mpoly; + MLoop *me_eval_mloop; + MVert *me_eval_mvert; + unsigned int me_eval_mpoly_len; const int *index_mp_to_orig; - dm_mpoly = dm->getPolyArray(dm); - dm_mloop = dm->getLoopArray(dm); + me_eval_mpoly = me_eval->mpoly; + me_eval_mloop = me_eval->mloop; + me_eval_mvert = me_eval->mvert; - dm_mpoly_tot = dm->getNumPolys(dm); + me_eval_mpoly_len = me_eval->totpoly; - index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); + 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 < dm_mpoly_tot; 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, - dm, &dm_mpoly[i], dm_mloop, + &me_eval_mpoly[i], me_eval_mvert, me_eval_mloop, &len_best, &v_idx_best); } } } else { - if (poly_index < dm_mpoly_tot) { + if (poly_index < me_eval_mpoly_len) { ed_mesh_pick_face_vert__mpoly_find( ar, mval_f, - dm, &dm_mpoly[poly_index], dm_mloop, + &me_eval_mpoly[poly_index], me_eval_mvert, me_eval_mloop, &len_best, &v_idx_best); } } @@ -1112,15 +1127,12 @@ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned /* map 'dm -> me' index if possible */ if (v_idx_best != ORIGINDEX_NONE) { const int *index_mv_to_orig; - - index_mv_to_orig = dm->getVertDataArray(dm, CD_ORIGINDEX); + 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]; } } - dm->release(dm); - if ((v_idx_best != ORIGINDEX_NONE) && (v_idx_best < me->totvert)) { *index = v_idx_best; return true; @@ -1194,7 +1206,7 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int } else { /* derived mesh to find deformed locations */ - DerivedMesh *dm = mesh_get_derived_final(vc.scene, ob, CD_MASK_BAREMESH); + Mesh *me_eval = mesh_get_eval_final(vc.depsgraph, vc.scene, ob, CD_MASK_BAREMESH); ARegion *ar = vc.ar; RegionView3D *rv3d = ar->regiondata; @@ -1206,7 +1218,7 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int ED_view3d_init_mats_rv3d(ob, rv3d); - if (dm == NULL) { + if (me_eval == NULL) { return false; } @@ -1217,9 +1229,7 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int data.len_best = FLT_MAX; data.v_idx_best = -1; - dm->foreachMappedVert(dm, ed_mesh_pick_vert__mapFunc, &data, DM_FOREACH_NOP); - - dm->release(dm); + BKE_mesh_foreach_mapped_vert(me_eval, ed_mesh_pick_vert__mapFunc, &data, MESH_FOREACH_NOP); if (data.v_idx_best == -1) { return false; @@ -1280,3 +1290,47 @@ MDeformVert *ED_mesh_active_dvert_get_only(Object *ob) return NULL; } } + +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; + } + } +} + + +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); + } +} |