2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2004 by Blender Foundation.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Joseph Eagar
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/mesh/editmesh_tools.c
34 #include "MEM_guardedalloc.h"
36 #include "DNA_key_types.h"
37 #include "DNA_material_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_meshdata_types.h"
40 #include "DNA_modifier_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
44 #include "BLI_listbase.h"
45 #include "BLI_noise.h"
48 #include "BLI_sort_utils.h"
50 #include "BKE_material.h"
51 #include "BKE_context.h"
52 #include "BKE_deform.h"
53 #include "BKE_depsgraph.h"
54 #include "BKE_report.h"
55 #include "BKE_texture.h"
57 #include "BKE_editmesh.h"
59 #include "BLT_translation.h"
61 #include "RNA_define.h"
62 #include "RNA_access.h"
63 #include "RNA_enum_types.h"
69 #include "ED_object.h"
70 #include "ED_screen.h"
71 #include "ED_transform.h"
72 #include "ED_transform_snap_object_context.h"
73 #include "ED_uvedit.h"
74 #include "ED_view3d.h"
76 #include "RE_render_ext.h"
78 #include "UI_interface.h"
79 #include "UI_resources.h"
81 #include "mesh_intern.h" /* own include */
83 #include "bmesh_tools.h"
85 #define USE_FACE_CREATE_SEL_EXTEND
87 /* -------------------------------------------------------------------- */
88 /** \name Subdivide Operator
91 static int edbm_subdivide_exec(bContext *C, wmOperator *op)
93 Object *obedit = CTX_data_edit_object(C);
94 BMEditMesh *em = BKE_editmesh_from_object(obedit);
95 const int cuts = RNA_int_get(op->ptr, "number_cuts");
96 float smooth = RNA_float_get(op->ptr, "smoothness");
97 const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
98 const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
100 if (RNA_boolean_get(op->ptr, "quadtri") &&
101 RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT)
103 RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT);
107 em->bm, BM_ELEM_SELECT,
108 smooth, SUBD_FALLOFF_LIN, false,
109 fractal, along_normal,
111 SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
112 RNA_boolean_get(op->ptr, "quadtri"), true, false,
113 RNA_int_get(op->ptr, "seed"));
115 EDBM_update_generic(em, true, true);
117 return OPERATOR_FINISHED;
120 /* Note, these values must match delete_mesh() event values */
121 static const EnumPropertyItem prop_mesh_cornervert_types[] = {
122 {SUBD_CORNER_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
123 {SUBD_CORNER_PATH, "PATH", 0, "Path", ""},
124 {SUBD_CORNER_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
125 {SUBD_CORNER_FAN, "FAN", 0, "Fan", ""},
126 {0, NULL, 0, NULL, NULL}
129 void MESH_OT_subdivide(wmOperatorType *ot)
134 ot->name = "Subdivide";
135 ot->description = "Subdivide selected edges";
136 ot->idname = "MESH_OT_subdivide";
139 ot->exec = edbm_subdivide_exec;
140 ot->poll = ED_operator_editmesh;
143 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
146 prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 100, "Number of Cuts", "", 1, 10);
147 /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
148 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
150 RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
152 RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
153 RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_CORNER_STRAIGHT_CUT,
154 "Quad Corner Type", "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)");
156 RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, 1e6f, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
157 RNA_def_float(ot->srna, "fractal_along_normal", 0.0f, 0.0f, 1.0f,
158 "Along Normal", "Apply fractal displacement along normal only", 0.0f, 1.0f);
159 RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Random Seed", "Seed for the random number generator", 0, 255);
164 /* -------------------------------------------------------------------- */
165 /** \name Edge Ring Subdivide Operator
167 * Bridge code shares props.
171 struct EdgeRingOpSubdProps {
177 float profile_shape_factor;
181 static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_min, const int cuts_default)
183 /* Note, these values must match delete_mesh() event values */
184 static const EnumPropertyItem prop_subd_edgering_types[] = {
185 {SUBD_RING_INTERP_LINEAR, "LINEAR", 0, "Linear", ""},
186 {SUBD_RING_INTERP_PATH, "PATH", 0, "Blend Path", ""},
187 {SUBD_RING_INTERP_SURF, "SURFACE", 0, "Blend Surface", ""},
188 {0, NULL, 0, NULL, NULL}
193 prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", cuts_min, 64);
194 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
196 RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH,
197 "Interpolation", "Interpolation method");
199 RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1e3f,
200 "Smoothness", "Smoothness factor", 0.0f, 2.0f);
203 RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -1e3f, 1e3f,
204 "Profile Factor", "How much intermediary new edges are shrunk/expanded", -2.0f, 2.0f);
206 prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE);
207 RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items);
208 RNA_def_property_enum_default(prop, PROP_SMOOTH);
209 RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile");
210 RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
213 static void mesh_operator_edgering_props_get(wmOperator *op, struct EdgeRingOpSubdProps *op_props)
215 op_props->interp_mode = RNA_enum_get(op->ptr, "interpolation");
216 op_props->cuts = RNA_int_get(op->ptr, "number_cuts");
217 op_props->smooth = RNA_float_get(op->ptr, "smoothness");
219 op_props->profile_shape = RNA_enum_get(op->ptr, "profile_shape");
220 op_props->profile_shape_factor = RNA_float_get(op->ptr, "profile_shape_factor");
223 static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op)
225 Object *obedit = CTX_data_edit_object(C);
226 BMEditMesh *em = BKE_editmesh_from_object(obedit);
227 struct EdgeRingOpSubdProps op_props;
229 mesh_operator_edgering_props_get(op, &op_props);
233 "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
234 "profile_shape=%i profile_shape_factor=%f",
235 BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth,
236 op_props.profile_shape, op_props.profile_shape_factor))
238 return OPERATOR_CANCELLED;
241 EDBM_update_generic(em, true, true);
243 return OPERATOR_FINISHED;
246 void MESH_OT_subdivide_edgering(wmOperatorType *ot)
249 ot->name = "Subdivide Edge-Ring";
250 ot->idname = "MESH_OT_subdivide_edgering";
253 ot->exec = edbm_subdivide_edge_ring_exec;
254 ot->poll = ED_operator_editmesh;
257 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
260 mesh_operator_edgering_props(ot, 1, 10);
265 /* -------------------------------------------------------------------- */
266 /** \name Un-Subdivide Operator
269 static int edbm_unsubdivide_exec(bContext *C, wmOperator *op)
271 Object *obedit = CTX_data_edit_object(C);
272 BMEditMesh *em = BKE_editmesh_from_object(obedit);
275 const int iterations = RNA_int_get(op->ptr, "iterations");
277 EDBM_op_init(em, &bmop, op,
278 "unsubdivide verts=%hv iterations=%i", BM_ELEM_SELECT, iterations);
280 BMO_op_exec(em->bm, &bmop);
282 if (!EDBM_op_finish(em, &bmop, op, true)) {
286 if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
287 EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); /* need to flush vert->face first */
289 EDBM_selectmode_flush(em);
291 EDBM_update_generic(em, true, true);
293 return OPERATOR_FINISHED;
296 void MESH_OT_unsubdivide(wmOperatorType *ot)
299 ot->name = "Un-Subdivide";
300 ot->description = "UnSubdivide selected edges & faces";
301 ot->idname = "MESH_OT_unsubdivide";
304 ot->exec = edbm_unsubdivide_exec;
305 ot->poll = ED_operator_editmesh;
308 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
311 RNA_def_int(ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to unsubdivide", 1, 100);
314 void EDBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
316 Object *obedit = em->ob;
320 ED_view3d_init_mats_rv3d(obedit, ar->regiondata);
322 struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
323 CTX_data_main(C), CTX_data_scene(C), 0,
324 ar, CTX_wm_view3d(C));
326 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
327 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
328 float mval[2], co_proj[3];
329 if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
330 if (ED_transform_snap_object_project_view3d_mixed(
333 &(const struct SnapObjectParams){
334 .snap_select = SNAP_NOT_ACTIVE,
335 .use_object_edit_cage = false,
340 mul_v3_m4v3(eve->co, obedit->imat, co_proj);
346 ED_transform_snap_object_context_destroy(snap_context);
351 /* -------------------------------------------------------------------- */
352 /** \name Delete Operator
355 /* Note, these values must match delete_mesh() event values */
357 MESH_DELETE_VERT = 0,
358 MESH_DELETE_EDGE = 1,
359 MESH_DELETE_FACE = 2,
360 MESH_DELETE_EDGE_FACE = 3,
361 MESH_DELETE_ONLY_FACE = 4,
364 static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int totelem[3])
366 BKE_reportf(reports, RPT_INFO,
367 "Removed: %d vertices, %d edges, %d faces",
368 totelem[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface);
371 static int edbm_delete_exec(bContext *C, wmOperator *op)
373 Object *obedit = CTX_data_edit_object(C);
374 BMEditMesh *em = BKE_editmesh_from_object(obedit);
375 const int type = RNA_enum_get(op->ptr, "type");
378 case MESH_DELETE_VERT:
379 if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
380 return OPERATOR_CANCELLED;
382 case MESH_DELETE_EDGE:
383 if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
384 return OPERATOR_CANCELLED;
386 case MESH_DELETE_FACE:
387 if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
388 return OPERATOR_CANCELLED;
390 case MESH_DELETE_EDGE_FACE:
391 /* Edges and Faces */
392 if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))
393 return OPERATOR_CANCELLED;
395 case MESH_DELETE_ONLY_FACE:
397 if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES))
398 return OPERATOR_CANCELLED;
405 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
407 EDBM_update_generic(em, true, true);
409 return OPERATOR_FINISHED;
412 void MESH_OT_delete(wmOperatorType *ot)
414 static const EnumPropertyItem prop_mesh_delete_types[] = {
415 {MESH_DELETE_VERT, "VERT", 0, "Vertices", ""},
416 {MESH_DELETE_EDGE, "EDGE", 0, "Edges", ""},
417 {MESH_DELETE_FACE, "FACE", 0, "Faces", ""},
418 {MESH_DELETE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""},
419 {MESH_DELETE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""},
420 {0, NULL, 0, NULL, NULL}
425 ot->description = "Delete selected vertices, edges or faces";
426 ot->idname = "MESH_OT_delete";
429 ot->invoke = WM_menu_invoke;
430 ot->exec = edbm_delete_exec;
432 ot->poll = ED_operator_editmesh;
435 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
438 ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, MESH_DELETE_VERT,
439 "Type", "Method used for deleting mesh data");
444 /* -------------------------------------------------------------------- */
445 /** \name Delete Loose Operator
448 static bool bm_face_is_loose(BMFace *f)
450 BMLoop *l_iter, *l_first;
452 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
454 if (!BM_edge_is_boundary(l_iter->e)) {
457 } while ((l_iter = l_iter->next) != l_first);
462 static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
464 Object *obedit = CTX_data_edit_object(C);
465 BMEditMesh *em = BKE_editmesh_from_object(obedit);
469 const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && bm->totvertsel);
470 const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && bm->totedgesel);
471 const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && bm->totfacesel);
473 const int totelem[3] = {bm->totvert, bm->totedge, bm->totface};
476 BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
481 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
482 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
483 BM_elem_flag_set(f, BM_ELEM_TAG, bm_face_is_loose(f));
487 BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
493 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
494 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
495 BM_elem_flag_set(e, BM_ELEM_TAG, BM_edge_is_wire(e));
499 BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_EDGES);
505 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
506 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
507 BM_elem_flag_set(v, BM_ELEM_TAG, (v->e == NULL));
511 BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS);
514 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
516 EDBM_update_generic(em, true, true);
518 edbm_report_delete_info(op->reports, bm, totelem);
520 return OPERATOR_FINISHED;
524 void MESH_OT_delete_loose(wmOperatorType *ot)
527 ot->name = "Delete Loose";
528 ot->description = "Delete loose vertices, edges or faces";
529 ot->idname = "MESH_OT_delete_loose";
532 ot->exec = edbm_delete_loose_exec;
534 ot->poll = ED_operator_editmesh;
537 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
540 RNA_def_boolean(ot->srna, "use_verts", true, "Vertices", "Remove loose vertices");
541 RNA_def_boolean(ot->srna, "use_edges", true, "Edges", "Remove loose edges");
542 RNA_def_boolean(ot->srna, "use_faces", false, "Faces", "Remove loose faces");
547 /* -------------------------------------------------------------------- */
548 /** \name Collapse Edge Operator
551 static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
553 Object *obedit = CTX_data_edit_object(C);
554 BMEditMesh *em = BKE_editmesh_from_object(obedit);
556 if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true))
557 return OPERATOR_CANCELLED;
559 EDBM_update_generic(em, true, true);
561 return OPERATOR_FINISHED;
564 void MESH_OT_edge_collapse(wmOperatorType *ot)
567 ot->name = "Edge Collapse";
568 ot->description = "Collapse selected edges";
569 ot->idname = "MESH_OT_edge_collapse";
572 ot->exec = edbm_collapse_edge_exec;
573 ot->poll = ED_operator_editmesh;
576 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
581 /* -------------------------------------------------------------------- */
582 /** \name Create Edge/Face Operator
585 static bool edbm_add_edge_face__smooth_get(BMesh *bm)
590 unsigned int vote_on_smooth[2] = {0, 0};
592 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
593 if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
594 vote_on_smooth[BM_elem_flag_test_bool(e->l->f, BM_ELEM_SMOOTH)]++;
598 return (vote_on_smooth[0] < vote_on_smooth[1]);
601 #ifdef USE_FACE_CREATE_SEL_EXTEND
603 * Function used to get a fixed number of edges linked to a vertex that passes a test function.
604 * This is used so we can request all boundary edges connected to a vertex for eg.
606 static int edbm_add_edge_face_exec__vert_edge_lookup(
607 BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len,
608 bool (* func)(const BMEdge *))
613 BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
614 if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) {
615 if ((e_used == NULL) || (e_used != e_iter)) {
618 if (i >= e_arr_len) {
628 static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm)
633 if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) {
634 /* first look for 2 boundary edges */
637 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
638 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
647 ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_wire) == 2) &&
648 (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) ||
650 ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_boundary) == 2) &&
651 (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false))
654 BMEdge *e_other = BM_edge_exists(
655 BM_edge_other_vert(ed_pair[0], v),
656 BM_edge_other_vert(ed_pair[1], v));
657 BM_edge_select_set(bm, ed_pair[0], true);
658 BM_edge_select_set(bm, ed_pair[1], true);
660 BM_edge_select_set(bm, e_other, true);
666 else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) {
667 /* first look for 2 boundary edges */
670 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
671 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
677 BMEdge *ed_pair_v1[2];
678 BMEdge *ed_pair_v2[2];
680 ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == 1) &&
681 (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == 1) &&
682 (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
683 (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
685 #if 1 /* better support mixed cases [#37203] */
686 ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == 1) &&
687 (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) &&
688 (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
689 (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
691 ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) &&
692 (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == 1) &&
693 (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
694 (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
697 ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) &&
698 (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) &&
699 (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
700 (BM_edge_share_face_check(e, ed_pair_v2[0]) == false))
703 BMVert *v1_other = BM_edge_other_vert(ed_pair_v1[0], e->v1);
704 BMVert *v2_other = BM_edge_other_vert(ed_pair_v2[0], e->v2);
705 BMEdge *e_other = (v1_other != v2_other) ? BM_edge_exists(v1_other, v2_other) : NULL;
706 BM_edge_select_set(bm, ed_pair_v1[0], true);
707 BM_edge_select_set(bm, ed_pair_v2[0], true);
709 BM_edge_select_set(bm, e_other, true);
718 static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_desel, BMFace *f)
720 /* now we need to find the edge that isnt connected to this element */
721 BM_select_history_clear(bm);
723 /* Notes on hidden geometry:
724 * - un-hide the face since its possible hidden was copied when copying surrounding face attributes.
725 * - un-hide before adding to select history
726 * since we may extend into an existing, hidden vert/edge.
729 BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
730 BM_face_select_set(bm, f, false);
732 if (ele_desel->head.htype == BM_VERT) {
733 BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel);
734 BLI_assert(f->len == 3);
735 BM_vert_select_set(bm, (BMVert *)ele_desel, false);
736 BM_edge_select_set(bm, l->next->e, true);
737 BM_select_history_store(bm, l->next->e);
740 BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel);
741 BLI_assert(f->len == 4 || f->len == 3);
743 BM_edge_select_set(bm, (BMEdge *)ele_desel, false);
745 BMEdge *e_active = l->next->next->e;
746 BM_elem_flag_disable(e_active, BM_ELEM_HIDDEN);
747 BM_edge_select_set(bm, e_active, true);
748 BM_select_history_store(bm, e_active);
751 BMVert *v_active = l->next->next->v;
752 BM_elem_flag_disable(v_active, BM_ELEM_HIDDEN);
753 BM_vert_select_set(bm, v_active, true);
754 BM_select_history_store(bm, v_active);
758 #endif /* USE_FACE_CREATE_SEL_EXTEND */
760 static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
763 Object *obedit = CTX_data_edit_object(C);
764 BMEditMesh *em = BKE_editmesh_from_object(obedit);
765 const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
766 const int totedge_orig = em->bm->totedge;
767 const int totface_orig = em->bm->totface;
768 /* when this is used to dissolve we could avoid this, but checking isnt too slow */
770 #ifdef USE_FACE_CREATE_SEL_EXTEND
772 BMFace *ele_desel_face;
774 /* be extra clever, figure out if a partial selection should be extended so we can create geometry
775 * with single vert or single edge selection */
776 ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm);
781 "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
782 BM_ELEM_SELECT, em->mat_nr, use_smooth))
784 return OPERATOR_CANCELLED;
787 BMO_op_exec(em->bm, &bmop);
789 /* cancel if nothing was done */
790 if ((totedge_orig == em->bm->totedge) &&
791 (totface_orig == em->bm->totface))
793 EDBM_op_finish(em, &bmop, op, true);
794 return OPERATOR_CANCELLED;
797 #ifdef USE_FACE_CREATE_SEL_EXTEND
798 /* normally we would want to leave the new geometry selected,
799 * but being able to press F many times to add geometry is too useful! */
801 (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) &&
802 (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out")))
804 edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face);
809 /* Newly created faces may include existing hidden edges,
810 * copying face data from surrounding, may have copied hidden face flag too.
812 * Important that faces use flushing since 'edges.out' wont include hidden edges that already existed.
814 BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true);
815 BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false);
817 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
818 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
821 if (!EDBM_op_finish(em, &bmop, op, true)) {
822 return OPERATOR_CANCELLED;
825 EDBM_update_generic(em, true, true);
827 return OPERATOR_FINISHED;
830 void MESH_OT_edge_face_add(wmOperatorType *ot)
833 ot->name = "Make Edge/Face";
834 ot->description = "Add an edge or face to selected";
835 ot->idname = "MESH_OT_edge_face_add";
838 ot->exec = edbm_add_edge_face_exec;
839 ot->poll = ED_operator_editmesh;
842 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
847 /* -------------------------------------------------------------------- */
848 /** \name Mark Edge (Seam) Operator
851 static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
853 Scene *scene = CTX_data_scene(C);
854 Object *obedit = CTX_data_edit_object(C);
855 Mesh *me = ((Mesh *)obedit->data);
856 BMEditMesh *em = BKE_editmesh_from_object(obedit);
860 const bool clear = RNA_boolean_get(op->ptr, "clear");
862 /* auto-enable seams drawing */
864 me->drawflag |= ME_DRAWSEAMS;
868 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
869 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
872 BM_elem_flag_disable(eed, BM_ELEM_SEAM);
876 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
877 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
879 BM_elem_flag_enable(eed, BM_ELEM_SEAM);
883 ED_uvedit_live_unwrap(scene, obedit);
884 EDBM_update_generic(em, true, false);
886 return OPERATOR_FINISHED;
889 void MESH_OT_mark_seam(wmOperatorType *ot)
894 ot->name = "Mark Seam";
895 ot->idname = "MESH_OT_mark_seam";
896 ot->description = "(Un)mark selected edges as a seam";
899 ot->exec = edbm_mark_seam_exec;
900 ot->poll = ED_operator_editmesh;
903 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
905 prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
906 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
911 /* -------------------------------------------------------------------- */
912 /** \name Mark Edge (Sharp) Operator
915 static int edbm_mark_sharp_exec(bContext *C, wmOperator *op)
917 Object *obedit = CTX_data_edit_object(C);
918 Mesh *me = ((Mesh *)obedit->data);
919 BMEditMesh *em = BKE_editmesh_from_object(obedit);
923 const bool clear = RNA_boolean_get(op->ptr, "clear");
924 const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
926 /* auto-enable sharp edge drawing */
928 me->drawflag |= ME_DRAWSHARP;
931 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
933 if (!(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))) {
937 else if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
941 BM_elem_flag_set(eed, BM_ELEM_SMOOTH, clear);
944 EDBM_update_generic(em, true, false);
946 return OPERATOR_FINISHED;
949 void MESH_OT_mark_sharp(wmOperatorType *ot)
954 ot->name = "Mark Sharp";
955 ot->idname = "MESH_OT_mark_sharp";
956 ot->description = "(Un)mark selected edges as sharp";
959 ot->exec = edbm_mark_sharp_exec;
960 ot->poll = ED_operator_editmesh;
963 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
965 prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
966 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
967 prop = RNA_def_boolean(ot->srna, "use_verts", false, "Vertices",
968 "Consider vertices instead of edges to select which edges to (un)tag as sharp");
969 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
972 static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
974 Object *obedit = CTX_data_edit_object(C);
975 BMEditMesh *em = BKE_editmesh_from_object(obedit);
978 bool is_pair = (bm->totvertsel == 2);
980 bool check_degenerate = true;
981 const int verts_len = bm->totvertsel;
984 verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__);
990 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
991 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
997 if (BM_vert_pair_share_face_check_cb(
999 BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN)))
1001 check_degenerate = false;
1010 "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
1011 verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
1019 "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
1020 verts, verts_len, BM_ELEM_HIDDEN, check_degenerate))
1026 BMO_op_exec(bm, &bmop);
1027 len = BMO_slot_get(bmop.slots_out, "edges.out")->len;
1031 /* new verts have been added, we have to select the edges, not just flush */
1032 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
1036 if (!EDBM_op_finish(em, &bmop, op, true)) {
1040 EDBM_selectmode_flush(em); /* so newly created edges get the selection state from the vertex */
1042 EDBM_update_generic(em, true, true);
1048 return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1051 void MESH_OT_vert_connect(wmOperatorType *ot)
1054 ot->name = "Vertex Connect";
1055 ot->idname = "MESH_OT_vert_connect";
1056 ot->description = "Connect selected vertices of faces, splitting the face";
1059 ot->exec = edbm_vert_connect_exec;
1060 ot->poll = ED_operator_editmesh;
1063 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1068 /* -------------------------------------------------------------------- */
1069 /** \name Split Concave Faces Operator
1073 * check that endpoints are verts and only have a single selected edge connected.
1075 static bool bm_vert_is_select_history_open(BMesh *bm)
1077 BMEditSelection *ele_a = bm->selected.first;
1078 BMEditSelection *ele_b = bm->selected.last;
1079 if ((ele_a->htype == BM_VERT) &&
1080 (ele_b->htype == BM_VERT))
1082 if ((BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_a->ele, BM_ELEM_SELECT, true) == 1) &&
1083 (BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_b->ele, BM_ELEM_SELECT, true) == 1))
1092 static bool bm_vert_connect_pair(BMesh *bm, BMVert *v_a, BMVert *v_b)
1096 const int totedge_orig = bm->totedge;
1098 BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, "connect_vert_pair");
1100 verts = BMO_slot_buffer_alloc(&bmop, bmop.slots_in, "verts", 2);
1104 BM_vert_normal_update(verts[0]);
1105 BM_vert_normal_update(verts[1]);
1107 BMO_op_exec(bm, &bmop);
1108 BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
1109 BMO_op_finish(bm, &bmop);
1110 return (bm->totedge != totedge_orig);
1113 static bool bm_vert_connect_select_history(BMesh *bm)
1115 /* Logic is as follows:
1117 * - If there are any isolated/wire verts - connect as edges.
1118 * - Otherwise connect faces.
1119 * - If all edges have been created already, closed the loop.
1121 if (BLI_listbase_count_at_most(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) {
1122 BMEditSelection *ese;
1124 bool changed = false;
1125 bool has_wire = false;
1128 /* ensure all verts have history */
1129 for (ese = bm->selected.first; ese; ese = ese->next, tot++) {
1131 if (ese->htype != BM_VERT) {
1134 v = (BMVert *)ese->ele;
1135 if ((has_wire == false) && ((v->e == NULL) || BM_vert_is_wire(v))) {
1139 // all_verts = (ese == NULL);
1141 if (has_wire == false) {
1142 /* all verts have faces , connect verts via faces! */
1143 if (tot == bm->totvertsel) {
1144 BMEditSelection *ese_last;
1145 ese_last = bm->selected.first;
1146 ese = ese_last->next;
1150 if (BM_edge_exists((BMVert *)ese_last->ele, (BMVert *)ese->ele)) {
1151 /* pass, edge exists (and will be selected) */
1154 changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele);
1165 if (changed == false) {
1166 /* existing loops: close the selection */
1167 if (bm_vert_is_select_history_open(bm)) {
1168 changed |= bm_vert_connect_pair(
1170 (BMVert *)((BMEditSelection *)bm->selected.first)->ele,
1171 (BMVert *)((BMEditSelection *)bm->selected.last)->ele);
1181 /* no faces, simply connect the verts by edges */
1182 BMEditSelection *ese_prev;
1183 ese_prev = bm->selected.first;
1184 ese = ese_prev->next;
1188 if (BM_edge_exists((BMVert *)ese_prev->ele, (BMVert *)ese->ele)) {
1189 /* pass, edge exists (and will be selected) */
1193 e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
1194 BM_edge_select_set(bm, e, true);
1201 if (changed == false) {
1202 /* existing loops: close the selection */
1203 if (bm_vert_is_select_history_open(bm)) {
1205 ese_prev = bm->selected.first;
1206 ese = bm->selected.last;
1207 e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
1208 BM_edge_select_set(bm, e, true);
1220 * Convert an edge selection to a temp vertex selection
1221 * (which must be cleared after use as a path to connect).
1223 static bool bm_vert_connect_select_history_edge_to_vert_path(BMesh *bm, ListBase *r_selected)
1225 ListBase selected_orig = {NULL, NULL};
1226 BMEditSelection *ese;
1230 /* first check all edges are OK */
1231 for (ese = bm->selected.first; ese; ese = ese->next) {
1232 if (ese->htype == BM_EDGE) {
1239 /* if this is a mixed selection, bail out! */
1240 if (bm->totedgesel != edges_len) {
1244 SWAP(ListBase, bm->selected, selected_orig);
1246 /* convert edge selection into 2 ordered loops (where the first edge ends up in the middle) */
1247 for (ese = selected_orig.first; ese; ese = ese->next) {
1248 BMEdge *e_curr = (BMEdge *)ese->ele;
1249 BMEdge *e_prev = ese->prev ? (BMEdge *)ese->prev->ele : NULL;
1255 BMFace *f = BM_edge_pair_share_face_by_len(e_curr, e_prev, &l_curr, &l_prev, true);
1257 if ((e_curr->v1 != l_curr->v) == (e_prev->v1 != l_prev->v)) {
1261 else if (is_quad_flip_v3(e_curr->v1->co, e_curr->v2->co, e_prev->v2->co, e_prev->v1->co)) {
1266 v = (&e_curr->v1)[side];
1267 if (!bm->selected.last || (BMVert *)((BMEditSelection *)bm->selected.last)->ele != v) {
1268 BM_select_history_store_notest(bm, v);
1271 v = (&e_curr->v1)[!side];
1272 if (!bm->selected.first || (BMVert *)((BMEditSelection *)bm->selected.first)->ele != v) {
1273 BM_select_history_store_head_notest(bm, v);
1279 *r_selected = bm->selected;
1280 bm->selected = selected_orig;
1285 static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
1287 Object *obedit = CTX_data_edit_object(C);
1288 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1290 bool is_pair = (em->bm->totvertsel == 2);
1291 ListBase selected_orig = {NULL, NULL};
1294 /* when there is only 2 vertices, we can ignore selection order */
1296 return edbm_vert_connect_exec(C, op);
1299 if (bm->selected.first) {
1300 BMEditSelection *ese = bm->selected.first;
1301 if (ese->htype == BM_EDGE) {
1302 if (bm_vert_connect_select_history_edge_to_vert_path(bm, &selected_orig)) {
1303 SWAP(ListBase, bm->selected, selected_orig);
1308 if (bm_vert_connect_select_history(bm)) {
1309 EDBM_selectmode_flush(em);
1310 EDBM_update_generic(em, true, true);
1311 retval = OPERATOR_FINISHED;
1314 BKE_report(op->reports, RPT_ERROR, "Invalid selection order");
1315 retval = OPERATOR_CANCELLED;
1318 if (!BLI_listbase_is_empty(&selected_orig)) {
1319 BM_select_history_clear(bm);
1320 bm->selected = selected_orig;
1326 void MESH_OT_vert_connect_path(wmOperatorType *ot)
1329 ot->name = "Vertex Connect Path";
1330 ot->idname = "MESH_OT_vert_connect_path";
1331 ot->description = "Connect vertices by their selection order, creating edges, splitting faces";
1334 ot->exec = edbm_vert_connect_path_exec;
1335 ot->poll = ED_operator_editmesh;
1338 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1341 static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
1343 Object *obedit = CTX_data_edit_object(C);
1344 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1346 if (!EDBM_op_call_and_selectf(
1349 "connect_verts_concave faces=%hf",
1352 return OPERATOR_CANCELLED;
1356 EDBM_update_generic(em, true, true);
1357 return OPERATOR_FINISHED;
1360 void MESH_OT_vert_connect_concave(wmOperatorType *ot)
1363 ot->name = "Split Concave Faces";
1364 ot->idname = "MESH_OT_vert_connect_concave";
1365 ot->description = "Make all faces convex";
1368 ot->exec = edbm_vert_connect_concave_exec;
1369 ot->poll = ED_operator_editmesh;
1372 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1377 /* -------------------------------------------------------------------- */
1378 /** \name Split Non-Planar Faces Operator
1381 static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
1383 Object *obedit = CTX_data_edit_object(C);
1384 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1386 const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
1388 if (!EDBM_op_call_and_selectf(
1391 "connect_verts_nonplanar faces=%hf angle_limit=%f",
1392 BM_ELEM_SELECT, angle_limit))
1394 return OPERATOR_CANCELLED;
1398 EDBM_update_generic(em, true, true);
1399 return OPERATOR_FINISHED;
1402 void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot)
1407 ot->name = "Split Non-Planar Faces";
1408 ot->idname = "MESH_OT_vert_connect_nonplanar";
1409 ot->description = "Split non-planar faces that exceed the angle threshold";
1412 ot->exec = edbm_vert_connect_nonplaner_exec;
1413 ot->poll = ED_operator_editmesh;
1416 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1419 prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
1420 "Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f));
1421 RNA_def_property_float_default(prop, DEG2RADF(5.0f));
1426 /* -------------------------------------------------------------------- */
1427 /** \name Make Planar Faces Operator
1430 static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
1432 Object *obedit = CTX_data_edit_object(C);
1433 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1434 const int repeat = RNA_int_get(op->ptr, "repeat");
1435 const float fac = RNA_float_get(op->ptr, "factor");
1438 em, op, "planar_faces faces=%hf iterations=%i factor=%f",
1439 BM_ELEM_SELECT, repeat, fac))
1441 return OPERATOR_CANCELLED;
1444 EDBM_update_generic(em, true, true);
1445 return OPERATOR_FINISHED;
1448 void MESH_OT_face_make_planar(wmOperatorType *ot)
1451 ot->name = "Make Planar Faces";
1452 ot->idname = "MESH_OT_face_make_planar";
1453 ot->description = "Flatten selected faces";
1456 ot->exec = edbm_face_make_planar_exec;
1457 ot->poll = ED_operator_editmesh;
1460 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1463 RNA_def_float(ot->srna, "factor", 1.0f, -10.0f, 10.0f, "Factor", "", 0.0f, 1.0f);
1464 RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
1469 /* -------------------------------------------------------------------- */
1470 /** \name Split Edge Operator
1473 static int edbm_edge_split_exec(bContext *C, wmOperator *op)
1475 Object *obedit = CTX_data_edit_object(C);
1476 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1478 if (!EDBM_op_call_and_selectf(
1481 "split_edges edges=%he",
1484 return OPERATOR_CANCELLED;
1487 if (em->selectmode == SCE_SELECT_FACE) {
1488 EDBM_select_flush(em);
1491 EDBM_update_generic(em, true, true);
1493 return OPERATOR_FINISHED;
1496 void MESH_OT_edge_split(wmOperatorType *ot)
1499 ot->name = "Edge Split";
1500 ot->idname = "MESH_OT_edge_split";
1501 ot->description = "Split selected edges so that each neighbor face gets its own copy";
1504 ot->exec = edbm_edge_split_exec;
1505 ot->poll = ED_operator_editmesh;
1508 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1513 /* -------------------------------------------------------------------- */
1514 /** \name Duplicate Operator
1517 static int edbm_duplicate_exec(bContext *C, wmOperator *op)
1519 Object *ob = CTX_data_edit_object(C);
1520 BMEditMesh *em = BKE_editmesh_from_object(ob);
1526 "duplicate geom=%hvef use_select_history=%b",
1527 BM_ELEM_SELECT, true);
1529 BMO_op_exec(bm, &bmop);
1531 /* de-select all would clear otherwise */
1532 BM_SELECT_HISTORY_BACKUP(bm);
1534 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1536 BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
1538 /* rebuild editselection */
1539 BM_SELECT_HISTORY_RESTORE(bm);
1541 if (!EDBM_op_finish(em, &bmop, op, true)) {
1542 return OPERATOR_CANCELLED;
1545 EDBM_update_generic(em, true, true);
1547 return OPERATOR_FINISHED;
1550 static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1553 edbm_duplicate_exec(C, op);
1556 return OPERATOR_FINISHED;
1559 void MESH_OT_duplicate(wmOperatorType *ot)
1562 ot->name = "Duplicate";
1563 ot->description = "Duplicate selected vertices, edges or faces";
1564 ot->idname = "MESH_OT_duplicate";
1567 ot->invoke = edbm_duplicate_invoke;
1568 ot->exec = edbm_duplicate_exec;
1570 ot->poll = ED_operator_editmesh;
1572 /* to give to transform */
1573 RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
1578 /* -------------------------------------------------------------------- */
1579 /** \name Flip Normals Operator
1581 static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
1583 Object *obedit = CTX_data_edit_object(C);
1584 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1587 em, op, "reverse_faces faces=%hf flip_multires=%b",
1588 BM_ELEM_SELECT, true))
1590 return OPERATOR_CANCELLED;
1593 EDBM_update_generic(em, true, false);
1595 return OPERATOR_FINISHED;
1598 void MESH_OT_flip_normals(wmOperatorType *ot)
1601 ot->name = "Flip Normals";
1602 ot->description = "Flip the direction of selected faces' normals (and of their vertices)";
1603 ot->idname = "MESH_OT_flip_normals";
1606 ot->exec = edbm_flip_normals_exec;
1607 ot->poll = ED_operator_editmesh;
1610 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1615 /* -------------------------------------------------------------------- */
1616 /** \name Rotate Edge Operator
1620 * Rotate the edges between selected faces, otherwise rotate the selected edges.
1622 static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
1624 Object *obedit = CTX_data_edit_object(C);
1625 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1629 const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
1632 if (em->bm->totedgesel == 0) {
1633 BKE_report(op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about");
1634 return OPERATOR_CANCELLED;
1637 /* first see if we have two adjacent faces */
1638 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1639 BM_elem_flag_disable(eed, BM_ELEM_TAG);
1640 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1642 if (BM_edge_face_pair(eed, &fa, &fb)) {
1643 /* if both faces are selected we rotate between them,
1644 * otherwise - rotate between 2 unselected - but not mixed */
1645 if (BM_elem_flag_test(fa, BM_ELEM_SELECT) == BM_elem_flag_test(fb, BM_ELEM_SELECT)) {
1646 BM_elem_flag_enable(eed, BM_ELEM_TAG);
1653 /* ok, we don't have two adjacent faces, but we do have two selected ones.
1654 * that's an error condition.*/
1656 BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated");
1657 return OPERATOR_CANCELLED;
1660 EDBM_op_init(em, &bmop, op, "rotate_edges edges=%he use_ccw=%b", BM_ELEM_TAG, use_ccw);
1662 /* avoids leaving old verts selected which can be a problem running multiple times,
1663 * since this means the edges become selected around the face which then attempt to rotate */
1664 BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "edges", BM_EDGE, BM_ELEM_SELECT, true);
1666 BMO_op_exec(em->bm, &bmop);
1667 /* edges may rotate into hidden vertices, if this does _not_ run we get an ilogical state */
1668 BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true);
1669 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
1671 const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out");
1672 const int tot_failed = tot - tot_rotate;
1673 if (tot_failed != 0) {
1674 /* If some edges fail to rotate, we need to re-select them,
1675 * otherwise we can end up with invalid selection
1676 * (unselected edge between 2 selected faces). */
1677 BM_mesh_elem_hflag_enable_test(em->bm, BM_EDGE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
1679 BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed);
1682 EDBM_selectmode_flush(em);
1684 if (!EDBM_op_finish(em, &bmop, op, true)) {
1685 return OPERATOR_CANCELLED;
1688 EDBM_update_generic(em, true, true);
1690 return OPERATOR_FINISHED;
1693 void MESH_OT_edge_rotate(wmOperatorType *ot)
1696 ot->name = "Rotate Selected Edge";
1697 ot->description = "Rotate selected edge or adjoining faces";
1698 ot->idname = "MESH_OT_edge_rotate";
1701 ot->exec = edbm_edge_rotate_selected_exec;
1702 ot->poll = ED_operator_editmesh;
1705 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1708 RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
1713 /* -------------------------------------------------------------------- */
1714 /** \name Hide Operator
1717 static int edbm_hide_exec(bContext *C, wmOperator *op)
1719 Object *obedit = CTX_data_edit_object(C);
1720 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1722 EDBM_mesh_hide(em, RNA_boolean_get(op->ptr, "unselected"));
1724 EDBM_update_generic(em, true, false);
1726 return OPERATOR_FINISHED;
1729 void MESH_OT_hide(wmOperatorType *ot)
1732 ot->name = "Hide Selection";
1733 ot->idname = "MESH_OT_hide";
1734 ot->description = "Hide (un)selected vertices, edges or faces";
1737 ot->exec = edbm_hide_exec;
1738 ot->poll = ED_operator_editmesh;
1741 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1744 RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
1749 /* -------------------------------------------------------------------- */
1750 /** \name Reveal Operator
1753 static int edbm_reveal_exec(bContext *C, wmOperator *op)
1755 Object *obedit = CTX_data_edit_object(C);
1756 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1757 const bool select = RNA_boolean_get(op->ptr, "select");
1759 EDBM_mesh_reveal(em, select);
1761 EDBM_update_generic(em, true, false);
1763 return OPERATOR_FINISHED;
1766 void MESH_OT_reveal(wmOperatorType *ot)
1769 ot->name = "Reveal Hidden";
1770 ot->idname = "MESH_OT_reveal";
1771 ot->description = "Reveal all hidden vertices, edges and faces";
1774 ot->exec = edbm_reveal_exec;
1775 ot->poll = ED_operator_editmesh;
1778 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1780 RNA_def_boolean(ot->srna, "select", true, "Select", "");
1785 /* -------------------------------------------------------------------- */
1786 /** \name Recalculate Normals Operator
1789 static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
1791 Object *obedit = CTX_data_edit_object(C);
1792 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1794 /* doflip has to do with bmesh_rationalize_normals, it's an internal
1796 if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT))
1797 return OPERATOR_CANCELLED;
1799 if (RNA_boolean_get(op->ptr, "inside")) {
1800 EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
1803 EDBM_update_generic(em, true, false);
1805 return OPERATOR_FINISHED;
1808 void MESH_OT_normals_make_consistent(wmOperatorType *ot)
1811 ot->name = "Make Normals Consistent";
1812 ot->description = "Make face and vertex normals point either outside or inside the mesh";
1813 ot->idname = "MESH_OT_normals_make_consistent";
1816 ot->exec = edbm_normals_make_consistent_exec;
1817 ot->poll = ED_operator_editmesh;
1820 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1822 RNA_def_boolean(ot->srna, "inside", false, "Inside", "");
1827 /* -------------------------------------------------------------------- */
1828 /** \name Smooth Vertex Operator
1831 static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
1833 Object *obedit = CTX_data_edit_object(C);
1834 Mesh *me = obedit->data;
1835 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1837 bool mirrx = false, mirry = false, mirrz = false;
1839 float clip_dist = 0.0f;
1840 const float fac = RNA_float_get(op->ptr, "factor");
1841 const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
1843 const bool xaxis = RNA_boolean_get(op->ptr, "xaxis");
1844 const bool yaxis = RNA_boolean_get(op->ptr, "yaxis");
1845 const bool zaxis = RNA_boolean_get(op->ptr, "zaxis");
1847 /* mirror before smooth */
1848 if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
1849 EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
1852 /* if there is a mirror modifier with clipping, flag the verts that
1853 * are within tolerance of the plane(s) of reflection
1855 for (md = obedit->modifiers.first; md; md = md->next) {
1856 if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
1857 MirrorModifierData *mmd = (MirrorModifierData *)md;
1859 if (mmd->flag & MOD_MIR_CLIPPING) {
1860 if (mmd->flag & MOD_MIR_AXIS_X)
1862 if (mmd->flag & MOD_MIR_AXIS_Y)
1864 if (mmd->flag & MOD_MIR_AXIS_Z)
1867 clip_dist = mmd->tolerance;
1872 repeat = RNA_int_get(op->ptr, "repeat");
1876 for (i = 0; i < repeat; i++) {
1879 "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
1880 "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
1881 BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
1883 return OPERATOR_CANCELLED;
1888 if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
1889 EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
1890 EDBM_verts_mirror_cache_end(em);
1893 EDBM_update_generic(em, true, false);
1895 return OPERATOR_FINISHED;
1899 void MESH_OT_vertices_smooth(wmOperatorType *ot)
1902 ot->name = "Smooth Vertex";
1903 ot->description = "Flatten angles of selected vertices";
1904 ot->idname = "MESH_OT_vertices_smooth";
1907 ot->exec = edbm_do_smooth_vertex_exec;
1908 ot->poll = ED_operator_editmesh;
1911 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1913 RNA_def_float(ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
1914 RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100);
1915 RNA_def_boolean(ot->srna, "xaxis", true, "X-Axis", "Smooth along the X axis");
1916 RNA_def_boolean(ot->srna, "yaxis", true, "Y-Axis", "Smooth along the Y axis");
1917 RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis");
1922 /* -------------------------------------------------------------------- */
1923 /** \name Laplacian Vertex Smooth Operator
1926 static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
1928 Object *obedit = CTX_data_edit_object(C);
1929 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1930 Mesh *me = obedit->data;
1931 bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
1932 bool usex = true, usey = true, usez = true, preserve_volume = true;
1934 float lambda_factor;
1935 float lambda_border;
1939 /* Check if select faces are triangles */
1940 BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) {
1941 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
1943 BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads");
1944 return OPERATOR_CANCELLED;
1949 /* mirror before smooth */
1950 if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
1951 EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
1954 repeat = RNA_int_get(op->ptr, "repeat");
1955 lambda_factor = RNA_float_get(op->ptr, "lambda_factor");
1956 lambda_border = RNA_float_get(op->ptr, "lambda_border");
1957 usex = RNA_boolean_get(op->ptr, "use_x");
1958 usey = RNA_boolean_get(op->ptr, "use_y");
1959 usez = RNA_boolean_get(op->ptr, "use_z");
1960 preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume");
1964 for (i = 0; i < repeat; i++) {
1967 "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
1968 BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume))
1970 return OPERATOR_CANCELLED;
1975 if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
1976 EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
1977 EDBM_verts_mirror_cache_end(em);
1980 EDBM_update_generic(em, true, false);
1982 return OPERATOR_FINISHED;
1985 void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
1988 ot->name = "Laplacian Smooth Vertex";
1989 ot->description = "Laplacian smooth of selected vertices";
1990 ot->idname = "MESH_OT_vertices_smooth_laplacian";
1993 ot->exec = edbm_do_smooth_laplacian_vertex_exec;
1994 ot->poll = ED_operator_editmesh;
1997 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1999 RNA_def_int(ot->srna, "repeat", 1, 1, 1000,
2000 "Number of iterations to smooth the mesh", "", 1, 200);
2001 RNA_def_float(ot->srna, "lambda_factor", 5e-5f, 1e-7f, 1000.0f,
2002 "Lambda factor", "", 1e-7f, 1000.0f);
2003 RNA_def_float(ot->srna, "lambda_border", 5e-5f, 1e-7f, 1000.0f,
2004 "Lambda factor in border", "", 1e-7f, 1000.0f);
2005 RNA_def_boolean(ot->srna, "use_x", true, "Smooth X Axis", "Smooth object along X axis");
2006 RNA_def_boolean(ot->srna, "use_y", true, "Smooth Y Axis", "Smooth object along Y axis");
2007 RNA_def_boolean(ot->srna, "use_z", true, "Smooth Z Axis", "Smooth object along Z axis");
2008 RNA_def_boolean(ot->srna, "preserve_volume", true, "Preserve Volume", "Apply volume preservation after smooth");
2013 /* -------------------------------------------------------------------- */
2014 /** \name Set Faces Smooth Shading Operator
2017 static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
2022 if (em == NULL) return;
2024 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2025 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2026 BM_elem_flag_set(efa, BM_ELEM_SMOOTH, smooth);
2031 static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
2033 Object *obedit = CTX_data_edit_object(C);
2034 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2036 mesh_set_smooth_faces(em, 1);
2038 EDBM_update_generic(em, false, false);
2040 return OPERATOR_FINISHED;
2043 void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
2046 ot->name = "Shade Smooth";
2047 ot->description = "Display faces smooth (using vertex normals)";
2048 ot->idname = "MESH_OT_faces_shade_smooth";
2051 ot->exec = edbm_faces_shade_smooth_exec;
2052 ot->poll = ED_operator_editmesh;
2055 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2060 /* -------------------------------------------------------------------- */
2061 /** \name Set Faces Flat Shading Operator
2064 static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
2066 Object *obedit = CTX_data_edit_object(C);
2067 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2069 mesh_set_smooth_faces(em, 0);
2071 EDBM_update_generic(em, false, false);
2073 return OPERATOR_FINISHED;
2076 void MESH_OT_faces_shade_flat(wmOperatorType *ot)
2079 ot->name = "Shade Flat";
2080 ot->description = "Display faces flat";
2081 ot->idname = "MESH_OT_faces_shade_flat";
2084 ot->exec = edbm_faces_shade_flat_exec;
2085 ot->poll = ED_operator_editmesh;
2088 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2093 /* -------------------------------------------------------------------- */
2094 /** \name UV/Color Rotate/Reverse Operator
2097 static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
2099 Object *ob = CTX_data_edit_object(C);
2100 BMEditMesh *em = BKE_editmesh_from_object(ob);
2103 /* get the direction from RNA */
2104 const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
2106 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2107 EDBM_op_init(em, &bmop, op, "rotate_uvs faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
2109 /* execute the operator */
2110 BMO_op_exec(em->bm, &bmop);
2112 /* finish the operator */
2113 if (!EDBM_op_finish(em, &bmop, op, true)) {
2114 return OPERATOR_CANCELLED;
2117 EDBM_update_generic(em, false, false);
2119 return OPERATOR_FINISHED;
2122 static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op)
2124 Object *ob = CTX_data_edit_object(C);
2125 BMEditMesh *em = BKE_editmesh_from_object(ob);
2128 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2129 EDBM_op_init(em, &bmop, op, "reverse_uvs faces=%hf", BM_ELEM_SELECT);
2131 /* execute the operator */
2132 BMO_op_exec(em->bm, &bmop);
2134 /* finish the operator */
2135 if (!EDBM_op_finish(em, &bmop, op, true)) {
2136 return OPERATOR_CANCELLED;
2139 EDBM_update_generic(em, false, false);
2141 return OPERATOR_FINISHED;
2144 static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
2146 Object *ob = CTX_data_edit_object(C);
2147 BMEditMesh *em = BKE_editmesh_from_object(ob);
2150 /* get the direction from RNA */
2151 const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
2153 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2154 EDBM_op_init(em, &bmop, op, "rotate_colors faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
2156 /* execute the operator */
2157 BMO_op_exec(em->bm, &bmop);
2159 /* finish the operator */
2160 if (!EDBM_op_finish(em, &bmop, op, true)) {
2161 return OPERATOR_CANCELLED;
2164 /* dependencies graph and notification stuff */
2165 EDBM_update_generic(em, false, false);
2167 return OPERATOR_FINISHED;
2171 static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
2173 Object *ob = CTX_data_edit_object(C);
2174 BMEditMesh *em = BKE_editmesh_from_object(ob);
2177 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2178 EDBM_op_init(em, &bmop, op, "reverse_colors faces=%hf", BM_ELEM_SELECT);
2180 /* execute the operator */
2181 BMO_op_exec(em->bm, &bmop);
2183 /* finish the operator */
2184 if (!EDBM_op_finish(em, &bmop, op, true)) {
2185 return OPERATOR_CANCELLED;
2188 EDBM_update_generic(em, false, false);
2190 return OPERATOR_FINISHED;
2193 void MESH_OT_uvs_rotate(wmOperatorType *ot)
2196 ot->name = "Rotate UVs";
2197 ot->idname = "MESH_OT_uvs_rotate";
2198 ot->description = "Rotate UV coordinates inside faces";
2201 ot->exec = edbm_rotate_uvs_exec;
2202 ot->poll = ED_operator_editmesh;
2205 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2208 RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
2211 void MESH_OT_uvs_reverse(wmOperatorType *ot)
2214 ot->name = "Reverse UVs";
2215 ot->idname = "MESH_OT_uvs_reverse";
2216 ot->description = "Flip direction of UV coordinates inside faces";
2219 ot->exec = edbm_reverse_uvs_exec;
2220 ot->poll = ED_operator_editmesh;
2223 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2226 //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around");
2229 void MESH_OT_colors_rotate(wmOperatorType *ot)
2232 ot->name = "Rotate Colors";
2233 ot->idname = "MESH_OT_colors_rotate";
2234 ot->description = "Rotate vertex colors inside faces";
2237 ot->exec = edbm_rotate_colors_exec;
2238 ot->poll = ED_operator_editmesh;
2241 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2244 RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
2247 void MESH_OT_colors_reverse(wmOperatorType *ot)
2250 ot->name = "Reverse Colors";
2251 ot->idname = "MESH_OT_colors_reverse";
2252 ot->description = "Flip direction of vertex colors inside faces";
2255 ot->exec = edbm_reverse_colors_exec;
2256 ot->poll = ED_operator_editmesh;
2259 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2262 //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around");
2267 /* -------------------------------------------------------------------- */
2268 /** \name Merge Vertices Operator
2272 MESH_MERGE_LAST = 1,
2273 MESH_MERGE_CENTER = 3,
2274 MESH_MERGE_CURSOR = 4,
2275 MESH_MERGE_COLLAPSE = 5,
2276 MESH_MERGE_FIRST = 6,
2279 static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use_uvmerge, wmOperator *wmop)
2282 BMEditSelection *ese;
2284 /* operator could be called directly from shortcut or python,
2285 * so do extra check for data here
2288 /* do sanity check in mergemenu in edit.c ?*/
2289 if (use_first == false) {
2290 if (!em->bm->selected.last || ((BMEditSelection *)em->bm->selected.last)->htype != BM_VERT)
2293 ese = em->bm->selected.last;
2294 mergevert = (BMVert *)ese->ele;
2297 if (!em->bm->selected.first || ((BMEditSelection *)em->bm->selected.first)->htype != BM_VERT)
2300 ese = em->bm->selected.first;
2301 mergevert = (BMVert *)ese->ele;
2304 if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT))
2308 if (!EDBM_op_callf(em, wmop, "pointmerge_facedata verts=%hv vert_snap=%e", BM_ELEM_SELECT, mergevert))
2312 if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, mergevert->co))
2318 static bool merge_target(
2319 BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
2320 const bool use_cursor, const bool use_uvmerge, wmOperator *wmop)
2324 float co[3], cent[3] = {0.0f, 0.0f, 0.0f};
2325 const float *vco = NULL;
2328 vco = ED_view3d_cursor3d_get(scene, v3d);
2329 copy_v3_v3(co, vco);
2330 invert_m4_m4(ob->imat, ob->obmat);
2331 mul_m4_v3(ob->imat, co);
2336 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2337 if (!BM_elem_flag_test(v, BM_ELEM_SELECT))
2339 add_v3_v3(cent, v->co);
2346 fac = 1.0f / (float)i;
2347 mul_v3_fl(cent, fac);
2348 copy_v3_v3(co, cent);
2356 if (!EDBM_op_callf(em, wmop, "average_vert_facedata verts=%hv", BM_ELEM_SELECT))
2360 if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, co))
2366 static int edbm_merge_exec(bContext *C, wmOperator *op)
2368 Scene *scene = CTX_data_scene(C);
2369 View3D *v3d = CTX_wm_view3d(C);
2370 Object *obedit = CTX_data_edit_object(C);
2371 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2372 const int type = RNA_enum_get(op->ptr, "type");
2373 const bool uvs = RNA_boolean_get(op->ptr, "uvs");
2377 case MESH_MERGE_CENTER:
2378 ok = merge_target(em, scene, v3d, obedit, false, uvs, op);
2380 case MESH_MERGE_CURSOR:
2381 ok = merge_target(em, scene, v3d, obedit, true, uvs, op);
2383 case MESH_MERGE_LAST:
2384 ok = merge_firstlast(em, false, uvs, op);
2386 case MESH_MERGE_FIRST:
2387 ok = merge_firstlast(em, true, uvs, op);
2389 case MESH_MERGE_COLLAPSE:
2390 ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs);
2398 return OPERATOR_CANCELLED;
2401 EDBM_update_generic(em, true, true);
2403 /* once collapsed, we can't have edge/face selection */
2404 if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
2405 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
2408 return OPERATOR_FINISHED;
2411 static const EnumPropertyItem merge_type_items[] = {
2412 {MESH_MERGE_FIRST, "FIRST", 0, "At First", ""},
2413 {MESH_MERGE_LAST, "LAST", 0, "At Last", ""},
2414 {MESH_MERGE_CENTER, "CENTER", 0, "At Center", ""},
2415 {MESH_MERGE_CURSOR, "CURSOR", 0, "At Cursor", ""},
2416 {MESH_MERGE_COLLAPSE, "COLLAPSE", 0, "Collapse", ""},
2417 {0, NULL, 0, NULL, NULL}
2420 static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
2423 EnumPropertyItem *item = NULL;
2426 if (!C) /* needed for docs */
2427 return merge_type_items;
2429 obedit = CTX_data_edit_object(C);
2430 if (obedit && obedit->type == OB_MESH) {
2431 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2433 if (em->selectmode & SCE_SELECT_VERTEX) {
2434 if (em->bm->selected.first && em->bm->selected.last &&
2435 ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT &&
2436 ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT)
2438 RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST);
2439 RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST);
2441 else if (em->bm->selected.first && ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) {
2442 RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST);
2444 else if (em->bm->selected.last && ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
2445 RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST);
2449 RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CENTER);
2450 RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CURSOR);
2451 RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_COLLAPSE);
2452 RNA_enum_item_end(&item, &totitem);
2462 void MESH_OT_merge(wmOperatorType *ot)
2466 ot->description = "Merge selected vertices";
2467 ot->idname = "MESH_OT_merge";
2470 ot->exec = edbm_merge_exec;
2471 ot->invoke = WM_menu_invoke;
2472 ot->poll = ED_operator_editmesh;
2475 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2478 ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, MESH_MERGE_CENTER, "Type", "Merge method to use");
2479 RNA_def_enum_funcs(ot->prop, merge_type_itemf);
2480 RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge");
2485 /* -------------------------------------------------------------------- */
2486 /** \name Remove Doubles Operator
2489 static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
2491 Object *obedit = CTX_data_edit_object(C);
2492 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2494 const float threshold = RNA_float_get(op->ptr, "threshold");
2495 const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected");
2496 const int totvert_orig = em->bm->totvert;
2500 /* avoid loosing selection state (select -> tags) */
2501 if (em->selectmode & SCE_SELECT_VERTEX) htype_select = BM_VERT;
2502 else if (em->selectmode & SCE_SELECT_EDGE) htype_select = BM_EDGE;
2503 else htype_select = BM_FACE;
2505 /* store selection as tags */
2506 BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT);
2509 if (use_unselected) {
2512 "automerge verts=%hv dist=%f",
2513 BM_ELEM_SELECT, threshold);
2514 BMO_op_exec(em->bm, &bmop);
2516 if (!EDBM_op_finish(em, &bmop, op, true)) {
2517 return OPERATOR_CANCELLED;
2523 "find_doubles verts=%hv dist=%f",
2524 BM_ELEM_SELECT, threshold);
2525 BMO_op_exec(em->bm, &bmop);
2527 if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) {
2528 BMO_op_finish(em->bm, &bmop);
2529 return OPERATOR_CANCELLED;
2532 if (!EDBM_op_finish(em, &bmop, op, true)) {
2533 return OPERATOR_CANCELLED;
2537 count = totvert_orig - em->bm->totvert;
2538 BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count);
2540 /* restore selection from tags */
2541 BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_SELECT, true, true, BM_ELEM_TAG);
2542 EDBM_selectmode_flush(em);
2544 EDBM_update_generic(em, true, true);
2546 return OPERATOR_FINISHED;
2549 void MESH_OT_remove_doubles(wmOperatorType *ot)
2552 ot->name = "Remove Doubles";
2553 ot->description = "Remove duplicate vertices";
2554 ot->idname = "MESH_OT_remove_doubles";
2557 ot->exec = edbm_remove_doubles_exec;
2558 ot->poll = ED_operator_editmesh;
2561 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2563 RNA_def_float_distance(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
2564 "Minimum distance between elements to merge", 1e-5f, 10.0f);
2565 RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices");
2570 /* -------------------------------------------------------------------- */
2571 /** \name Shape Key Propagate Operator
2574 /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
2575 static void shape_propagate(BMEditMesh *em, wmOperator *op)
2580 int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
2582 if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
2583 BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
2587 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2588 if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
2591 for (i = 0; i < totshape; i++) {
2592 co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
2593 copy_v3_v3(co, eve->co);
2598 //TAG Mesh Objects that share this data
2599 for (base = scene->base.first; base; base = base->next) {
2600 if (base->object && base->object->data == me) {
2601 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
2608 static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
2610 Object *obedit = CTX_data_edit_object(C);
2611 Mesh *me = obedit->data;
2612 BMEditMesh *em = me->edit_btmesh;
2614 shape_propagate(em, op);
2616 EDBM_update_generic(em, false, false);
2618 return OPERATOR_FINISHED;
2622 void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
2625 ot->name = "Shape Propagate";
2626 ot->description = "Apply selected vertex locations to all other shape keys";
2627 ot->idname = "MESH_OT_shape_propagate_to_all";
2630 ot->exec = edbm_shape_propagate_to_all_exec;
2631 ot->poll = ED_operator_editmesh;
2634 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2639 /* -------------------------------------------------------------------- */
2640 /** \name Blend from Shape Operator
2643 /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
2644 static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
2646 Object *obedit = CTX_data_edit_object(C);
2647 Mesh *me = obedit->data;
2649 KeyBlock *kb = NULL;
2650 BMEditMesh *em = me->edit_btmesh;
2656 const float blend = RNA_float_get(op->ptr, "blend");
2657 const int shape = RNA_enum_get(op->ptr, "shape");
2658 const bool use_add = RNA_boolean_get(op->ptr, "add");
2661 totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
2662 if (totshape == 0 || shape < 0 || shape >= totshape)
2663 return OPERATOR_CANCELLED;
2665 /* get shape key - needed for finding reference shape (for add mode only) */
2667 kb = BLI_findlink(&key->block, shape);
2670 /* perform blending on selected vertices*/
2671 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2672 if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
2675 /* get coordinates of shapekey we're blending from */
2676 sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
2677 copy_v3_v3(co, sco);
2680 /* in add mode, we add relative shape key offset */
2682 const float *rco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative);
2683 sub_v3_v3v3(co, co, rco);
2686 madd_v3_v3fl(eve->co, co, blend);
2689 /* in blend mode, we interpolate to the shape key */
2690 interp_v3_v3v3(eve->co, eve->co, co, blend);
2694 EDBM_update_generic(em, true, false);
2696 return OPERATOR_FINISHED;
2699 static const EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
2701 Object *obedit = CTX_data_edit_object(C);
2703 EnumPropertyItem *item = NULL;
2706 if ((obedit && obedit->type == OB_MESH) &&
2707 (em = BKE_editmesh_from_object(obedit)) &&
2708 CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY))
2710 EnumPropertyItem tmp = {0, "", 0, "", ""};
2713 for (a = 0; a < em->bm->vdata.totlayer; a++) {
2714 if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
2717 tmp.value = totitem;
2718 tmp.identifier = em->bm->vdata.layers[a].name;
2719 tmp.name = em->bm->vdata.layers[a].name;
2720 /* RNA_enum_item_add sets totitem itself! */
2721 RNA_enum_item_add(&item, &totitem, &tmp);
2725 RNA_enum_item_end(&item, &totitem);
2731 static void edbm_blend_from_shape_ui(bContext *C, wmOperator *op)
2733 uiLayout *layout = op->layout;
2735 Object *obedit = CTX_data_edit_object(C);
2736 Mesh *me = obedit->data;
2739 RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
2740 RNA_id_pointer_create((ID *)me->key, &ptr_key);
2742 uiItemPointerR(layout, &ptr, "shape", &ptr_key, "key_blocks", "", ICON_SHAPEKEY_DATA);
2743 uiItemR(layout, &ptr, "blend", 0, NULL, ICON_NONE);
2744 uiItemR(layout, &ptr, "add", 0, NULL, ICON_NONE);
2747 void MESH_OT_blend_from_shape(wmOperatorType *ot)
2752 ot->name = "Blend From Shape";
2753 ot->description = "Blend in shape from a shape key";
2754 ot->idname = "MESH_OT_blend_from_shape";
2757 ot->exec = edbm_blend_from_shape_exec;
2758 // ot->invoke = WM_operator_props_popup_call; /* disable because search popup closes too easily */
2759 ot->ui = edbm_blend_from_shape_ui;
2760 ot->poll = ED_operator_editmesh;
2763 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2766 prop = RNA_def_enum(ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending");
2767 RNA_def_enum_funcs(prop, shape_itemf);
2768 RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_NEVER_UNLINK);
2769 RNA_def_float(ot->srna, "blend", 1.0f, -1e3f, 1e3f, "Blend", "Blending factor", -2.0f, 2.0f);
2770 RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes");
2775 /* -------------------------------------------------------------------- */
2776 /** \name Solidify Mesh Operator
2779 static int edbm_solidify_exec(bContext *C, wmOperator *op)
2781 Object *obedit = CTX_data_edit_object(C);
2782 Mesh *me = obedit->data;
2783 BMEditMesh *em = me->edit_btmesh;
2787 const float thickness = RNA_float_get(op->ptr, "thickness");
2789 if (!EDBM_op_init(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) {
2790 return OPERATOR_CANCELLED;
2793 /* deselect only the faces in the region to be solidified (leave wire
2794 * edges and loose verts selected, as there will be no corresponding
2795 * geometry selected below) */
2796 BMO_slot_buffer_hflag_disable(bm, bmop.slots_in, "geom", BM_FACE, BM_ELEM_SELECT, true);
2798 /* run the solidify operator */
2799 BMO_op_exec(bm, &bmop);
2801 /* select the newly generated faces */
2802 BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
2804 if (!EDBM_op_finish(em, &bmop, op, true)) {
2805 return OPERATOR_CANCELLED;
2808 EDBM_update_generic(em, true, true);
2810 return OPERATOR_FINISHED;
2814 void MESH_OT_solidify(wmOperatorType *ot)
2818 ot->name = "Solidify";
2819 ot->description = "Create a solid skin by extruding, compensating for sharp angles";
2820 ot->idname = "MESH_OT_solidify";
2823 ot->exec = edbm_solidify_exec;
2824 ot->poll = ED_operator_editmesh;
2827 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2829 prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f);
2830 RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4);
2835 /* -------------------------------------------------------------------- */
2836 /** \name Knife Subdivide Operator
2839 /* ******************************************************************** */
2840 /* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
2843 * Currently mapped to KKey when in MeshEdit mode.
2845 * - Hit Shift K, Select Centers or Exact
2846 * - Hold LMB down to draw path, hit RETKEY.
2847 * - ESC cancels as expected.
2849 * Contributed by Robert Wenzlaff (Det. Thorn).
2852 * - non modal (no menu before cutting)
2853 * - exit on mouse release
2854 * - polygon/segment drawing can become handled by WM cb later
2856 * bmesh port version
2859 #define KNIFE_EXACT 1
2860 #define KNIFE_MIDPOINT 2
2861 #define KNIFE_MULTICUT 3
2863 static const EnumPropertyItem knife_items[] = {
2864 {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
2865 {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
2866 {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
2867 {0, NULL, 0, NULL, NULL}
2870 /* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */
2872 static float bm_edge_seg_isect(
2873 const float sco_a[2], const float sco_b[2],
2874 float (*mouse_path)[2], int len, char mode, int *isected)
2876 #define MAXSLOPE 100000
2877 float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max;
2878 float y2min, dist, lastdist = 0, xdiff2, xdiff1;
2879 float m1, b1, m2, b2, x21, x22, y21, y22, xi;
2880 float yi, x1min, x1max, y1max, y1min, perc = 0;
2881 float threshold = 0.0;
2884 //threshold = 0.000001; /* tolerance for vertex intersection */
2885 // XXX threshold = scene->toolsettings->select_thresh / 100;
2887 /* Get screen coords of verts */
2894 xdiff2 = (x22 - x21);
2896 m2 = (y22 - y21) / xdiff2;
2897 b2 = ((x22 * y21) - (x21 * y22)) / xdiff2;
2900 m2 = MAXSLOPE; /* Vertical slope */
2906 /* check for _exact_ vertex intersection first */
2907 if (mode != KNIFE_MULTICUT) {
2908 for (i = 0; i < len; i++) {
2914 x11 = mouse_path[i][0];
2915 y11 = mouse_path[i][1];
2917 x12 = mouse_path[i][0];
2918 y12 = mouse_path[i][1];
2921 if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) {
2927 else if ((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)) {
2935 /* now check for edge intersect (may produce vertex intersection as well) */
2936 for (i = 0; i < len; i++) {
2942 x11 = mouse_path[i][0];
2943 y11 = mouse_path[i][1];
2945 x12 = mouse_path[i][0];
2946 y12 = mouse_path[i][1];
2948 /* Perp. Distance from point to line */
2949 if (m2 != MAXSLOPE) dist = (y12 - m2 * x12 - b2); /* /sqrt(m2 * m2 + 1); Only looking for */
2950 /* change in sign. Skip extra math */
2951 else dist = x22 - x12;
2953 if (i == 0) lastdist = dist;
2955 /* if dist changes sign, and intersect point in edge's Bound Box */
2956 if ((lastdist * dist) <= 0) {
2957 xdiff1 = (x12 - x11); /* Equation of line between last 2 points */
2959 m1 = (y12 - y11) / xdiff1;
2960 b1 = ((x12 * y11) - (x11 * y12)) / xdiff1;
2966 x2max = max_ff(x21, x22) + 0.001f; /* prevent missed edges */
2967 x2min = min_ff(x21, x22) - 0.001f; /* due to round off error */
2968 y2max = max_ff(y21, y22) + 0.001f;
2969 y2min = min_ff(y21, y22) - 0.001f;
2971 /* Found an intersect, calc intersect point */
2972 if (m1 == m2) { /* co-incident lines */
2973 /* cut at 50% of overlap area */
2974 x1max = max_ff(x11, x12);
2975 x1min = min_ff(x11, x12);
2976 xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f;
2978 y1max = max_ff(y11, y12);
2979 y1min = min_ff(y11, y12);
2980 yi = (min_ff(y2max, y1max) + max_ff(y2min, y1min)) / 2.0f;
2982 else if (m2 == MAXSLOPE) {
2986 else if (m1 == MAXSLOPE) {
2991 xi = (b1 - b2) / (m2 - m1);
2992 yi = (b1 * m2 - m1 * b2) / (m2 - m1);
2995 /* Intersect inside bounding box of edge?*/
2996 if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) {
2997 /* test for vertex intersect that may be 'close enough'*/
2998 if (mode != KNIFE_MULTICUT) {
2999 if (xi <= (x21 + threshold) && xi >= (x21 - threshold)) {
3000 if (yi <= (y21 + threshold) && yi >= (y21 - threshold)) {
3006 if (xi <= (x22 + threshold) && xi >= (x22 - threshold)) {
3007 if (yi <= (y22 + threshold) && yi >= (y22 - threshold)) {
3014 if ((m2 <= 1.0f) && (m2 >= -1.0f)) perc = (xi - x21) / (x22 - x21);
3015 else perc = (yi - y21) / (y22 - y21); /* lower slope more accurate */
3016 //isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */
3026 #define ELE_EDGE_CUT 1
3028 static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
3030 Object *obedit = CTX_data_edit_object(C);
3031 BMEditMesh *em = BKE_editmesh_from_object(obedit);
3033 ARegion *ar = CTX_wm_region(C);
3039 int len = 0, isected, i;
3041 const short mode = RNA_int_get(op->ptr, "type");
3042 BMOpSlot *slot_edge_percents;
3045 float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2];
3047 /* edit-object needed for matrix, and ar->regiondata for projections to work */
3048 if (ELEM(NULL, obedit, ar, ar->regiondata))
3049 return OPERATOR_CANCELLED;
3051 if (bm->totvertsel < 2) {
3052 BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on");
3053 return OPERATOR_CANCELLED;
3056 len = RNA_collection_length(op->ptr, "path");
3059 BKE_report(op->reports, RPT_ERROR, "Mouse path too short");
3060 return OPERATOR_CANCELLED;
3063 mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__);
3065 /* get the cut curve */
3066 RNA_BEGIN (op->ptr, itemptr, "path")
3068 RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]);
3072 /* for ED_view3d_project_float_object */
3073 ED_view3d_init_mats_rv3d(obedit, ar->regiondata);
3075 /* TODO, investigate using index lookup for screen_vert_coords() rather then a hash table */
3077 /* the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer */
3078 screen_vert_coords = sco = MEM_mallocN(bm->totvert * sizeof(float) * 2, __func__);
3080 BM_ITER_MESH_INDEX (bv, &iter, bm, BM_VERTS_OF_MESH, i) {
3081 if (ED_view3d_project_float_object(ar, bv->co, *sco, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK) {
3082 copy_v2_fl(*sco, FLT_MAX); /* set error value */
3084 BM_elem_index_set(bv, i); /* set_inline */
3088 bm->elem_index_dirty &= ~BM_VERT; /* clear dirty flag */
3090 if (!EDBM_op_init(em, &bmop, op, "subdivide_edges")) {
3091 MEM_freeN(mouse_path);
3092 MEM_freeN(screen_vert_coords);
3093 return OPERATOR_CANCELLED;
3096 /* store percentage of edge cut for KNIFE_EXACT here.*/
3097 slot_edge_percents = BMO_slot_get(bmop.slots_in, "edge_percents");
3098 BM_ITER_MESH (be, &iter, bm, BM_EDGES_OF_MESH) {
3099 bool is_cut = false;
3100 if (BM_elem_flag_test(be, BM_ELEM_SELECT)) {
3101 const float *sco_a = screen_vert_coords[BM_elem_index_get(be->v1)];
3102 const float *sco_b = screen_vert_coords[BM_elem_index_get(be->v2)];
3104 /* check for error value (vert cant be projected) */
3105 if ((sco_a[0] != FLT_MAX) && (sco_b[0] != FLT_MAX)) {
3106 isect = bm_edge_seg_isect(sco_a, sco_b, mouse_path, len, mode, &isected);
3108 if (isect != 0.0f) {
3109 if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) {
3110 BMO_slot_map_float_insert(&bmop, slot_edge_percents, be, isect);
3116 BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
3120 /* free all allocs */
3121 MEM_freeN(screen_vert_coords);
3122 MEM_freeN(mouse_path);
3125 BMO_slot_buffer_from_enabled_flag(bm, &bmop, bmop.slots_in, "edges", BM_EDGE, ELE_EDGE_CUT);
3127 if (mode == KNIFE_MIDPOINT) numcuts = 1;
3128 BMO_slot_int_set(bmop.slots_in, "cuts", numcuts);
3130 BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_CORNER_STRAIGHT_CUT);
3131 BMO_slot_bool_set(bmop.slots_in, "use_single_edge", false);
3132 BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false);
3134 BMO_slot_float_set(bmop.slots_in, "radius", 0);
3136 BMO_op_exec(bm, &bmop);
3137 if (!EDBM_op_finish(em, &bmop, op, true)) {
3138 return OPERATOR_CANCELLED;
3141 EDBM_update_generic(em, true, true);
3143 return OPERATOR_FINISHED;
3148 void MESH_OT_knife_cut(wmOperatorType *ot)
3150 ot->name = "Knife Cut";
3151 ot->description = "Cut selected edges and faces into parts";
3152 ot->idname = "MESH_OT_knife_cut";
3154 ot->invoke = WM_gesture_lines_invoke;
3155 ot->modal = WM_gesture_lines_modal;
3156 ot->exec = edbm_knife_cut_exec;
3158 ot->poll = EDBM_view3d_poll;
3161 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3165 prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
3166 RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
3168 RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
3171 RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
3176 /* -------------------------------------------------------------------- */
3177 /** \name Separate Parts Operator
3181 MESH_SEPARATE_SELECTED = 0,
3182 MESH_SEPARATE_MATERIAL = 1,
3183 MESH_SEPARATE_LOOSE = 2,
3186 static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
3189 Object *obedit = base_old->object;
3192 bm_new = BM_mesh_create(
3193 &bm_mesh_allocsize_default,
3194 &((struct BMeshCreateParams){.use_toolflags = true,}));
3195 BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */
3197 CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
3198 CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH, CD_CALLOC, 0);
3199 CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
3200 CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
3202 CustomData_bmesh_init_pool(&bm_new->vdata, bm_mesh_allocsize_default.totvert, BM_VERT);
3203 CustomData_bmesh_init_pool(&bm_new->edata, bm_mesh_allocsize_default.totedge, BM_EDGE);
3204 CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP);
3205 CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE);
3207 base_new = ED_object_add_duplicate(bmain, scene, base_old, USER_DUP_MESH);
3208 /* DAG_relations_tag_update(bmain); */ /* normally would call directly after but in this case delay recalc */
3209 assign_matarar(bmain, base_new->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
3211 ED_base_object_select(base_new, BA_SELECT);
3213 BMO_op_callf(bm_old, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
3214 "duplicate geom=%hvef dest=%p", BM_ELEM_TAG, bm_new);
3215 BMO_op_callf(bm_old, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
3216 "delete geom=%hvef context=%i", BM_ELEM_TAG, DEL_FACES);
3218 /* deselect loose data - this used to get deleted,
3219 * we could de-select edges and verts only, but this turns out to be less complicated
3220 * since de-selecting all skips selection flushing logic */
3221 BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
3223 BM_mesh_normals_update(bm_new);
3225 BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
3227 BM_mesh_free(bm_new);
3228 ((Mesh *)base_new->object->data)->edit_btmesh = NULL;
3233 static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
3235 /* we may have tags from previous operators */
3236 BM_mesh_elem_hflag_disable_all(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, false);
3239 BM_mesh_elem_hflag_enable_test(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, false, BM_ELEM_SELECT);
3241 return (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL);
3244 /* flush a hflag to from verts to edges/faces */
3245 static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag)
3257 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
3258 if (BM_elem_flag_test(e->v1, hflag) &&
3259 BM_elem_flag_test(e->v2, hflag))
3261 BM_elem_flag_enable(e, hflag);
3264 BM_elem_flag_disable(e, hflag);
3267 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
3269 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
3271 if (!BM_elem_flag_test(l_iter->v, hflag)) {
3275 } while ((l_iter = l_iter->next) != l_first);
3277 BM_elem_flag_set(f, hflag, ok);
3282 * Sets an object to a single material. from one of its slots.
3284 * \note This could be used for split-by-material for non mesh types.
3285 * \note This could take material data from another object or args.
3287 static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const short mat_nr)
3289 ID *obdata = ob->data;
3291 Material ***matarar;
3292 const short *totcolp;
3294 totcolp = give_totcolp_id(obdata);
3295 matarar = give_matarar_id(obdata);
3297 if ((totcolp && matarar) == 0) {
3304 Material *ma_obdata;
3307 if (mat_nr < ob->totcol) {
3308 ma_ob = ob->mat[mat_nr];
3309 matbit = ob->matbits[mat_nr];
3316 if (mat_nr < *totcolp) {
3317 ma_obdata = (*matarar)[mat_nr];
3323 BKE_material_clear_id(bmain, obdata, true);
3324 BKE_material_resize_object(bmain, ob, 1, true);