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_depsgraph.h"
53 #include "BKE_report.h"
54 #include "BKE_texture.h"
56 #include "BKE_editmesh.h"
58 #include "BLF_translation.h"
60 #include "RNA_define.h"
61 #include "RNA_access.h"
62 #include "RNA_enum_types.h"
68 #include "ED_object.h"
69 #include "ED_screen.h"
70 #include "ED_transform.h"
71 #include "ED_uvedit.h"
72 #include "ED_view3d.h"
74 #include "RE_render_ext.h"
76 #include "UI_interface.h"
77 #include "UI_resources.h"
79 #include "mesh_intern.h" /* own include */
81 #define USE_FACE_CREATE_SEL_EXTEND
83 static int edbm_subdivide_exec(bContext *C, wmOperator *op)
85 Object *obedit = CTX_data_edit_object(C);
86 BMEditMesh *em = BKE_editmesh_from_object(obedit);
87 const int cuts = RNA_int_get(op->ptr, "number_cuts");
88 float smooth = 0.292f * RNA_float_get(op->ptr, "smoothness");
89 const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
90 const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
92 if (RNA_boolean_get(op->ptr, "quadtri") &&
93 RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT)
95 RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);
98 BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
99 smooth, SUBD_FALLOFF_ROOT, false,
100 fractal, along_normal,
102 SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
103 RNA_boolean_get(op->ptr, "quadtri"), true, false,
104 RNA_int_get(op->ptr, "seed"));
106 EDBM_update_generic(em, true, true);
108 return OPERATOR_FINISHED;
111 /* Note, these values must match delete_mesh() event values */
112 static EnumPropertyItem prop_mesh_cornervert_types[] = {
113 {SUBD_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
114 {SUBD_PATH, "PATH", 0, "Path", ""},
115 {SUBD_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
116 {SUBD_FAN, "FAN", 0, "Fan", ""},
117 {0, NULL, 0, NULL, NULL}
120 void MESH_OT_subdivide(wmOperatorType *ot)
125 ot->name = "Subdivide";
126 ot->description = "Subdivide selected edges";
127 ot->idname = "MESH_OT_subdivide";
130 ot->exec = edbm_subdivide_exec;
131 ot->poll = ED_operator_editmesh;
134 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
137 prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
138 /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
139 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
141 RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
143 RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
144 RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT,
145 "Quad Corner Type", "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)");
147 RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
148 RNA_def_float(ot->srna, "fractal_along_normal", 0.0f, 0.0f, 1.0f, "Along Normal", "Apply fractal displacement along normal only", 0.0f, 1.0f);
149 RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
152 /* -------------------------------------------------------------------- */
154 * (bridge code shares props)
157 struct EdgeRingOpSubdProps {
163 float profile_shape_factor;
167 static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_default)
169 /* Note, these values must match delete_mesh() event values */
170 static EnumPropertyItem prop_subd_edgering_types[] = {
171 {SUBD_RING_INTERP_LINEAR, "LINEAR", 0, "Linear", ""},
172 {SUBD_RING_INTERP_PATH, "PATH", 0, "Blend Path", ""},
173 {SUBD_RING_INTERP_SURF, "SURFACE", 0, "Blend Surface", ""},
174 {0, NULL, 0, NULL, NULL}
179 prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, INT_MAX, "Number of Cuts", "", 0, 64);
180 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
182 RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH,
183 "Interpolation", "Interpolation method");
185 RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, FLT_MAX,
186 "Smoothness", "Smoothness factor", 0.0f, 2.0f);
189 RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -FLT_MAX, FLT_MAX,
190 "Profile Factor", "", -2.0f, 2.0f);
192 prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE);
193 RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
194 RNA_def_property_enum_default(prop, PROP_SMOOTH);
195 RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile");
196 RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
199 static void mesh_operator_edgering_props_get(wmOperator *op, struct EdgeRingOpSubdProps *op_props)
201 op_props->interp_mode = RNA_enum_get(op->ptr, "interpolation");
202 op_props->cuts = RNA_int_get(op->ptr, "number_cuts");
203 op_props->smooth = RNA_float_get(op->ptr, "smoothness");
205 op_props->profile_shape = RNA_enum_get(op->ptr, "profile_shape");
206 op_props->profile_shape_factor = RNA_float_get(op->ptr, "profile_shape_factor");
209 static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op)
211 Object *obedit = CTX_data_edit_object(C);
212 BMEditMesh *em = BKE_editmesh_from_object(obedit);
213 struct EdgeRingOpSubdProps op_props;
215 mesh_operator_edgering_props_get(op, &op_props);
217 if (!EDBM_op_callf(em, op,
218 "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
219 "profile_shape=%i profile_shape_factor=%f",
220 BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth,
221 op_props.profile_shape, op_props.profile_shape_factor))
223 return OPERATOR_CANCELLED;
226 EDBM_update_generic(em, true, true);
228 return OPERATOR_FINISHED;
231 void MESH_OT_subdivide_edgering(wmOperatorType *ot)
234 ot->name = "Subdivide Edge-Ring";
235 ot->description = "";
236 ot->idname = "MESH_OT_subdivide_edgering";
239 ot->exec = edbm_subdivide_edge_ring_exec;
240 ot->poll = ED_operator_editmesh;
243 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
246 mesh_operator_edgering_props(ot, 10);
250 static int edbm_unsubdivide_exec(bContext *C, wmOperator *op)
252 Object *obedit = CTX_data_edit_object(C);
253 BMEditMesh *em = BKE_editmesh_from_object(obedit);
256 const int iterations = RNA_int_get(op->ptr, "iterations");
258 EDBM_op_init(em, &bmop, op,
259 "unsubdivide verts=%hv iterations=%i", BM_ELEM_SELECT, iterations);
261 BMO_op_exec(em->bm, &bmop);
263 if (!EDBM_op_finish(em, &bmop, op, true)) {
267 if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
268 EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); /* need to flush vert->face first */
270 EDBM_selectmode_flush(em);
272 EDBM_update_generic(em, true, true);
274 return OPERATOR_FINISHED;
277 void MESH_OT_unsubdivide(wmOperatorType *ot)
280 ot->name = "Un-Subdivide";
281 ot->description = "UnSubdivide selected edges & faces";
282 ot->idname = "MESH_OT_unsubdivide";
285 ot->exec = edbm_unsubdivide_exec;
286 ot->poll = ED_operator_editmesh;
289 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
292 RNA_def_int(ot->srna, "iterations", 2, 1, INT_MAX, "Iterations", "Number of times to unsubdivide", 1, 100);
295 void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
297 Object *obedit = em->ob;
301 ED_view3d_init_mats_rv3d(obedit, ar->regiondata);
303 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
304 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
305 float mval[2], co_proj[3], no_dummy[3];
307 if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
308 if (snapObjectsContext(C, mval, &dist_px_dummy, co_proj, no_dummy, SNAP_NOT_OBEDIT)) {
309 mul_v3_m4v3(eve->co, obedit->imat, co_proj);
317 /* Note, these values must match delete_mesh() event values */
318 static EnumPropertyItem prop_mesh_delete_types[] = {
319 {0, "VERT", 0, "Vertices", ""},
320 {1, "EDGE", 0, "Edges", ""},
321 {2, "FACE", 0, "Faces", ""},
322 {3, "EDGE_FACE", 0, "Only Edges & Faces", ""},
323 {4, "ONLY_FACE", 0, "Only Faces", ""},
324 {0, NULL, 0, NULL, NULL}
327 static int edbm_delete_exec(bContext *C, wmOperator *op)
329 Object *obedit = CTX_data_edit_object(C);
330 BMEditMesh *em = BKE_editmesh_from_object(obedit);
331 const int type = RNA_enum_get(op->ptr, "type");
334 if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
335 return OPERATOR_CANCELLED;
337 else if (type == 1) {
338 if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
339 return OPERATOR_CANCELLED;
341 else if (type == 2) {
342 if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
343 return OPERATOR_CANCELLED;
345 else if (type == 3) {
346 if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)) /* Edges and Faces */
347 return OPERATOR_CANCELLED;
349 else if (type == 4) {
350 //"Erase Only Faces";
351 if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i",
352 BM_ELEM_SELECT, DEL_ONLYFACES))
354 return OPERATOR_CANCELLED;
358 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
360 EDBM_update_generic(em, true, true);
362 return OPERATOR_FINISHED;
365 void MESH_OT_delete(wmOperatorType *ot)
369 ot->description = "Delete selected vertices, edges or faces";
370 ot->idname = "MESH_OT_delete";
373 ot->invoke = WM_menu_invoke;
374 ot->exec = edbm_delete_exec;
376 ot->poll = ED_operator_editmesh;
379 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
382 ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 0, "Type", "Method used for deleting mesh data");
385 static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
387 Object *obedit = CTX_data_edit_object(C);
388 BMEditMesh *em = BKE_editmesh_from_object(obedit);
390 if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
391 return OPERATOR_CANCELLED;
393 EDBM_update_generic(em, true, true);
395 return OPERATOR_FINISHED;
398 void MESH_OT_edge_collapse(wmOperatorType *ot)
401 ot->name = "Edge Collapse";
402 ot->description = "Collapse selected edges";
403 ot->idname = "MESH_OT_edge_collapse";
406 ot->exec = edbm_collapse_edge_exec;
407 ot->poll = ED_operator_editmesh;
410 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
413 static int edbm_add_edge_face__smooth_get(BMesh *bm)
418 unsigned int vote_on_smooth[2] = {0, 0};
420 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
421 if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
422 vote_on_smooth[BM_elem_flag_test_bool(e->l->f, BM_ELEM_SMOOTH)]++;
426 return (vote_on_smooth[0] < vote_on_smooth[1]);
429 #ifdef USE_FACE_CREATE_SEL_EXTEND
431 * Function used to get a fixed number of edges linked to a vertex that passes a test function.
432 * This is used so we can request all boundary edges connected to a vertex for eg.
434 static int edbm_add_edge_face_exec__vert_edge_lookup(
435 BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len,
436 bool (* func)(const BMEdge *))
441 BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
442 if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) {
443 if ((e_used == NULL) || (e_used != e_iter)) {
446 if (i >= e_arr_len) {
456 static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm)
461 if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) {
462 /* first look for 2 boundary edges */
465 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
466 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
475 ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_wire) == 2) &&
476 (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) ||
478 ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_boundary) == 2) &&
479 (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false))
482 BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v),
483 BM_edge_other_vert(ed_pair[1], v));
484 BM_edge_select_set(bm, ed_pair[0], true);
485 BM_edge_select_set(bm, ed_pair[1], true);
487 BM_edge_select_set(bm, e_other, true);
493 else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) {
494 /* first look for 2 boundary edges */
497 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
498 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
504 BMEdge *ed_pair_v1[2];
505 BMEdge *ed_pair_v2[2];
507 ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == 1) &&
508 (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == 1) &&
509 (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
510 (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
512 #if 1 /* better support mixed cases [#37203] */
513 ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == 1) &&
514 (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) &&
515 (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
516 (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
518 ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) &&
519 (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == 1) &&
520 (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
521 (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
524 ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) &&
525 (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) &&
526 (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
527 (BM_edge_share_face_check(e, ed_pair_v2[0]) == false))
530 BMVert *v1_other = BM_edge_other_vert(ed_pair_v1[0], e->v1);
531 BMVert *v2_other = BM_edge_other_vert(ed_pair_v2[0], e->v2);
532 BMEdge *e_other = (v1_other != v2_other) ? BM_edge_exists(v1_other, v2_other) : NULL;
533 BM_edge_select_set(bm, ed_pair_v1[0], true);
534 BM_edge_select_set(bm, ed_pair_v2[0], true);
536 BM_edge_select_set(bm, e_other, true);
545 static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_desel, BMFace *f)
547 /* now we need to find the edge that isnt connected to this element */
548 BM_select_history_clear(bm);
550 if (ele_desel->head.htype == BM_VERT) {
551 BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel);
552 BLI_assert(f->len == 3);
553 BM_face_select_set(bm, f, false);
554 BM_vert_select_set(bm, (BMVert *)ele_desel, false);
556 BM_edge_select_set(bm, l->next->e, true);
557 BM_select_history_store(bm, l->next->e);
560 BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel);
561 BLI_assert(f->len == 4 || f->len == 3);
562 BM_face_select_set(bm, f, false);
563 BM_edge_select_set(bm, (BMEdge *)ele_desel, false);
565 BM_edge_select_set(bm, l->next->next->e, true);
566 BM_select_history_store(bm, l->next->next->e);
569 BM_vert_select_set(bm, l->next->next->v, true);
570 BM_select_history_store(bm, l->next->next->v);
574 #endif /* USE_FACE_CREATE_SEL_EXTEND */
576 static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
579 Object *obedit = CTX_data_edit_object(C);
580 BMEditMesh *em = BKE_editmesh_from_object(obedit);
581 const short use_smooth = edbm_add_edge_face__smooth_get(em->bm);
582 const int totedge_orig = em->bm->totedge;
583 const int totface_orig = em->bm->totface;
584 /* when this is used to dissolve we could avoid this, but checking isnt too slow */
586 #ifdef USE_FACE_CREATE_SEL_EXTEND
588 BMFace *ele_desel_face;
590 /* be extra clever, figure out if a partial selection should be extended so we can create geometry
591 * with single vert or single edge selection */
592 ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm);
595 if (!EDBM_op_init(em, &bmop, op,
596 "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
597 BM_ELEM_SELECT, em->mat_nr, use_smooth))
599 return OPERATOR_CANCELLED;
602 BMO_op_exec(em->bm, &bmop);
604 /* cancel if nothing was done */
605 if ((totedge_orig == em->bm->totedge) &&
606 (totface_orig == em->bm->totface))
608 EDBM_op_finish(em, &bmop, op, true);
609 return OPERATOR_CANCELLED;
612 #ifdef USE_FACE_CREATE_SEL_EXTEND
613 /* normally we would want to leave the new geometry selected,
614 * but being able to press F many times to add geometry is too useful! */
616 (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) &&
617 (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out")))
619 edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face);
624 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
625 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
628 if (!EDBM_op_finish(em, &bmop, op, true)) {
629 return OPERATOR_CANCELLED;
632 EDBM_update_generic(em, true, true);
634 return OPERATOR_FINISHED;
637 void MESH_OT_edge_face_add(wmOperatorType *ot)
640 ot->name = "Make Edge/Face";
641 ot->description = "Add an edge or face to selected";
642 ot->idname = "MESH_OT_edge_face_add";
645 ot->exec = edbm_add_edge_face_exec;
646 ot->poll = ED_operator_editmesh;
649 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
652 /* ************************* SEAMS AND EDGES **************** */
654 static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
656 Scene *scene = CTX_data_scene(C);
657 Object *obedit = CTX_data_edit_object(C);
658 Mesh *me = ((Mesh *)obedit->data);
659 BMEditMesh *em = BKE_editmesh_from_object(obedit);
663 const bool clear = RNA_boolean_get(op->ptr, "clear");
665 /* auto-enable seams drawing */
667 me->drawflag |= ME_DRAWSEAMS;
671 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
672 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
675 BM_elem_flag_disable(eed, BM_ELEM_SEAM);
679 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
680 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
682 BM_elem_flag_enable(eed, BM_ELEM_SEAM);
686 ED_uvedit_live_unwrap(scene, obedit);
687 EDBM_update_generic(em, true, false);
689 return OPERATOR_FINISHED;
692 void MESH_OT_mark_seam(wmOperatorType *ot)
695 ot->name = "Mark Seam";
696 ot->idname = "MESH_OT_mark_seam";
697 ot->description = "(Un)mark selected edges as a seam";
700 ot->exec = edbm_mark_seam_exec;
701 ot->poll = ED_operator_editmesh;
704 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
706 RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
709 static int edbm_mark_sharp_exec(bContext *C, wmOperator *op)
711 Object *obedit = CTX_data_edit_object(C);
712 Mesh *me = ((Mesh *)obedit->data);
713 BMEditMesh *em = BKE_editmesh_from_object(obedit);
717 const bool clear = RNA_boolean_get(op->ptr, "clear");
719 /* auto-enable sharp edge drawing */
721 me->drawflag |= ME_DRAWSHARP;
725 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
726 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
729 BM_elem_flag_disable(eed, BM_ELEM_SMOOTH);
733 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
734 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
737 BM_elem_flag_enable(eed, BM_ELEM_SMOOTH);
741 EDBM_update_generic(em, true, false);
743 return OPERATOR_FINISHED;
746 void MESH_OT_mark_sharp(wmOperatorType *ot)
749 ot->name = "Mark Sharp";
750 ot->idname = "MESH_OT_mark_sharp";
751 ot->description = "(Un)mark selected edges as sharp";
754 ot->exec = edbm_mark_sharp_exec;
755 ot->poll = ED_operator_editmesh;
758 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
760 RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
764 static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
766 Object *obedit = CTX_data_edit_object(C);
767 BMEditMesh *em = BKE_editmesh_from_object(obedit);
770 const bool is_pair = (bm->totvertsel == 2);
774 if (!EDBM_op_init(em, &bmop, op, "connect_vert_pair verts=%hv", BM_ELEM_SELECT)) {
775 return OPERATOR_CANCELLED;
779 if (!EDBM_op_init(em, &bmop, op, "connect_verts verts=%hv", BM_ELEM_SELECT)) {
780 return OPERATOR_CANCELLED;
784 BMO_op_exec(bm, &bmop);
785 len = BMO_slot_get(bmop.slots_out, "edges.out")->len;
789 /* new verts have been added, we have to select the edges, not just flush */
790 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
794 if (!EDBM_op_finish(em, &bmop, op, true)) {
795 return OPERATOR_CANCELLED;
798 EDBM_selectmode_flush(em); /* so newly created edges get the selection state from the vertex */
800 EDBM_update_generic(em, true, true);
802 return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
806 void MESH_OT_vert_connect(wmOperatorType *ot)
809 ot->name = "Vertex Connect";
810 ot->idname = "MESH_OT_vert_connect";
811 ot->description = "Connect 2 vertices of a face by an edge, splitting the face in two";
814 ot->exec = edbm_vert_connect_exec;
815 ot->poll = ED_operator_editmesh;
818 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
822 static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
824 Object *obedit = CTX_data_edit_object(C);
825 BMEditMesh *em = BKE_editmesh_from_object(obedit);
827 const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
829 if (!EDBM_op_call_and_selectf(
832 "connect_verts_nonplanar faces=%hf angle_limit=%f",
833 BM_ELEM_SELECT, angle_limit))
835 return OPERATOR_CANCELLED;
839 EDBM_update_generic(em, true, true);
840 return OPERATOR_FINISHED;
843 void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot)
848 ot->name = "Split Non-Planar Faces";
849 ot->idname = "MESH_OT_vert_connect_nonplanar";
850 ot->description = "Split non-planar faces that exceed the angle threshold";
853 ot->exec = edbm_vert_connect_nonplaner_exec;
854 ot->poll = ED_operator_editmesh;
857 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
860 prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
861 "Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f));
862 RNA_def_property_float_default(prop, DEG2RADF(5.0f));
866 static int edbm_edge_split_exec(bContext *C, wmOperator *op)
868 Object *obedit = CTX_data_edit_object(C);
869 BMEditMesh *em = BKE_editmesh_from_object(obedit);
871 if (!EDBM_op_call_and_selectf(
874 "split_edges edges=%he",
877 return OPERATOR_CANCELLED;
880 if (em->selectmode == SCE_SELECT_FACE) {
881 EDBM_select_flush(em);
884 EDBM_update_generic(em, true, true);
886 return OPERATOR_FINISHED;
889 void MESH_OT_edge_split(wmOperatorType *ot)
892 ot->name = "Edge Split";
893 ot->idname = "MESH_OT_edge_split";
894 ot->description = "Split selected edges so that each neighbor face gets its own copy";
897 ot->exec = edbm_edge_split_exec;
898 ot->poll = ED_operator_editmesh;
901 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
904 /****************** add duplicate operator ***************/
906 static int edbm_duplicate_exec(bContext *C, wmOperator *op)
908 Object *ob = CTX_data_edit_object(C);
909 BMEditMesh *em = BKE_editmesh_from_object(ob);
912 ListBase bm_selected_store = {NULL, NULL};
914 /* de-select all would clear otherwise */
915 SWAP(ListBase, bm->selected, bm_selected_store);
917 EDBM_op_init(em, &bmop, op, "duplicate geom=%hvef", BM_ELEM_SELECT);
919 BMO_op_exec(bm, &bmop);
920 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
922 BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
924 /* rebuild editselection */
925 bm->selected = bm_selected_store;
927 if (bm->selected.first) {
928 BMOpSlot *slot_vert_map_out = BMO_slot_get(bmop.slots_out, "vert_map.out");
929 BMOpSlot *slot_edge_map_out = BMO_slot_get(bmop.slots_out, "edge_map.out");
930 BMOpSlot *slot_face_map_out = BMO_slot_get(bmop.slots_out, "face_map.out");
932 BMO_mesh_selected_remap(bm, slot_vert_map_out, slot_edge_map_out, slot_face_map_out);
935 if (!EDBM_op_finish(em, &bmop, op, true)) {
936 return OPERATOR_CANCELLED;
939 EDBM_update_generic(em, true, true);
941 return OPERATOR_FINISHED;
944 static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
947 edbm_duplicate_exec(C, op);
950 return OPERATOR_FINISHED;
953 void MESH_OT_duplicate(wmOperatorType *ot)
956 ot->name = "Duplicate";
957 ot->description = "Duplicate selected vertices, edges or faces";
958 ot->idname = "MESH_OT_duplicate";
961 ot->invoke = edbm_duplicate_invoke;
962 ot->exec = edbm_duplicate_exec;
964 ot->poll = ED_operator_editmesh;
966 /* to give to transform */
967 RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
970 static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
972 Object *obedit = CTX_data_edit_object(C);
973 BMEditMesh *em = BKE_editmesh_from_object(obedit);
975 if (!EDBM_op_callf(em, op, "reverse_faces faces=%hf", BM_ELEM_SELECT))
976 return OPERATOR_CANCELLED;
978 EDBM_update_generic(em, true, false);
980 return OPERATOR_FINISHED;
983 void MESH_OT_flip_normals(wmOperatorType *ot)
986 ot->name = "Flip Normals";
987 ot->description = "Flip the direction of selected faces' normals (and of their vertices)";
988 ot->idname = "MESH_OT_flip_normals";
991 ot->exec = edbm_flip_normals_exec;
992 ot->poll = ED_operator_editmesh;
995 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
998 /* only accepts 1 selected edge, or 2 selected faces */
999 static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
1001 Object *obedit = CTX_data_edit_object(C);
1002 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1006 const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
1009 if (em->bm->totedgesel == 0) {
1010 BKE_report(op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about");
1011 return OPERATOR_CANCELLED;
1014 /* first see if we have two adjacent faces */
1015 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1016 BM_elem_flag_disable(eed, BM_ELEM_TAG);
1017 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1019 if (BM_edge_face_pair(eed, &fa, &fb)) {
1020 /* if both faces are selected we rotate between them,
1021 * otherwise - rotate between 2 unselected - but not mixed */
1022 if (BM_elem_flag_test(fa, BM_ELEM_SELECT) == BM_elem_flag_test(fb, BM_ELEM_SELECT)) {
1023 BM_elem_flag_enable(eed, BM_ELEM_TAG);
1030 /* ok, we don't have two adjacent faces, but we do have two selected ones.
1031 * that's an error condition.*/
1033 BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated");
1034 return OPERATOR_CANCELLED;
1037 EDBM_op_init(em, &bmop, op, "rotate_edges edges=%he use_ccw=%b", BM_ELEM_TAG, use_ccw);
1039 /* avoids leaving old verts selected which can be a problem running multiple times,
1040 * since this means the edges become selected around the face which then attempt to rotate */
1041 BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "edges", BM_EDGE, BM_ELEM_SELECT, true);
1043 BMO_op_exec(em->bm, &bmop);
1044 /* edges may rotate into hidden vertices, if this does _not_ run we get an ilogical state */
1045 BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true);
1046 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
1047 EDBM_selectmode_flush(em);
1049 if (!EDBM_op_finish(em, &bmop, op, true)) {
1050 return OPERATOR_CANCELLED;
1053 EDBM_update_generic(em, true, true);
1055 return OPERATOR_FINISHED;
1058 void MESH_OT_edge_rotate(wmOperatorType *ot)
1061 ot->name = "Rotate Selected Edge";
1062 ot->description = "Rotate selected edge or adjoining faces";
1063 ot->idname = "MESH_OT_edge_rotate";
1066 ot->exec = edbm_edge_rotate_selected_exec;
1067 ot->poll = ED_operator_editmesh;
1070 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1073 RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
1077 static int edbm_hide_exec(bContext *C, wmOperator *op)
1079 Object *obedit = CTX_data_edit_object(C);
1080 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1082 EDBM_mesh_hide(em, RNA_boolean_get(op->ptr, "unselected"));
1084 EDBM_update_generic(em, true, false);
1086 return OPERATOR_FINISHED;
1089 void MESH_OT_hide(wmOperatorType *ot)
1092 ot->name = "Hide Selection";
1093 ot->idname = "MESH_OT_hide";
1094 ot->description = "Hide (un)selected vertices, edges or faces";
1097 ot->exec = edbm_hide_exec;
1098 ot->poll = ED_operator_editmesh;
1101 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1104 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1107 static int edbm_reveal_exec(bContext *C, wmOperator *UNUSED(op))
1109 Object *obedit = CTX_data_edit_object(C);
1110 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1112 EDBM_mesh_reveal(em);
1114 EDBM_update_generic(em, true, false);
1116 return OPERATOR_FINISHED;
1119 void MESH_OT_reveal(wmOperatorType *ot)
1122 ot->name = "Reveal Hidden";
1123 ot->idname = "MESH_OT_reveal";
1124 ot->description = "Reveal all hidden vertices, edges and faces";
1127 ot->exec = edbm_reveal_exec;
1128 ot->poll = ED_operator_editmesh;
1131 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1134 static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
1136 Object *obedit = CTX_data_edit_object(C);
1137 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1139 /* doflip has to do with bmesh_rationalize_normals, it's an internal
1141 if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT))
1142 return OPERATOR_CANCELLED;
1144 if (RNA_boolean_get(op->ptr, "inside"))
1145 EDBM_op_callf(em, op, "reverse_faces faces=%hf", BM_ELEM_SELECT);
1147 EDBM_update_generic(em, true, false);
1149 return OPERATOR_FINISHED;
1152 void MESH_OT_normals_make_consistent(wmOperatorType *ot)
1155 ot->name = "Make Normals Consistent";
1156 ot->description = "Make face and vertex normals point either outside or inside the mesh";
1157 ot->idname = "MESH_OT_normals_make_consistent";
1160 ot->exec = edbm_normals_make_consistent_exec;
1161 ot->poll = ED_operator_editmesh;
1164 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1166 RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
1171 static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
1173 Object *obedit = CTX_data_edit_object(C);
1174 Mesh *me = obedit->data;
1175 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1177 int mirrx = false, mirry = false, mirrz = false;
1179 float clip_dist = 0.0f;
1180 bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
1182 const bool xaxis = RNA_boolean_get(op->ptr, "xaxis");
1183 const bool yaxis = RNA_boolean_get(op->ptr, "yaxis");
1184 const bool zaxis = RNA_boolean_get(op->ptr, "zaxis");
1186 /* mirror before smooth */
1187 if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
1188 EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
1191 /* if there is a mirror modifier with clipping, flag the verts that
1192 * are within tolerance of the plane(s) of reflection
1194 for (md = obedit->modifiers.first; md; md = md->next) {
1195 if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
1196 MirrorModifierData *mmd = (MirrorModifierData *)md;
1198 if (mmd->flag & MOD_MIR_CLIPPING) {
1199 if (mmd->flag & MOD_MIR_AXIS_X)
1201 if (mmd->flag & MOD_MIR_AXIS_Y)
1203 if (mmd->flag & MOD_MIR_AXIS_Z)
1206 clip_dist = mmd->tolerance;
1211 repeat = RNA_int_get(op->ptr, "repeat");
1215 for (i = 0; i < repeat; i++) {
1216 if (!EDBM_op_callf(em, op,
1217 "smooth_vert verts=%hv mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b clip_dist=%f "
1218 "use_axis_x=%b use_axis_y=%b use_axis_z=%b",
1219 BM_ELEM_SELECT, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
1221 return OPERATOR_CANCELLED;
1226 if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
1227 EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
1228 EDBM_verts_mirror_cache_end(em);
1231 EDBM_update_generic(em, true, false);
1233 return OPERATOR_FINISHED;
1236 void MESH_OT_vertices_smooth(wmOperatorType *ot)
1239 ot->name = "Smooth Vertex";
1240 ot->description = "Flatten angles of selected vertices";
1241 ot->idname = "MESH_OT_vertices_smooth";
1244 ot->exec = edbm_do_smooth_vertex_exec;
1245 ot->poll = ED_operator_editmesh;
1248 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1250 RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Number of times to smooth the mesh", "", 1, 100);
1251 RNA_def_boolean(ot->srna, "xaxis", 1, "X-Axis", "Smooth along the X axis");
1252 RNA_def_boolean(ot->srna, "yaxis", 1, "Y-Axis", "Smooth along the Y axis");
1253 RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis");
1256 static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
1258 Object *obedit = CTX_data_edit_object(C);
1259 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1260 Mesh *me = obedit->data;
1261 bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
1262 int usex = true, usey = true, usez = true, preserve_volume = true;
1264 float lambda_factor;
1265 float lambda_border;
1269 /* Check if select faces are triangles */
1270 BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) {
1271 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
1273 BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads");
1274 return OPERATOR_CANCELLED;
1279 /* mirror before smooth */
1280 if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
1281 EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
1284 repeat = RNA_int_get(op->ptr, "repeat");
1285 lambda_factor = RNA_float_get(op->ptr, "lambda_factor");
1286 lambda_border = RNA_float_get(op->ptr, "lambda_border");
1287 usex = RNA_boolean_get(op->ptr, "use_x");
1288 usey = RNA_boolean_get(op->ptr, "use_y");
1289 usez = RNA_boolean_get(op->ptr, "use_z");
1290 preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume");
1294 for (i = 0; i < repeat; i++) {
1295 if (!EDBM_op_callf(em, op,
1296 "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
1297 BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume))
1299 return OPERATOR_CANCELLED;
1304 if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
1305 EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
1306 EDBM_verts_mirror_cache_end(em);
1309 EDBM_update_generic(em, true, false);
1311 return OPERATOR_FINISHED;
1314 void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
1317 ot->name = "Laplacian Smooth Vertex";
1318 ot->description = "Laplacian smooth of selected vertices";
1319 ot->idname = "MESH_OT_vertices_smooth_laplacian";
1322 ot->exec = edbm_do_smooth_laplacian_vertex_exec;
1323 ot->poll = ED_operator_editmesh;
1326 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1328 RNA_def_int(ot->srna, "repeat", 1, 1, 200,
1329 "Number of iterations to smooth the mesh", "", 1, 200);
1330 RNA_def_float(ot->srna, "lambda_factor", 0.00005f, 0.0000001f, 1000.0f,
1331 "Lambda factor", "", 0.0000001f, 1000.0f);
1332 RNA_def_float(ot->srna, "lambda_border", 0.00005f, 0.0000001f, 1000.0f,
1333 "Lambda factor in border", "", 0.0000001f, 1000.0f);
1334 RNA_def_boolean(ot->srna, "use_x", 1, "Smooth X Axis", "Smooth object along X axis");
1335 RNA_def_boolean(ot->srna, "use_y", 1, "Smooth Y Axis", "Smooth object along Y axis");
1336 RNA_def_boolean(ot->srna, "use_z", 1, "Smooth Z Axis", "Smooth object along Z axis");
1337 RNA_def_boolean(ot->srna, "preserve_volume", 1, "Preserve Volume", "Apply volume preservation after smooth");
1340 /********************** Smooth/Solid Operators *************************/
1342 static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
1347 if (em == NULL) return;
1349 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1350 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1351 BM_elem_flag_set(efa, BM_ELEM_SMOOTH, smooth);
1356 static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
1358 Object *obedit = CTX_data_edit_object(C);
1359 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1361 mesh_set_smooth_faces(em, 1);
1363 EDBM_update_generic(em, false, false);
1365 return OPERATOR_FINISHED;
1368 void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
1371 ot->name = "Shade Smooth";
1372 ot->description = "Display faces smooth (using vertex normals)";
1373 ot->idname = "MESH_OT_faces_shade_smooth";
1376 ot->exec = edbm_faces_shade_smooth_exec;
1377 ot->poll = ED_operator_editmesh;
1380 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1383 static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
1385 Object *obedit = CTX_data_edit_object(C);
1386 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1388 mesh_set_smooth_faces(em, 0);
1390 EDBM_update_generic(em, false, false);
1392 return OPERATOR_FINISHED;
1395 void MESH_OT_faces_shade_flat(wmOperatorType *ot)
1398 ot->name = "Shade Flat";
1399 ot->description = "Display faces flat";
1400 ot->idname = "MESH_OT_faces_shade_flat";
1403 ot->exec = edbm_faces_shade_flat_exec;
1404 ot->poll = ED_operator_editmesh;
1407 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1411 /********************** UV/Color Operators *************************/
1413 static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
1415 Object *ob = CTX_data_edit_object(C);
1416 BMEditMesh *em = BKE_editmesh_from_object(ob);
1419 /* get the direction from RNA */
1420 const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
1422 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1423 EDBM_op_init(em, &bmop, op, "rotate_uvs faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
1425 /* execute the operator */
1426 BMO_op_exec(em->bm, &bmop);
1428 /* finish the operator */
1429 if (!EDBM_op_finish(em, &bmop, op, true)) {
1430 return OPERATOR_CANCELLED;
1433 EDBM_update_generic(em, false, false);
1435 return OPERATOR_FINISHED;
1438 static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op)
1440 Object *ob = CTX_data_edit_object(C);
1441 BMEditMesh *em = BKE_editmesh_from_object(ob);
1444 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1445 EDBM_op_init(em, &bmop, op, "reverse_uvs faces=%hf", BM_ELEM_SELECT);
1447 /* execute the operator */
1448 BMO_op_exec(em->bm, &bmop);
1450 /* finish the operator */
1451 if (!EDBM_op_finish(em, &bmop, op, true)) {
1452 return OPERATOR_CANCELLED;
1455 EDBM_update_generic(em, false, false);
1457 return OPERATOR_FINISHED;
1460 static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
1462 Object *ob = CTX_data_edit_object(C);
1463 BMEditMesh *em = BKE_editmesh_from_object(ob);
1466 /* get the direction from RNA */
1467 const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
1469 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1470 EDBM_op_init(em, &bmop, op, "rotate_colors faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
1472 /* execute the operator */
1473 BMO_op_exec(em->bm, &bmop);
1475 /* finish the operator */
1476 if (!EDBM_op_finish(em, &bmop, op, true)) {
1477 return OPERATOR_CANCELLED;
1480 /* dependencies graph and notification stuff */
1481 EDBM_update_generic(em, false, false);
1483 return OPERATOR_FINISHED;
1487 static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
1489 Object *ob = CTX_data_edit_object(C);
1490 BMEditMesh *em = BKE_editmesh_from_object(ob);
1493 /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1494 EDBM_op_init(em, &bmop, op, "reverse_colors faces=%hf", BM_ELEM_SELECT);
1496 /* execute the operator */
1497 BMO_op_exec(em->bm, &bmop);
1499 /* finish the operator */
1500 if (!EDBM_op_finish(em, &bmop, op, true)) {
1501 return OPERATOR_CANCELLED;
1504 EDBM_update_generic(em, false, false);
1506 return OPERATOR_FINISHED;
1509 void MESH_OT_uvs_rotate(wmOperatorType *ot)
1512 ot->name = "Rotate UVs";
1513 ot->idname = "MESH_OT_uvs_rotate";
1514 ot->description = "Rotate UV coordinates inside faces";
1517 ot->exec = edbm_rotate_uvs_exec;
1518 ot->poll = ED_operator_editmesh;
1521 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1524 RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
1527 void MESH_OT_uvs_reverse(wmOperatorType *ot)
1530 ot->name = "Reverse UVs";
1531 ot->idname = "MESH_OT_uvs_reverse";
1532 ot->description = "Flip direction of UV coordinates inside faces";
1535 ot->exec = edbm_reverse_uvs_exec;
1536 ot->poll = ED_operator_editmesh;
1539 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1542 //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around");
1545 void MESH_OT_colors_rotate(wmOperatorType *ot)
1548 ot->name = "Rotate Colors";
1549 ot->idname = "MESH_OT_colors_rotate";
1550 ot->description = "Rotate vertex colors inside faces";
1553 ot->exec = edbm_rotate_colors_exec;
1554 ot->poll = ED_operator_editmesh;
1557 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1560 RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
1563 void MESH_OT_colors_reverse(wmOperatorType *ot)
1566 ot->name = "Reverse Colors";
1567 ot->idname = "MESH_OT_colors_reverse";
1568 ot->description = "Flip direction of vertex colors inside faces";
1571 ot->exec = edbm_reverse_colors_exec;
1572 ot->poll = ED_operator_editmesh;
1575 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1578 //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around");
1582 static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use_uvmerge, wmOperator *wmop)
1585 BMEditSelection *ese;
1587 /* operator could be called directly from shortcut or python,
1588 * so do extra check for data here
1591 /* do sanity check in mergemenu in edit.c ?*/
1592 if (use_first == false) {
1593 if (!em->bm->selected.last || ((BMEditSelection *)em->bm->selected.last)->htype != BM_VERT)
1596 ese = em->bm->selected.last;
1597 mergevert = (BMVert *)ese->ele;
1600 if (!em->bm->selected.first || ((BMEditSelection *)em->bm->selected.first)->htype != BM_VERT)
1603 ese = em->bm->selected.first;
1604 mergevert = (BMVert *)ese->ele;
1607 if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT))
1611 if (!EDBM_op_callf(em, wmop, "pointmerge_facedata verts=%hv vert_snap=%e", BM_ELEM_SELECT, mergevert))
1615 if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, mergevert->co))
1621 static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
1622 const bool use_cursor, const bool use_uvmerge, wmOperator *wmop)
1626 float co[3], cent[3] = {0.0f, 0.0f, 0.0f};
1627 const float *vco = NULL;
1630 vco = ED_view3d_cursor3d_get(scene, v3d);
1631 copy_v3_v3(co, vco);
1632 mul_m4_v3(ob->imat, co);
1637 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
1638 if (!BM_elem_flag_test(v, BM_ELEM_SELECT))
1640 add_v3_v3(cent, v->co);
1647 fac = 1.0f / (float)i;
1648 mul_v3_fl(cent, fac);
1649 copy_v3_v3(co, cent);
1657 if (!EDBM_op_callf(em, wmop, "average_vert_facedata verts=%hv", BM_ELEM_SELECT))
1661 if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, co))
1667 static int edbm_merge_exec(bContext *C, wmOperator *op)
1669 Scene *scene = CTX_data_scene(C);
1670 View3D *v3d = CTX_wm_view3d(C);
1671 Object *obedit = CTX_data_edit_object(C);
1672 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1673 const int type = RNA_enum_get(op->ptr, "type");
1674 const bool uvs = RNA_boolean_get(op->ptr, "uvs");
1679 ok = merge_target(em, scene, v3d, obedit, false, uvs, op);
1682 ok = merge_target(em, scene, v3d, obedit, true, uvs, op);
1685 ok = merge_firstlast(em, false, uvs, op);
1688 ok = merge_firstlast(em, true, uvs, op);
1692 if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
1701 return OPERATOR_CANCELLED;
1704 EDBM_update_generic(em, true, true);
1706 return OPERATOR_FINISHED;
1709 static EnumPropertyItem merge_type_items[] = {
1710 {6, "FIRST", 0, "At First", ""},
1711 {1, "LAST", 0, "At Last", ""},
1712 {3, "CENTER", 0, "At Center", ""},
1713 {4, "CURSOR", 0, "At Cursor", ""},
1714 {5, "COLLAPSE", 0, "Collapse", ""},
1715 {0, NULL, 0, NULL, NULL}
1718 static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
1721 EnumPropertyItem *item = NULL;
1724 if (!C) /* needed for docs */
1725 return merge_type_items;
1727 obedit = CTX_data_edit_object(C);
1728 if (obedit && obedit->type == OB_MESH) {
1729 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1731 if (em->selectmode & SCE_SELECT_VERTEX) {
1732 if (em->bm->selected.first && em->bm->selected.last &&
1733 ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT &&
1734 ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT)
1736 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
1737 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
1739 else if (em->bm->selected.first && ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) {
1740 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
1742 else if (em->bm->selected.last && ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
1743 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
1747 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
1748 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
1749 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
1750 RNA_enum_item_end(&item, &totitem);
1760 void MESH_OT_merge(wmOperatorType *ot)
1764 ot->description = "Merge selected vertices";
1765 ot->idname = "MESH_OT_merge";
1768 ot->exec = edbm_merge_exec;
1769 ot->invoke = WM_menu_invoke;
1770 ot->poll = ED_operator_editmesh;
1773 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1776 ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use");
1777 RNA_def_enum_funcs(ot->prop, merge_type_itemf);
1778 RNA_def_boolean(ot->srna, "uvs", 0, "UVs", "Move UVs according to merge");
1782 static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
1784 Object *obedit = CTX_data_edit_object(C);
1785 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1787 const float threshold = RNA_float_get(op->ptr, "threshold");
1788 const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected");
1789 const int totvert_orig = em->bm->totvert;
1792 if (use_unselected) {
1793 EDBM_op_init(em, &bmop, op,
1794 "automerge verts=%hv dist=%f",
1795 BM_ELEM_SELECT, threshold);
1796 BMO_op_exec(em->bm, &bmop);
1798 if (!EDBM_op_finish(em, &bmop, op, true)) {
1799 return OPERATOR_CANCELLED;
1803 EDBM_op_init(em, &bmop, op,
1804 "find_doubles verts=%hv dist=%f",
1805 BM_ELEM_SELECT, threshold);
1806 BMO_op_exec(em->bm, &bmop);
1808 if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) {
1809 BMO_op_finish(em->bm, &bmop);
1810 return OPERATOR_CANCELLED;
1813 if (!EDBM_op_finish(em, &bmop, op, true)) {
1814 return OPERATOR_CANCELLED;
1818 count = totvert_orig - em->bm->totvert;
1819 BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count);
1821 EDBM_update_generic(em, true, true);
1823 return OPERATOR_FINISHED;
1826 void MESH_OT_remove_doubles(wmOperatorType *ot)
1829 ot->name = "Remove Doubles";
1830 ot->description = "Remove duplicate vertices";
1831 ot->idname = "MESH_OT_remove_doubles";
1834 ot->exec = edbm_remove_doubles_exec;
1835 ot->poll = ED_operator_editmesh;
1838 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1840 RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Merge Distance",
1841 "Minimum distance between elements to merge", 0.00001, 10.0);
1842 RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
1846 /************************ Shape Operators *************************/
1848 /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
1849 static void shape_propagate(BMEditMesh *em, wmOperator *op)
1854 int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
1856 if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
1857 BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
1861 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1862 if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
1865 for (i = 0; i < totshape; i++) {
1866 co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
1867 copy_v3_v3(co, eve->co);
1872 //TAG Mesh Objects that share this data
1873 for (base = scene->base.first; base; base = base->next) {
1874 if (base->object && base->object->data == me) {
1875 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
1882 static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
1884 Object *obedit = CTX_data_edit_object(C);
1885 Mesh *me = obedit->data;
1886 BMEditMesh *em = me->edit_btmesh;
1888 shape_propagate(em, op);
1890 EDBM_update_generic(em, false, false);
1892 return OPERATOR_FINISHED;
1896 void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
1899 ot->name = "Shape Propagate";
1900 ot->description = "Apply selected vertex locations to all other shape keys";
1901 ot->idname = "MESH_OT_shape_propagate_to_all";
1904 ot->exec = edbm_shape_propagate_to_all_exec;
1905 ot->poll = ED_operator_editmesh;
1908 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1911 /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
1912 static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
1914 Object *obedit = CTX_data_edit_object(C);
1915 Mesh *me = obedit->data;
1917 KeyBlock *kb = NULL;
1918 BMEditMesh *em = me->edit_btmesh;
1924 const float blend = RNA_float_get(op->ptr, "blend");
1925 const int shape = RNA_enum_get(op->ptr, "shape");
1926 const bool use_add = RNA_boolean_get(op->ptr, "add");
1929 totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
1930 if (totshape == 0 || shape < 0 || shape >= totshape)
1931 return OPERATOR_CANCELLED;
1933 /* get shape key - needed for finding reference shape (for add mode only) */
1935 kb = BLI_findlink(&key->block, shape);
1938 /* perform blending on selected vertices*/
1939 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1940 if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
1943 /* get coordinates of shapekey we're blending from */
1944 sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
1945 copy_v3_v3(co, sco);
1948 /* in add mode, we add relative shape key offset */
1950 float *rco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative);
1951 sub_v3_v3v3(co, co, rco);
1954 madd_v3_v3fl(eve->co, co, blend);
1957 /* in blend mode, we interpolate to the shape key */
1958 interp_v3_v3v3(eve->co, eve->co, co, blend);
1962 EDBM_update_generic(em, true, false);
1964 return OPERATOR_FINISHED;
1967 static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
1969 Object *obedit = CTX_data_edit_object(C);
1971 EnumPropertyItem *item = NULL;
1974 if ((obedit && obedit->type == OB_MESH) &&
1975 (em = BKE_editmesh_from_object(obedit)) &&
1976 CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY))
1978 EnumPropertyItem tmp = {0, "", 0, "", ""};
1981 for (a = 0; a < em->bm->vdata.totlayer; a++) {
1982 if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
1985 tmp.value = totitem;
1986 tmp.identifier = em->bm->vdata.layers[a].name;
1987 tmp.name = em->bm->vdata.layers[a].name;
1988 /* RNA_enum_item_add sets totitem itself! */
1989 RNA_enum_item_add(&item, &totitem, &tmp);
1993 RNA_enum_item_end(&item, &totitem);
1999 static void edbm_blend_from_shape_ui(bContext *C, wmOperator *op)
2001 uiLayout *layout = op->layout;
2003 Object *obedit = CTX_data_edit_object(C);
2004 Mesh *me = obedit->data;
2007 RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
2008 RNA_id_pointer_create((ID *)me->key, &ptr_key);
2010 uiItemPointerR(layout, &ptr, "shape", &ptr_key, "key_blocks", "", ICON_SHAPEKEY_DATA);
2011 uiItemR(layout, &ptr, "blend", 0, NULL, ICON_NONE);
2012 uiItemR(layout, &ptr, "add", 0, NULL, ICON_NONE);
2015 void MESH_OT_blend_from_shape(wmOperatorType *ot)
2020 ot->name = "Blend From Shape";
2021 ot->description = "Blend in shape from a shape key";
2022 ot->idname = "MESH_OT_blend_from_shape";
2025 ot->exec = edbm_blend_from_shape_exec;
2026 // ot->invoke = WM_operator_props_popup_call; /* disable because search popup closes too easily */
2027 ot->ui = edbm_blend_from_shape_ui;
2028 ot->poll = ED_operator_editmesh;
2031 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2034 prop = RNA_def_enum(ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending");
2035 RNA_def_enum_funcs(prop, shape_itemf);
2036 RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor", -2.0f, 2.0f);
2037 RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather than blend between shapes");
2040 static int edbm_solidify_exec(bContext *C, wmOperator *op)
2042 Object *obedit = CTX_data_edit_object(C);
2043 Mesh *me = obedit->data;
2044 BMEditMesh *em = me->edit_btmesh;
2048 const float thickness = RNA_float_get(op->ptr, "thickness");
2050 if (!EDBM_op_init(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) {
2051 return OPERATOR_CANCELLED;
2054 /* deselect only the faces in the region to be solidified (leave wire
2055 * edges and loose verts selected, as there will be no corresponding
2056 * geometry selected below) */
2057 BMO_slot_buffer_hflag_disable(bm, bmop.slots_in, "geom", BM_FACE, BM_ELEM_SELECT, true);
2059 /* run the solidify operator */
2060 BMO_op_exec(bm, &bmop);
2062 /* select the newly generated faces */
2063 BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
2065 if (!EDBM_op_finish(em, &bmop, op, true)) {
2066 return OPERATOR_CANCELLED;
2069 EDBM_update_generic(em, true, true);
2071 return OPERATOR_FINISHED;
2075 void MESH_OT_solidify(wmOperatorType *ot)
2079 ot->name = "Solidify";
2080 ot->description = "Create a solid skin by extruding, compensating for sharp angles";
2081 ot->idname = "MESH_OT_solidify";
2084 ot->exec = edbm_solidify_exec;
2085 ot->poll = ED_operator_editmesh;
2088 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2090 prop = RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f);
2091 RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
2094 /* ******************************************************************** */
2095 /* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
2098 * Currently mapped to KKey when in MeshEdit mode.
2100 * - Hit Shift K, Select Centers or Exact
2101 * - Hold LMB down to draw path, hit RETKEY.
2102 * - ESC cancels as expected.
2104 * Contributed by Robert Wenzlaff (Det. Thorn).
2107 * - non modal (no menu before cutting)
2108 * - exit on mouse release
2109 * - polygon/segment drawing can become handled by WM cb later
2111 * bmesh port version
2114 #define KNIFE_EXACT 1
2115 #define KNIFE_MIDPOINT 2
2116 #define KNIFE_MULTICUT 3
2118 static EnumPropertyItem knife_items[] = {
2119 {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
2120 {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
2121 {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
2122 {0, NULL, 0, NULL, NULL}
2125 /* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */
2127 static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
2128 float (*mouse_path)[2], int len, char mode, int *isected)
2130 #define MAXSLOPE 100000
2131 float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max;
2132 float y2min, dist, lastdist = 0, xdiff2, xdiff1;
2133 float m1, b1, m2, b2, x21, x22, y21, y22, xi;
2134 float yi, x1min, x1max, y1max, y1min, perc = 0;
2135 float threshold = 0.0;
2138 //threshold = 0.000001; /* tolerance for vertex intersection */
2139 // XXX threshold = scene->toolsettings->select_thresh / 100;
2141 /* Get screen coords of verts */
2148 xdiff2 = (x22 - x21);
2150 m2 = (y22 - y21) / xdiff2;
2151 b2 = ((x22 * y21) - (x21 * y22)) / xdiff2;
2154 m2 = MAXSLOPE; /* Verticle slope */
2160 /* check for _exact_ vertex intersection first */
2161 if (mode != KNIFE_MULTICUT) {
2162 for (i = 0; i < len; i++) {
2168 x11 = mouse_path[i][0];
2169 y11 = mouse_path[i][1];
2171 x12 = mouse_path[i][0];
2172 y12 = mouse_path[i][1];
2175 if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) {
2181 else if ((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)) {
2189 /* now check for edge intersect (may produce vertex intersection as well) */
2190 for (i = 0; i < len; i++) {
2196 x11 = mouse_path[i][0];
2197 y11 = mouse_path[i][1];
2199 x12 = mouse_path[i][0];
2200 y12 = mouse_path[i][1];
2202 /* Perp. Distance from point to line */
2203 if (m2 != MAXSLOPE) dist = (y12 - m2 * x12 - b2); /* /sqrt(m2 * m2 + 1); Only looking for */
2204 /* change in sign. Skip extra math */
2205 else dist = x22 - x12;
2207 if (i == 0) lastdist = dist;
2209 /* if dist changes sign, and intersect point in edge's Bound Box */
2210 if ((lastdist * dist) <= 0) {
2211 xdiff1 = (x12 - x11); /* Equation of line between last 2 points */
2213 m1 = (y12 - y11) / xdiff1;
2214 b1 = ((x12 * y11) - (x11 * y12)) / xdiff1;
2220 x2max = max_ff(x21, x22) + 0.001f; /* prevent missed edges */
2221 x2min = min_ff(x21, x22) - 0.001f; /* due to round off error */
2222 y2max = max_ff(y21, y22) + 0.001f;
2223 y2min = min_ff(y21, y22) - 0.001f;
2225 /* Found an intersect, calc intersect point */
2226 if (m1 == m2) { /* co-incident lines */
2227 /* cut at 50% of overlap area */
2228 x1max = max_ff(x11, x12);
2229 x1min = min_ff(x11, x12);
2230 xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f;
2232 y1max = max_ff(y11, y12);
2233 y1min = min_ff(y11, y12);
2234 yi = (min_ff(y2max, y1max) + max_ff(y2min, y1min)) / 2.0f;
2236 else if (m2 == MAXSLOPE) {
2240 else if (m1 == MAXSLOPE) {
2245 xi = (b1 - b2) / (m2 - m1);
2246 yi = (b1 * m2 - m1 * b2) / (m2 - m1);
2249 /* Intersect inside bounding box of edge?*/
2250 if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) {
2251 /* test for vertex intersect that may be 'close enough'*/
2252 if (mode != KNIFE_MULTICUT) {
2253 if (xi <= (x21 + threshold) && xi >= (x21 - threshold)) {
2254 if (yi <= (y21 + threshold) && yi >= (y21 - threshold)) {
2260 if (xi <= (x22 + threshold) && xi >= (x22 - threshold)) {
2261 if (yi <= (y22 + threshold) && yi >= (y22 - threshold)) {
2268 if ((m2 <= 1.0f) && (m2 >= -1.0f)) perc = (xi - x21) / (x22 - x21);
2269 else perc = (yi - y21) / (y22 - y21); /* lower slope more accurate */
2270 //isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */
2280 #define ELE_EDGE_CUT 1
2282 static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
2284 Object *obedit = CTX_data_edit_object(C);
2285 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2287 ARegion *ar = CTX_wm_region(C);
2293 int len = 0, isected, i;
2295 const short mode = RNA_int_get(op->ptr, "type");
2296 BMOpSlot *slot_edge_percents;
2299 float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2];
2301 /* edit-object needed for matrix, and ar->regiondata for projections to work */
2302 if (ELEM3(NULL, obedit, ar, ar->regiondata))
2303 return OPERATOR_CANCELLED;
2305 if (bm->totvertsel < 2) {
2306 BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on");
2307 return OPERATOR_CANCELLED;
2310 len = RNA_collection_length(op->ptr, "path");
2313 BKE_report(op->reports, RPT_ERROR, "Mouse path too short");
2314 return OPERATOR_CANCELLED;
2317 mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__);
2319 /* get the cut curve */
2320 RNA_BEGIN (op->ptr, itemptr, "path")
2322 RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]);
2326 /* for ED_view3d_project_float_object */
2327 ED_view3d_init_mats_rv3d(obedit, ar->regiondata);
2329 /* TODO, investigate using index lookup for screen_vert_coords() rather then a hash table */
2331 /* the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer */
2332 screen_vert_coords = sco = MEM_mallocN(bm->totvert * sizeof(float) * 2, __func__);
2334 BM_ITER_MESH_INDEX (bv, &iter, bm, BM_VERTS_OF_MESH, i) {
2335 if (ED_view3d_project_float_object(ar, bv->co, *sco, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK) {
2336 copy_v2_fl(*sco, FLT_MAX); /* set error value */
2338 BM_elem_index_set(bv, i); /* set_ok */
2342 bm->elem_index_dirty &= ~BM_VERT; /* clear dirty flag */
2344 if (!EDBM_op_init(em, &bmop, op, "subdivide_edges")) {
2345 MEM_freeN(mouse_path);
2346 MEM_freeN(screen_vert_coords);
2347 return OPERATOR_CANCELLED;
2350 /* store percentage of edge cut for KNIFE_EXACT here.*/
2351 slot_edge_percents = BMO_slot_get(bmop.slots_in, "edge_percents");
2352 BM_ITER_MESH (be, &iter, bm, BM_EDGES_OF_MESH) {
2353 bool is_cut = false;
2354 if (BM_elem_flag_test(be, BM_ELEM_SELECT)) {
2355 const float *sco_a = screen_vert_coords[BM_elem_index_get(be->v1)];
2356 const float *sco_b = screen_vert_coords[BM_elem_index_get(be->v2)];
2358 /* check for error value (vert cant be projected) */
2359 if ((sco_a[0] != FLT_MAX) && (sco_b[0] != FLT_MAX)) {
2360 isect = bm_edge_seg_isect(sco_a, sco_b, mouse_path, len, mode, &isected);
2362 if (isect != 0.0f) {
2363 if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) {
2364 BMO_slot_map_float_insert(&bmop, slot_edge_percents, be, isect);
2370 BMO_elem_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
2374 /* free all allocs */
2375 MEM_freeN(screen_vert_coords);
2376 MEM_freeN(mouse_path);
2379 BMO_slot_buffer_from_enabled_flag(bm, &bmop, bmop.slots_in, "edges", BM_EDGE, ELE_EDGE_CUT);
2381 if (mode == KNIFE_MIDPOINT) numcuts = 1;
2382 BMO_slot_int_set(bmop.slots_in, "cuts", numcuts);
2384 BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_STRAIGHT_CUT);
2385 BMO_slot_bool_set(bmop.slots_in, "use_single_edge", false);
2386 BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false);
2388 BMO_slot_float_set(bmop.slots_in, "radius", 0);
2390 BMO_op_exec(bm, &bmop);
2391 if (!EDBM_op_finish(em, &bmop, op, true)) {
2392 return OPERATOR_CANCELLED;
2395 EDBM_update_generic(em, true, true);
2397 return OPERATOR_FINISHED;
2402 void MESH_OT_knife_cut(wmOperatorType *ot)
2406 ot->name = "Knife Cut";
2407 ot->description = "Cut selected edges and faces into parts";
2408 ot->idname = "MESH_OT_knife_cut";
2410 ot->invoke = WM_gesture_lines_invoke;
2411 ot->modal = WM_gesture_lines_modal;
2412 ot->exec = edbm_knife_cut_exec;
2414 ot->poll = EDBM_view3d_poll;
2417 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2419 RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
2420 prop = RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
2421 RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
2424 RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
2427 static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
2430 Object *obedit = base_old->object;
2433 bm_new = BM_mesh_create(&bm_mesh_allocsize_default);
2434 BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */
2436 CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
2437 CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH, CD_CALLOC, 0);
2438 CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
2439 CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
2441 CustomData_bmesh_init_pool(&bm_new->vdata, bm_mesh_allocsize_default.totvert, BM_VERT);
2442 CustomData_bmesh_init_pool(&bm_new->edata, bm_mesh_allocsize_default.totedge, BM_EDGE);
2443 CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP);
2444 CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE);
2446 base_new = ED_object_add_duplicate(bmain, scene, base_old, USER_DUP_MESH);
2447 /* DAG_relations_tag_update(bmain); */ /* normally would call directly after but in this case delay recalc */
2448 assign_matarar(base_new->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
2450 ED_base_object_select(base_new, BA_SELECT);
2452 BMO_op_callf(bm_old, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
2453 "duplicate geom=%hvef dest=%p", BM_ELEM_TAG, bm_new);
2454 BMO_op_callf(bm_old, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
2455 "delete geom=%hvef context=%i", BM_ELEM_TAG, DEL_FACES);
2457 /* deselect loose data - this used to get deleted,
2458 * we could de-select edges and verts only, but this turns out to be less complicated
2459 * since de-selecting all skips selection flushing logic */
2460 BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
2462 BM_mesh_normals_update(bm_new);
2464 BM_mesh_bm_to_me(bm_new, base_new->object->data, false);
2466 BM_mesh_free(bm_new);
2467 ((Mesh *)base_new->object->data)->edit_btmesh = NULL;
2472 static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
2474 /* we may have tags from previous operators */
2475 BM_mesh_elem_hflag_disable_all(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, false);
2478 BM_mesh_elem_hflag_enable_test(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, BM_ELEM_SELECT);
2480 return (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL);
2483 /* flush a hflag to from verts to edges/faces */
2484 static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag)
2496 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
2497 if (BM_elem_flag_test(e->v1, hflag) &&
2498 BM_elem_flag_test(e->v2, hflag))
2500 BM_elem_flag_enable(e, hflag);
2503 BM_elem_flag_disable(e, hflag);
2506 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2508 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2510 if (!BM_elem_flag_test(l_iter->v, hflag)) {
2514 } while ((l_iter = l_iter->next) != l_first);
2516 BM_elem_flag_set(f, hflag, ok);
2521 * Sets an object to a single material. from one of its slots.
2523 * \note This could be used for split-by-material for non mesh types.
2524 * \note This could take material data from another object or args.
2526 static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr)
2528 ID *obdata = ob->data;
2530 Material ***matarar;
2533 totcolp = give_totcolp_id(obdata);
2534 matarar = give_matarar_id(obdata);
2536 if ((totcolp && matarar) == 0) {
2543 Material *ma_obdata;
2546 if (mat_nr < ob->totcol) {
2547 ma_ob = ob->mat[mat_nr];
2548 matbit = ob->matbits[mat_nr];
2555 if (mat_nr < *totcolp) {
2556 ma_obdata = (*matarar)[mat_nr];
2562 BKE_material_clear_id(obdata, true);
2563 BKE_material_resize_object(ob, 1, true);
2564 BKE_material_resize_id(obdata, 1, true);
2567 ob->matbits[0] = matbit;
2568 (*matarar)[0] = ma_obdata;
2571 BKE_material_clear_id(obdata, true);
2572 BKE_material_resize_object(ob, 0, true);
2573 BKE_material_resize_id(obdata, 0, true);
2577 static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
2581 bool result = false;
2583 while ((f_cmp = BM_iter_at_index(bm_old, BM_FACES_OF_MESH, NULL, 0))) {
2585 const short mat_nr = f_cmp->mat_nr;
2588 BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
2590 BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) {
2591 if (f->mat_nr == mat_nr) {
2595 BM_elem_flag_enable(f, BM_ELEM_TAG);
2596 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2598 BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
2599 BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
2600 } while ((l_iter = l_iter->next) != l_first);
2606 /* leave the current object with some materials */
2607 if (tot == bm_old->totface) {
2608 mesh_separate_material_assign_mat_nr(base_old->object, mat_nr);
2610 /* since we're in editmode, must set faces here */
2611 BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) {
2617 /* Move selection into a separate object */
2618 base_new = mesh_separate_tagged(bmain, scene, base_old, bm_old);
2620 mesh_separate_material_assign_mat_nr(base_new->object, mat_nr);
2623 result |= (base_new != NULL);
2629 static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
2635 bool result = false;
2636 int max_iter = bm_old->totvert;
2638 /* Clear all selected vertices */
2639 BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
2641 /* A "while (true)" loop should work here as each iteration should
2642 * select and remove at least one vertex and when all vertices
2643 * are selected the loop will break out. But guard against bad
2644 * behavior by limiting iterations to the number of vertices in the
2646 for (i = 0; i < max_iter; i++) {
2648 /* Get a seed vertex to start the walk */
2649 v_seed = BM_iter_at_index(bm_old, BM_VERTS_OF_MESH, NULL, 0);
2651 /* No vertices available, can't do anything */
2652 if (v_seed == NULL) {
2656 /* Select the seed explicitly, in case it has no edges */
2657 if (!BM_elem_flag_test(v_seed, BM_ELEM_TAG)) { BM_elem_flag_enable(v_seed, BM_ELEM_TAG); tot++; }
2659 /* Walk from the single vertex, selecting everything connected
2661 BMW_init(&walker, bm_old, BMW_SHELL,
2662 BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
2666 for (e = BMW_begin(&walker, v_seed); e; e = BMW_step(&walker)) {
2667 if (!BM_elem_flag_test(e->v1, BM_ELEM_TAG)) { BM_elem_flag_enable(e->v1, BM_ELEM_TAG); tot++; }
2668 if (!BM_elem_flag_test(e->v2, BM_ELEM_TAG)) { BM_elem_flag_enable(e->v2, BM_ELEM_TAG); tot++; }
2672 if (bm_old->totvert == tot) {
2673 /* Every vertex selected, nothing to separate, work is done */
2677 /* Flush the selection to get edge/face selections matching
2678 * the vertex selection */
2679 bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG);
2681 /* Move selection into a separate object */
2682 result |= (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL);
2688 static int edbm_separate_exec(bContext *C, wmOperator *op)
2690 Main *bmain = CTX_data_main(C);
2691 Scene *scene = CTX_data_scene(C);
2692 const int type = RNA_enum_get(op->ptr, "type");
2695 if (ED_operator_editmesh(C)) {
2696 Base *base = CTX_data_active_base(C);
2697 BMEditMesh *em = BKE_editmesh_from_object(base->object);
2700 if ((em->bm->totvertsel == 0) &&
2701 (em->bm->totedgesel == 0) &&
2702 (em->bm->totfacesel == 0))
2704 BKE_report(op->reports, RPT_ERROR, "Nothing selected");
2705 return OPERATOR_CANCELLED;
2709 /* editmode separate */
2710 if (type == 0) retval = mesh_separate_selected(bmain, scene, base, em->bm);
2711 else if (type == 1) retval = mesh_separate_material(bmain, scene, base, em->bm);
2712 else if (type == 2) retval = mesh_separate_loose(bmain, scene, base, em->bm);
2716 EDBM_update_generic(em, true, true);
2721 BKE_report(op->reports, RPT_ERROR, "Selection not supported in object mode");
2722 return OPERATOR_CANCELLED;
2725 /* object mode separate */
2726 CTX_DATA_BEGIN(C, Base *, base_iter, selected_editable_bases)
2728 Object *ob = base_iter->object;
2729 if (ob->type == OB_MESH) {
2730 Mesh *me = ob->data;
2731 if (me->id.lib == NULL) {
2732 BMesh *bm_old = NULL;
2733 int retval_iter = 0;
2735 bm_old = BM_mesh_create(&bm_mesh_allocsize_default);
2737 BM_mesh_bm_from_me(bm_old, me, false, false, 0);
2739 if (type == 1) retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old);
2740 else if (type == 2) retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old);
2744 BM_mesh_bm_to_me(bm_old, me, false);
2746 DAG_id_tag_update(&me->id, OB_RECALC_DATA);
2747 WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
2750 BM_mesh_free(bm_old);
2752 retval |= retval_iter;
2760 /* delay depsgraph recalc until all objects are duplicated */
2761 DAG_relations_tag_update(bmain);
2762 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
2764 return OPERATOR_FINISHED;
2767 return OPERATOR_CANCELLED;
2770 /* *************** Operator: separate parts *************/
2772 static EnumPropertyItem prop_separate_types[] = {
2773 {0, "SELECTED", 0, "Selection", ""},
2774 {1, "MATERIAL", 0, "By Material", ""},
2775 {2, "LOOSE", 0, "By loose parts", ""},
2776 {0, NULL, 0, NULL, NULL}
2779 void MESH_OT_separate(wmOperatorType *ot)
2782 ot->name = "Separate";
2783 ot->description = "Separate selected geometry into a new mesh";
2784 ot->idname = "MESH_OT_separate";
2787 ot->invoke = WM_menu_invoke;
2788 ot->exec = edbm_separate_exec;
2789 ot->poll = ED_operator_scene_editable; /* object and editmode */
2792 ot->flag = OPTYPE_UNDO;
2794 ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
2798 static int edbm_fill_exec(bContext *C, wmOperator *op)
2800 Object *obedit = CTX_data_edit_object(C);
2801 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2802 const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty");
2805 if (!EDBM_op_init(em, &bmop, op,
2806 "triangle_fill edges=%he use_beauty=%b",
2807 BM_ELEM_SELECT, use_beauty))
2809 return OPERATOR_CANCELLED;
2812 BMO_op_exec(em->bm, &bmop);
2814 /* select new geometry */
2815 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
2817 if (!EDBM_op_finish(em, &bmop, op, true)) {
2818 return OPERATOR_CANCELLED;
2821 EDBM_update_generic(em, true, true);
2823 return OPERATOR_FINISHED;
2827 void MESH_OT_fill(wmOperatorType *ot)
2831 ot->idname = "MESH_OT_fill";
2832 ot->description = "Fill a selected edge loop with faces";
2835 ot->exec = edbm_fill_exec;
2836 ot->poll = ED_operator_editmesh;
2839 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2841 RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division");
2845 /* -------------------------------------------------------------------- */
2846 /* Grid Fill (and helper functions) */
2848 static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v))
2850 return BM_elem_flag_test_bool(e, BM_ELEM_TAG);
2853 static float edbm_fill_grid_vert_tag_angle(BMVert *v)
2859 BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
2860 if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) {
2861 v_pair[i++] = BM_edge_other_vert(e_iter, v);
2866 return fabsf((float)M_PI - angle_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co));
2870 * non-essential utility function to select 2 open edge loops from a closed loop.
2872 static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span_calc)
2879 ListBase eloops = {NULL};
2880 struct BMEdgeLoopStore *el_store;
2881 // LinkData *el_store;
2884 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
2885 BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
2888 count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm);
2889 el_store = eloops.first;
2891 if (count == 1 && BM_edgeloop_is_closed(el_store) && (BM_edgeloop_length_get(el_store) & 1) == 0) {
2892 /* be clever! detect 2 edge loops from one closed edge loop */
2893 const int verts_len = BM_edgeloop_length_get(el_store);
2894 ListBase *verts = BM_edgeloop_verts_get(el_store);
2895 BMVert *v_act = BM_mesh_active_vert_get(bm);
2896 LinkData *v_act_link;
2897 BMEdge **edges = MEM_mallocN(sizeof(*edges) * verts_len, __func__);
2900 if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) {
2904 /* find the vertex with the best angle (a corner vertex) */
2905 LinkData *v_link, *v_link_best = NULL;
2906 float angle_best = -1.0f;
2907 for (v_link = verts->first; v_link; v_link = v_link->next) {
2908 const float angle = edbm_fill_grid_vert_tag_angle(v_link->data);
2909 if ((angle > angle_best) || (v_link_best == NULL)) {
2911 v_link_best = v_link;
2915 v_act_link = v_link_best;
2916 v_act = v_act_link->data;
2920 v_act_link = BLI_findlink(verts, offset);
2921 v_act = v_act_link->data;
2924 /* set this vertex first */
2925 BLI_rotatelist_first(verts, v_act_link);
2926 BM_edgeloop_edges_get(el_store, edges);
2930 /* calculate the span by finding the next corner in 'verts'
2931 * we dont know what defines a corner exactly so find the 4 verts
2932 * in the loop with the greatest angle.
2933 * Tag them and use the first tagged vertex to calculate the span.
2935 * note: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each
2936 * vert, but advantage of de-duplicating is minimal. */
2937 struct SortPointerByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__);
2939 for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) {
2940 BMVert *v = v_link->data;
2941 const float angle = edbm_fill_grid_vert_tag_angle(v);
2942 ele_sort[i].sort_value = angle;
2943 ele_sort[i].data = v;
2945 BM_elem_flag_disable(v, BM_ELEM_TAG);
2948 qsort(ele_sort, verts_len, sizeof(*ele_sort), BLI_sortutil_cmp_float_reverse);
2950 for (i = 0; i < 4; i++) {
2951 BMVert *v = ele_sort[i].data;
2952 BM_elem_flag_enable(v, BM_ELEM_TAG);
2955 /* now find the first... */
2956 for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) {
2957 BMVert *v = v_link->data;
2958 if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
2965 MEM_freeN(ele_sort);
2970 /* un-flag 'rails' */
2971 for (i = 0; i < span; i++) {
2972 BM_elem_flag_disable(edges[i], BM_ELEM_TAG);
2973 BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG);
2977 /* else let the bmesh-operator handle it */
2979 BM_mesh_edgeloops_free(&eloops);
2984 static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
2987 Object *obedit = CTX_data_edit_object(C);
2988 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2989 const short use_smooth = edbm_add_edge_face__smooth_get(em->bm);
2990 const int totedge_orig = em->bm->totedge;
2991 const int totface_orig = em->bm->totface;
2992 const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple");
2993 const bool use_prepare = true;
2997 /* use when we have a single loop selected */
2998 PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span");
2999 PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset");
3002 const int clamp = em->bm->totvertsel;
3006 if (RNA_property_is_set(op->ptr, prop_span)) {
3007 span = RNA_property_int_get(op->ptr, prop_span);
3008 span = min_ii(span, (clamp / 2) - 1);
3016 offset = RNA_property_int_get(op->ptr, prop_offset);
3017 offset = clamp ? mod_i(offset, clamp) : 0;
3019 /* in simple cases, move selection for tags, but also support more advanced cases */
3020 edbm_fill_grid_prepare(em->bm, offset, &span, calc_span);
3022 RNA_property_int_set(op->ptr, prop_span, span);
3024 /* end tricky prepare code */
3027 if (!EDBM_op_init(em, &bmop, op,
3028 "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
3029 use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT,
3030 em->mat_nr, use_smooth, use_interp_simple))
3032 return OPERATOR_CANCELLED;
3035 BMO_op_exec(em->bm, &bmop);
3037 /* cancel if nothing was done */
3038 if ((totedge_orig == em->bm->totedge) &&
3039 (totface_orig == em->bm->totface))
3041 EDBM_op_finish(em, &bmop, op, true);
3042 return OPERATOR_CANCELLED;
3045 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
3047 if (!EDBM_op_finish(em, &bmop, op, true)) {
3048 return OPERATOR_CANCELLED;
3051 EDBM_update_generic(em, true, true);
3053 return OPERATOR_FINISHED;
3056 void MESH_OT_fill_grid(wmOperatorType *ot)
3061 ot->name = "Grid Fill";
3062 ot->description = "Fill grid from two loops";
3063 ot->idname = "MESH_OT_fill_grid";
3066 ot->exec = edbm_fill_grid_exec;
3067 ot->poll = ED_operator_editmesh;
3070 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3073 prop = RNA_def_int(ot->srna, "span", 1, 1, INT_MAX, "Span", "Number of sides (zero disables)", 1, 100);
3074 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3075 prop = RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "Number of sides (zero disables)", -100, 100);
3076 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3077 RNA_def_boolean(ot->srna, "use_interp_simple", 0, "Simple Blending", "");
3080 static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
3082 Object *obedit = CTX_data_edit_object(C);
3083 BMEditMesh *em = BKE_editmesh_from_object(obedit);
3084 const int sides = RNA_int_get(op->ptr, "sides");
3086 if (!EDBM_op_call_and_selectf(
3089 "holes_fill edges=%he sides=%i",
3090 BM_ELEM_SELECT, sides))
3092 return OPERATOR_CANCELLED;
3095 EDBM_update_generic(em, true, true);
3097 return OPERATOR_FINISHED;
3101 void MESH_OT_fill_holes(wmOperatorType *ot)
3104 ot->name = "Fill Holes";
3105 ot->idname = "MESH_OT_fill_holes";
3106 ot->description = "Fill in holes (boundary edge loops)";
3109 ot->exec = edbm_fill_holes_exec;
3110 ot->poll = ED_operator_editmesh;
3113 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3115 RNA_def_int(ot->srna, "sides", 4, 0, INT_MAX, "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100);
3118 static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
3120 Object *obedit = CTX_data_edit_object(C);
3121 BMEditMesh *em = BKE_editmesh_from_object(obedit);
3123 const float angle_max = M_PI;
3124 const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
3127 if (angle_limit >= angle_max) {
3128 hflag = BM_ELEM_SELECT;
3134 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3135 BM_elem_flag_set(e, BM_ELEM_TAG,
3136 (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
3137 BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit));
3141 hflag = BM_ELEM_TAG;
3144 if (!EDBM_op_call_and_selectf(
3145 em, op, "geom.out", true,
3146 "beautify_fill faces=%hf edges=%he",
3147 BM_ELEM_SELECT, hflag))
3149 return OPERATOR_CANCELLED;
3152 EDBM_update_generic(em, true, true);
3154 return OPERATOR_FINISHED;
3157 void MESH_OT_beautify_fill(wmOperatorType *ot)
3162 ot->name = "Beautify Faces";
3163 ot->idname = "MESH_OT_beautify_fill";
3164 ot->description = "Rearrange some faces to try to get less degenerated geometry";
3167 ot->exec = edbm_beautify_fill_exec;
3168 ot->poll = ED_operator_editmesh;
3171 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3174 prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
3175 "Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f));
3176 RNA_def_property_float_default(prop, DEG2RADF(180.0f));
3180 /********************** Poke Face **********************/
3182 static int edbm_poke_face_exec(bContext *C, wmOperator *op)
3184 Object *obedit = CTX_data_edit_object(C);
3185 BMEditMesh *em = BKE_editmesh_from_object(obedit);
3188 const float offset = RNA_float_get(op->ptr, "offset");
3189 const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset");
3190 const int center_mode = RNA_enum_get(op->ptr, "center_mode");
3192 EDBM_op_init(em, &bmop, op, "poke faces=%hf offset=%f use_relative_offset=%b center_mode=%i",
3193 BM_ELEM_SELECT, offset, use_relative_offset, center_mode);
3194 BMO_op_exec(em->bm, &bmop);
3196 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
3198 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true);
3199 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
3201 if (!EDBM_op_finish(em, &bmop, op, true)) {
3202 return OPERATOR_CANCELLED;
3205 EDBM_mesh_normals_update(em);
3207 EDBM_update_generic(em, true, true);
3209 return OPERATOR_FINISHED;
3213 void MESH_OT_poke(wmOperatorType *ot)
3216 static EnumPropertyItem poke_center_modes[] = {
3217 {BMOP_POKE_MEAN_WEIGHTED, "MEAN_WEIGHTED", 0, "Weighted Mean", "Weighted Mean Face Center"},
3218 {BMOP_POKE_MEAN, "MEAN", 0, "Mean", "Mean Face Center"},
3219 {BMOP_POKE_BOUNDS, "BOUNDS", 0, "Bounds", "Face Bounds Center"},
3220 {0, NULL, 0, NULL, NULL}};
3224 ot->name = "Poke Faces";
3225 ot->idname = "MESH_OT_poke";
3226 ot->description = "Split a face into a fan";
3229 ot->exec = edbm_poke_face_exec;
3230 ot->poll = ED_operator_editmesh;
3233 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3235 RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
3236 RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
3237 RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEAN_WEIGHTED, "Poke Center", "Poke Face Center Calculation");
3240 /********************** Quad/Tri Operators *************************/
3242 static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
3244 Object *obedit = CTX_data_edit_object(C);
3245 BMEditMesh *em = BKE_editmesh_from_object(obedit);
3247 const int quad_method = RNA_enum_get(op->ptr, "quad_method");
3248 const int ngon_method = RNA_enum_get(op->ptr, "ngon_method");
3250 EDBM_op_init(em, &bmop, op, "triangulate faces=%hf quad_method=%i ngon_method=%i", BM_ELEM_SELECT, quad_method, ngon_method);
3251 BMO_op_exec(em->bm, &bmop);
3253 /* select the output */
3254 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
3255 EDBM_selectmode_flush(em);
3257 if (!EDBM_op_finish(em, &bmop, op, true)) {
3258 return OPERATOR_CANCELLED;
3261 EDBM_update_generic(em, true, true);
3263 return OPERATOR_FINISHED;
3267 void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
3270 ot->name = "Triangulate Faces";
3271 ot->idname = "MESH_OT_quads_convert_to_tris";
3272 ot->description = "Triangulate selected faces";
3275 ot->exec = edbm_quads_convert_to_tris_exec;
3276 ot->poll = ED_operator_editmesh;
3279 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3281 RNA_def_enum(ot->srna, "quad_method", modifier_triangulate_quad_method_items, MOD_TRIANGULATE_QUAD_BEAUTY,
3282 "Quad Method", "Method for splitting the quads into triangles");