Blender  V2.93
editmesh_tools.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2004 by Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <stddef.h>
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "DNA_key_types.h"
29 #include "DNA_material_types.h"
30 #include "DNA_mesh_types.h"
31 #include "DNA_meshdata_types.h"
32 #include "DNA_modifier_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35 
36 #include "BLI_bitmap.h"
37 #include "BLI_heap_simple.h"
38 #include "BLI_linklist.h"
39 #include "BLI_linklist_stack.h"
40 #include "BLI_listbase.h"
41 #include "BLI_math.h"
42 #include "BLI_rand.h"
43 #include "BLI_sort_utils.h"
44 #include "BLI_string.h"
45 
46 #include "BKE_context.h"
47 #include "BKE_deform.h"
48 #include "BKE_editmesh.h"
49 #include "BKE_key.h"
50 #include "BKE_layer.h"
51 #include "BKE_lib_id.h"
52 #include "BKE_main.h"
53 #include "BKE_material.h"
54 #include "BKE_mesh.h"
55 #include "BKE_report.h"
56 #include "BKE_texture.h"
57 
58 #include "DEG_depsgraph.h"
59 #include "DEG_depsgraph_build.h"
60 
61 #include "BLT_translation.h"
62 
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65 #include "RNA_enum_types.h"
66 
67 #include "WM_api.h"
68 #include "WM_types.h"
69 
70 #include "ED_mesh.h"
71 #include "ED_object.h"
72 #include "ED_outliner.h"
73 #include "ED_screen.h"
74 #include "ED_transform.h"
75 #include "ED_uvedit.h"
76 #include "ED_view3d.h"
77 
78 #include "RE_texture.h"
79 
80 #include "UI_interface.h"
81 #include "UI_resources.h"
82 
83 #include "mesh_intern.h" /* own include */
84 
85 #include "bmesh_tools.h"
86 
87 #define USE_FACE_CREATE_SEL_EXTEND
88 
89 /* -------------------------------------------------------------------- */
94 {
95  const int cuts = RNA_int_get(op->ptr, "number_cuts");
96  const 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");
99  const bool use_quad_tri = !RNA_boolean_get(op->ptr, "ngon");
100 
101  if (use_quad_tri && RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT) {
102  RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT);
103  }
104  const int quad_corner_type = RNA_enum_get(op->ptr, "quadcorner");
105  const int seed = RNA_int_get(op->ptr, "seed");
106 
107  ViewLayer *view_layer = CTX_data_view_layer(C);
108  uint objects_len = 0;
110  view_layer, CTX_wm_view3d(C), &objects_len);
111 
112  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
113  Object *obedit = objects[ob_index];
114  BMEditMesh *em = BKE_editmesh_from_object(obedit);
115 
116  if (!(em->bm->totedgesel || em->bm->totfacesel)) {
117  continue;
118  }
119 
122  smooth,
124  false,
125  fractal,
126  along_normal,
127  cuts,
129  quad_corner_type,
130  use_quad_tri,
131  true,
132  false,
133  seed);
134 
135  EDBM_update_generic(obedit->data, true, true);
136  }
137 
138  MEM_freeN(objects);
139 
140  return OPERATOR_FINISHED;
141 }
142 
143 /* Note, these values must match delete_mesh() event values */
145  {SUBD_CORNER_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
146  {SUBD_CORNER_PATH, "PATH", 0, "Path", ""},
147  {SUBD_CORNER_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
148  {SUBD_CORNER_FAN, "FAN", 0, "Fan", ""},
149  {0, NULL, 0, NULL, NULL},
150 };
151 
153 {
154  PropertyRNA *prop;
155 
156  /* identifiers */
157  ot->name = "Subdivide";
158  ot->description = "Subdivide selected edges";
159  ot->idname = "MESH_OT_subdivide";
160 
161  /* api callbacks */
164 
165  /* flags */
167 
168  /* properties */
169  prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 100, "Number of Cuts", "", 1, 10);
170  /* avoid re-using last var because it can cause
171  * _very_ high poly meshes and annoy users (or worse crash) */
173 
175  ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
176 
178 
180  "ngon",
181  true,
182  "Create N-Gons",
183  "When disabled, newly created faces are limited to 3 and 4 sided faces");
184  RNA_def_enum(
185  ot->srna,
186  "quadcorner",
189  "Quad Corner Type",
190  "How to subdivide quad corners (anything other than Straight Cut will prevent n-gons)");
191 
193  "fractal",
194  0.0f,
195  0.0f,
196  1e6f,
197  "Fractal",
198  "Fractal randomness factor",
199  0.0f,
200  1000.0f);
202  "fractal_along_normal",
203  0.0f,
204  0.0f,
205  1.0f,
206  "Along Normal",
207  "Apply fractal displacement along normal only",
208  0.0f,
209  1.0f);
211  "seed",
212  0,
213  0,
214  INT_MAX,
215  "Random Seed",
216  "Seed for the random number generator",
217  0,
218  255);
219 }
220 
223 /* -------------------------------------------------------------------- */
232  int cuts;
233  float smooth;
234 
237 };
238 
240  const int cuts_min,
241  const int cuts_default)
242 {
243  /* Note, these values must match delete_mesh() event values */
244  static const EnumPropertyItem prop_subd_edgering_types[] = {
245  {SUBD_RING_INTERP_LINEAR, "LINEAR", 0, "Linear", ""},
246  {SUBD_RING_INTERP_PATH, "PATH", 0, "Blend Path", ""},
247  {SUBD_RING_INTERP_SURF, "SURFACE", 0, "Blend Surface", ""},
248  {0, NULL, 0, NULL, NULL},
249  };
250 
251  PropertyRNA *prop;
252 
253  prop = RNA_def_int(
254  ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", cuts_min, 64);
256 
258  "interpolation",
259  prop_subd_edgering_types,
261  "Interpolation",
262  "Interpolation method");
263 
265  ot->srna, "smoothness", 1.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 2.0f);
266 
267  /* profile-shape */
269  "profile_shape_factor",
270  0.0f,
271  -1e3f,
272  1e3f,
273  "Profile Factor",
274  "How much intermediary new edges are shrunk/expanded",
275  -2.0f,
276  2.0f);
277 
278  prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE);
281  RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile");
282  RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
283 }
284 
286 {
287  op_props->interp_mode = RNA_enum_get(op->ptr, "interpolation");
288  op_props->cuts = RNA_int_get(op->ptr, "number_cuts");
289  op_props->smooth = RNA_float_get(op->ptr, "smoothness");
290 
291  op_props->profile_shape = RNA_enum_get(op->ptr, "profile_shape");
292  op_props->profile_shape_factor = RNA_float_get(op->ptr, "profile_shape_factor");
293 }
294 
296 {
297 
298  ViewLayer *view_layer = CTX_data_view_layer(C);
299  uint objects_len = 0;
301  view_layer, CTX_wm_view3d(C), &objects_len);
302  struct EdgeRingOpSubdProps op_props;
303 
304  mesh_operator_edgering_props_get(op, &op_props);
305 
306  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
307  Object *obedit = objects[ob_index];
308  BMEditMesh *em = BKE_editmesh_from_object(obedit);
309 
310  if (em->bm->totedgesel == 0) {
311  continue;
312  }
313 
314  if (!EDBM_op_callf(em,
315  op,
316  "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
317  "profile_shape=%i profile_shape_factor=%f",
319  op_props.interp_mode,
320  op_props.cuts,
321  op_props.smooth,
322  op_props.profile_shape,
323  op_props.profile_shape_factor)) {
324  continue;
325  }
326 
327  EDBM_update_generic(obedit->data, true, true);
328  }
329 
330  MEM_freeN(objects);
331  return OPERATOR_FINISHED;
332 }
333 
335 {
336  /* identifiers */
337  ot->name = "Subdivide Edge-Ring";
338  ot->description = "Subdivide perpendicular edges to the selected edge-ring";
339  ot->idname = "MESH_OT_subdivide_edgering";
340 
341  /* api callbacks */
344 
345  /* flags */
347 
348  /* properties */
350 }
351 
354 /* -------------------------------------------------------------------- */
359 {
360  const int iterations = RNA_int_get(op->ptr, "iterations");
361  ViewLayer *view_layer = CTX_data_view_layer(C);
362  uint objects_len = 0;
364  view_layer, CTX_wm_view3d(C), &objects_len);
365  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
366  Object *obedit = objects[ob_index];
367  BMEditMesh *em = BKE_editmesh_from_object(obedit);
368 
369  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
370  continue;
371  }
372 
373  BMOperator bmop;
374  EDBM_op_init(em, &bmop, op, "unsubdivide verts=%hv iterations=%i", BM_ELEM_SELECT, iterations);
375 
376  BMO_op_exec(em->bm, &bmop);
377 
378  if (!EDBM_op_finish(em, &bmop, op, true)) {
379  continue;
380  }
381 
382  if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
383  EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); /* need to flush vert->face first */
384  }
386 
387  EDBM_update_generic(obedit->data, true, true);
388  }
389  MEM_freeN(objects);
390 
391  return OPERATOR_FINISHED;
392 }
393 
395 {
396  /* identifiers */
397  ot->name = "Un-Subdivide";
398  ot->description = "Un-subdivide selected edges and faces";
399  ot->idname = "MESH_OT_unsubdivide";
400 
401  /* api callbacks */
404 
405  /* flags */
407 
408  /* props */
409  RNA_def_int(
410  ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to un-subdivide", 1, 100);
411 }
412 
415 /* -------------------------------------------------------------------- */
419 /* Note, these values must match delete_mesh() event values */
420 enum {
426 };
427 
428 static void edbm_report_delete_info(ReportList *reports,
429  const int totelem_old[3],
430  const int totelem_new[3])
431 {
432  BKE_reportf(reports,
433  RPT_INFO,
434  "Removed: %d vertices, %d edges, %d faces",
435  totelem_old[0] - totelem_new[0],
436  totelem_old[1] - totelem_new[1],
437  totelem_old[2] - totelem_new[2]);
438 }
439 
441 {
442  ViewLayer *view_layer = CTX_data_view_layer(C);
443 
444  uint objects_len = 0;
446  view_layer, CTX_wm_view3d(C), &objects_len);
447  bool changed_multi = false;
448 
449  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
450  Object *obedit = objects[ob_index];
451  BMEditMesh *em = BKE_editmesh_from_object(obedit);
452  const int type = RNA_enum_get(op->ptr, "type");
453 
455 
456  switch (type) {
457  case MESH_DELETE_VERT: /* Erase Vertices */
458  if (!(em->bm->totvertsel &&
459  EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS))) {
460  continue;
461  }
462  break;
463  case MESH_DELETE_EDGE: /* Erase Edges */
464  if (!(em->bm->totedgesel &&
465  EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES))) {
466  continue;
467  }
468  break;
469  case MESH_DELETE_FACE: /* Erase Faces */
470  if (!(em->bm->totfacesel &&
471  EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES))) {
472  continue;
473  }
474  break;
476  /* Edges and Faces */
477  if (!((em->bm->totedgesel || em->bm->totfacesel) &&
479  em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))) {
480  continue;
481  }
482  break;
484  /* Only faces. */
485  if (!(em->bm->totfacesel &&
487  em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES))) {
488  continue;
489  }
490  break;
491  default:
492  BLI_assert(0);
493  break;
494  }
495 
496  changed_multi = true;
497 
499 
501 
502  EDBM_update_generic(obedit->data, true, true);
503 
506  }
507 
508  MEM_freeN(objects);
509 
510  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
511 }
512 
514 {
515  static const EnumPropertyItem prop_mesh_delete_types[] = {
516  {MESH_DELETE_VERT, "VERT", 0, "Vertices", ""},
517  {MESH_DELETE_EDGE, "EDGE", 0, "Edges", ""},
518  {MESH_DELETE_FACE, "FACE", 0, "Faces", ""},
519  {MESH_DELETE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""},
520  {MESH_DELETE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""},
521  {0, NULL, 0, NULL, NULL},
522  };
523 
524  /* identifiers */
525  ot->name = "Delete";
526  ot->description = "Delete selected vertices, edges or faces";
527  ot->idname = "MESH_OT_delete";
528 
529  /* api callbacks */
532 
534 
535  /* flags */
537 
538  /* props */
539  ot->prop = RNA_def_enum(ot->srna,
540  "type",
541  prop_mesh_delete_types,
543  "Type",
544  "Method used for deleting mesh data");
546 }
547 
550 /* -------------------------------------------------------------------- */
554 static bool bm_face_is_loose(BMFace *f)
555 {
556  BMLoop *l_iter, *l_first;
557 
558  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
559  do {
560  if (!BM_edge_is_boundary(l_iter->e)) {
561  return false;
562  }
563  } while ((l_iter = l_iter->next) != l_first);
564 
565  return true;
566 }
567 
569 {
570  ViewLayer *view_layer = CTX_data_view_layer(C);
571  int totelem_old_sel[3];
572  int totelem_old[3];
573 
574  uint objects_len = 0;
576  view_layer, CTX_wm_view3d(C), &objects_len);
577 
578  EDBM_mesh_stats_multi(objects, objects_len, totelem_old, totelem_old_sel);
579 
580  const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && totelem_old_sel[0]);
581  const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && totelem_old_sel[1]);
582  const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && totelem_old_sel[2]);
583 
584  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
585  Object *obedit = objects[ob_index];
586 
587  BMEditMesh *em = BKE_editmesh_from_object(obedit);
588  BMesh *bm = em->bm;
589  BMIter iter;
590 
592 
593  if (use_faces) {
594  BMFace *f;
595 
596  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
599  }
600  }
601 
603  }
604 
605  if (use_edges) {
606  BMEdge *e;
607 
608  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
611  }
612  }
613 
615  }
616 
617  if (use_verts) {
618  BMVert *v;
619 
620  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
623  }
624  }
625 
627  }
628 
630 
631  EDBM_update_generic(obedit->data, true, true);
632  }
633 
634  int totelem_new[3];
635  EDBM_mesh_stats_multi(objects, objects_len, totelem_new, NULL);
636 
637  edbm_report_delete_info(op->reports, totelem_old, totelem_new);
638 
639  MEM_freeN(objects);
640 
641  return OPERATOR_FINISHED;
642 }
643 
645 {
646  /* identifiers */
647  ot->name = "Delete Loose";
648  ot->description = "Delete loose vertices, edges or faces";
649  ot->idname = "MESH_OT_delete_loose";
650 
651  /* api callbacks */
653 
655 
656  /* flags */
658 
659  /* props */
660  RNA_def_boolean(ot->srna, "use_verts", true, "Vertices", "Remove loose vertices");
661  RNA_def_boolean(ot->srna, "use_edges", true, "Edges", "Remove loose edges");
662  RNA_def_boolean(ot->srna, "use_faces", false, "Faces", "Remove loose faces");
663 }
664 
667 /* -------------------------------------------------------------------- */
672 {
673  ViewLayer *view_layer = CTX_data_view_layer(C);
674  uint objects_len = 0;
676  view_layer, CTX_wm_view3d(C), &objects_len);
677  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
678  Object *obedit = objects[ob_index];
679  BMEditMesh *em = BKE_editmesh_from_object(obedit);
680 
681  if (em->bm->totedgesel == 0) {
682  continue;
683  }
684 
685  if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true)) {
686  continue;
687  }
688 
689  EDBM_update_generic(obedit->data, true, true);
690  }
691  MEM_freeN(objects);
692 
693  return OPERATOR_FINISHED;
694 }
695 
697 {
698  /* identifiers */
699  ot->name = "Collapse Edges & Faces";
700  ot->description =
701  "Collapse isolated edge and face regions, merging data such as UV's and vertex colors. "
702  "This can collapse edge-rings as well as regions of connected faces into vertices";
703  ot->idname = "MESH_OT_edge_collapse";
704 
705  /* api callbacks */
708 
709  /* flags */
711 }
712 
715 /* -------------------------------------------------------------------- */
720 {
721  BMEdge *e;
722  BMIter iter;
723 
724  uint vote_on_smooth[2] = {0, 0};
725 
726  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
727  if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
728  vote_on_smooth[BM_elem_flag_test_bool(e->l->f, BM_ELEM_SMOOTH)]++;
729  }
730  }
731 
732  return (vote_on_smooth[0] < vote_on_smooth[1]);
733 }
734 
735 #ifdef USE_FACE_CREATE_SEL_EXTEND
741  BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len, bool (*func)(const BMEdge *))
742 {
743  BMIter iter;
744  BMEdge *e_iter;
745  int i = 0;
746  BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
747  if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) {
748  if ((e_used == NULL) || (e_used != e_iter)) {
749  if (func(e_iter)) {
750  e_arr[i++] = e_iter;
751  if (i >= e_arr_len) {
752  break;
753  }
754  }
755  }
756  }
757  }
758  return i;
759 }
760 
762 {
763  BMIter iter;
764  bool found = false;
765 
766  if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) {
767  /* first look for 2 boundary edges */
768  BMVert *v;
769 
770  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
772  found = true;
773  break;
774  }
775  }
776 
777  if (found) {
778  BMEdge *ed_pair[3];
780  2) &&
781  (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) ||
782 
784  2) &&
785  (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false))) {
786  BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v),
787  BM_edge_other_vert(ed_pair[1], v));
788  BM_edge_select_set(bm, ed_pair[0], true);
789  BM_edge_select_set(bm, ed_pair[1], true);
790  if (e_other) {
791  BM_edge_select_set(bm, e_other, true);
792  }
793  return (BMElem *)v;
794  }
795  }
796  }
797  else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) {
798  /* first look for 2 boundary edges */
799  BMEdge *e;
800 
801  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
803  found = true;
804  break;
805  }
806  }
807  if (found) {
808  BMEdge *ed_pair_v1[2];
809  BMEdge *ed_pair_v2[2];
810  if (((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) ==
811  1) &&
813  1) &&
814  (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
815  (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
816 
817 # if 1 /* better support mixed cases T37203. */
819  1) &&
821  e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) &&
822  (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
823  (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
824 
826  e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) &&
828  1) &&
829  (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
830  (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
831 # endif
832 
834  e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) &&
836  e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) &&
837  (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
838  (BM_edge_share_face_check(e, ed_pair_v2[0]) == false))) {
839  BMVert *v1_other = BM_edge_other_vert(ed_pair_v1[0], e->v1);
840  BMVert *v2_other = BM_edge_other_vert(ed_pair_v2[0], e->v2);
841  BMEdge *e_other = (v1_other != v2_other) ? BM_edge_exists(v1_other, v2_other) : NULL;
842  BM_edge_select_set(bm, ed_pair_v1[0], true);
843  BM_edge_select_set(bm, ed_pair_v2[0], true);
844  if (e_other) {
845  BM_edge_select_set(bm, e_other, true);
846  }
847  return (BMElem *)e;
848  }
849  }
850  }
851 
852  return NULL;
853 }
855 {
856  /* Now we need to find the edge that isn't connected to this element. */
858 
859  /* Notes on hidden geometry:
860  * - Un-hide the face since its possible hidden was copied when copying
861  * surrounding face attributes.
862  * - Un-hide before adding to select history
863  * since we may extend into an existing, hidden vert/edge.
864  */
865 
867  BM_face_select_set(bm, f, false);
868 
869  if (ele_desel->head.htype == BM_VERT) {
870  BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel);
871  BLI_assert(f->len == 3);
872  BM_vert_select_set(bm, (BMVert *)ele_desel, false);
873  BM_edge_select_set(bm, l->next->e, true);
875  }
876  else {
877  BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel);
878  BLI_assert(ELEM(f->len, 4, 3));
879 
880  BM_edge_select_set(bm, (BMEdge *)ele_desel, false);
881  if (f->len == 4) {
882  BMEdge *e_active = l->next->next->e;
884  BM_edge_select_set(bm, e_active, true);
885  BM_select_history_store(bm, e_active);
886  }
887  else {
888  BMVert *v_active = l->next->next->v;
890  BM_vert_select_set(bm, v_active, true);
891  BM_select_history_store(bm, v_active);
892  }
893  }
894 }
895 #endif /* USE_FACE_CREATE_SEL_EXTEND */
896 
898 {
899  /* When this is used to dissolve we could avoid this, but checking isn't too slow. */
900  bool changed_multi = false;
901  ViewLayer *view_layer = CTX_data_view_layer(C);
902  uint objects_len = 0;
904  view_layer, CTX_wm_view3d(C), &objects_len);
905  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
906  Object *obedit = objects[ob_index];
907  BMEditMesh *em = BKE_editmesh_from_object(obedit);
908 
909  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totvertsel == 0)) {
910  continue;
911  }
912 
913  bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
914  int totedge_orig = em->bm->totedge;
915  int totface_orig = em->bm->totface;
916 
917  BMOperator bmop;
918 #ifdef USE_FACE_CREATE_SEL_EXTEND
919  BMElem *ele_desel;
920  BMFace *ele_desel_face;
921 
922  /* be extra clever, figure out if a partial selection should be extended so we can create
923  * geometry with single vert or single edge selection. */
925 #endif
926  if (!EDBM_op_init(em,
927  &bmop,
928  op,
929  "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
931  em->mat_nr,
932  use_smooth)) {
933  continue;
934  }
935 
936  BMO_op_exec(em->bm, &bmop);
937 
938  /* cancel if nothing was done */
939  if ((totedge_orig == em->bm->totedge) && (totface_orig == em->bm->totface)) {
940  EDBM_op_finish(em, &bmop, op, true);
941  continue;
942  }
943 #ifdef USE_FACE_CREATE_SEL_EXTEND
944  /* normally we would want to leave the new geometry selected,
945  * but being able to press F many times to add geometry is too useful! */
946  if (ele_desel && (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) &&
947  (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out"))) {
948  edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face);
949  }
950  else
951 #endif
952  {
953  /* Newly created faces may include existing hidden edges,
954  * copying face data from surrounding, may have copied hidden face flag too.
955  *
956  * Important that faces use flushing since 'edges.out'
957  * wont include hidden edges that already existed.
958  */
960  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true);
962  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false);
963 
965  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
967  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
968  }
969 
970  if (!EDBM_op_finish(em, &bmop, op, true)) {
971  continue;
972  }
973 
974  EDBM_update_generic(obedit->data, true, true);
975  changed_multi = true;
976  }
977  MEM_freeN(objects);
978 
979  if (!changed_multi) {
980  return OPERATOR_CANCELLED;
981  }
982 
983  return OPERATOR_FINISHED;
984 }
985 
987 {
988  /* identifiers */
989  ot->name = "Make Edge/Face";
990  ot->description = "Add an edge or face to selected";
991  ot->idname = "MESH_OT_edge_face_add";
992 
993  /* api callbacks */
996 
997  /* flags */
999 }
1000 
1003 /* -------------------------------------------------------------------- */
1008 {
1010  ViewLayer *view_layer = CTX_data_view_layer(C);
1011  BMEdge *eed;
1012  BMIter iter;
1013  const bool clear = RNA_boolean_get(op->ptr, "clear");
1014 
1015  uint objects_len = 0;
1017  view_layer, CTX_wm_view3d(C), &objects_len);
1018  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1019  Object *obedit = objects[ob_index];
1020  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1021  BMesh *bm = em->bm;
1022 
1023  if (bm->totedgesel == 0) {
1024  continue;
1025  }
1026 
1027  if (clear) {
1028  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
1030  continue;
1031  }
1032 
1034  }
1035  }
1036  else {
1037  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
1039  continue;
1040  }
1042  }
1043  }
1044  }
1045 
1046  ED_uvedit_live_unwrap(scene, objects, objects_len);
1047 
1048  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1049  Object *obedit = objects[ob_index];
1050  EDBM_update_generic(obedit->data, true, false);
1051  }
1052 
1053  MEM_freeN(objects);
1054 
1055  return OPERATOR_FINISHED;
1056 }
1057 
1059 {
1060  PropertyRNA *prop;
1061 
1062  /* identifiers */
1063  ot->name = "Mark Seam";
1064  ot->idname = "MESH_OT_mark_seam";
1065  ot->description = "(Un)mark selected edges as a seam";
1066 
1067  /* api callbacks */
1070 
1071  /* flags */
1073 
1074  prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1076 
1078 }
1079 
1082 /* -------------------------------------------------------------------- */
1087 {
1088  BMEdge *eed;
1089  BMIter iter;
1090  const bool clear = RNA_boolean_get(op->ptr, "clear");
1091  const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
1092  ViewLayer *view_layer = CTX_data_view_layer(C);
1093 
1094  uint objects_len = 0;
1096  view_layer, CTX_wm_view3d(C), &objects_len);
1097  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1098  Object *obedit = objects[ob_index];
1099  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1100  BMesh *bm = em->bm;
1101 
1102  if ((use_verts && bm->totvertsel == 0) || (!use_verts && bm->totedgesel == 0)) {
1103  continue;
1104  }
1105 
1106  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
1107  if (use_verts) {
1108  if (!(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
1110  continue;
1111  }
1112  }
1113  else if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1114  continue;
1115  }
1116 
1118  }
1119 
1120  EDBM_update_generic(obedit->data, true, false);
1121  }
1122  MEM_freeN(objects);
1123 
1124  return OPERATOR_FINISHED;
1125 }
1126 
1128 {
1129  PropertyRNA *prop;
1130 
1131  /* identifiers */
1132  ot->name = "Mark Sharp";
1133  ot->idname = "MESH_OT_mark_sharp";
1134  ot->description = "(Un)mark selected edges as sharp";
1135 
1136  /* api callbacks */
1139 
1140  /* flags */
1142 
1143  prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
1145  prop = RNA_def_boolean(
1146  ot->srna,
1147  "use_verts",
1148  false,
1149  "Vertices",
1150  "Consider vertices instead of edges to select which edges to (un)tag as sharp");
1152 }
1153 
1156 /* -------------------------------------------------------------------- */
1160 static bool edbm_connect_vert_pair(BMEditMesh *em, struct Mesh *me, wmOperator *op)
1161 {
1162  BMesh *bm = em->bm;
1163  BMOperator bmop;
1164  const int verts_len = bm->totvertsel;
1165  bool is_pair = (verts_len == 2);
1166  int len = 0;
1167  bool check_degenerate = true;
1168 
1169  bool checks_succeded = true;
1170 
1171  /* sanity check */
1172  if (verts_len < 2) {
1173  return false;
1174  }
1175 
1176  BMVert **verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__);
1177  {
1178  BMIter iter;
1179  BMVert *v;
1180  int i = 0;
1181 
1182  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
1184  verts[i++] = v;
1185  }
1186  }
1187 
1189  verts[0],
1190  verts[1],
1192  check_degenerate = false;
1193  is_pair = false;
1194  }
1195  }
1196 
1197  if (is_pair) {
1198  if (!EDBM_op_init(em,
1199  &bmop,
1200  op,
1201  "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
1202  verts,
1203  verts_len,
1205  BM_ELEM_HIDDEN)) {
1206  checks_succeded = false;
1207  }
1208  }
1209  else {
1210  if (!EDBM_op_init(em,
1211  &bmop,
1212  op,
1213  "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
1214  verts,
1215  verts_len,
1217  check_degenerate)) {
1218  checks_succeded = false;
1219  }
1220  }
1221  if (checks_succeded) {
1223 
1224  BMO_op_exec(bm, &bmop);
1225  len = BMO_slot_get(bmop.slots_out, "edges.out")->len;
1226 
1227  if (len && is_pair) {
1228  /* new verts have been added, we have to select the edges, not just flush */
1230  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
1231  }
1232 
1233  if (!EDBM_op_finish(em, &bmop, op, true)) {
1234  len = 0;
1235  }
1236  else {
1237  /* so newly created edges get the selection state from the vertex */
1239 
1241 
1242  EDBM_update_generic(me, true, true);
1243  }
1244  }
1245  MEM_freeN(verts);
1246 
1247  return len;
1248 }
1249 
1251 {
1252  ViewLayer *view_layer = CTX_data_view_layer(C);
1253  uint objects_len = 0;
1254  uint failed_objects_len = 0;
1256  view_layer, CTX_wm_view3d(C), &objects_len);
1257 
1258  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1259  Object *obedit = objects[ob_index];
1260  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1261 
1262  if (!edbm_connect_vert_pair(em, obedit->data, op)) {
1263  failed_objects_len++;
1264  }
1265  }
1266  MEM_freeN(objects);
1267  return failed_objects_len == objects_len ? OPERATOR_CANCELLED : OPERATOR_FINISHED;
1268 }
1269 
1271 {
1272  /* identifiers */
1273  ot->name = "Vertex Connect";
1274  ot->idname = "MESH_OT_vert_connect";
1275  ot->description = "Connect selected vertices of faces, splitting the face";
1276 
1277  /* api callbacks */
1280 
1281  /* flags */
1283 }
1284 
1287 /* -------------------------------------------------------------------- */
1295 {
1296  BMEditSelection *ele_a = bm->selected.first;
1297  BMEditSelection *ele_b = bm->selected.last;
1298  if ((ele_a->htype == BM_VERT) && (ele_b->htype == BM_VERT)) {
1300  1) &&
1302  1)) {
1303  return true;
1304  }
1305  }
1306 
1307  return false;
1308 }
1309 
1310 static bool bm_vert_connect_pair(BMesh *bm, BMVert *v_a, BMVert *v_b)
1311 {
1312  BMOperator bmop;
1313  BMVert **verts;
1314  const int totedge_orig = bm->totedge;
1315 
1316  BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, "connect_vert_pair");
1317 
1318  verts = BMO_slot_buffer_alloc(&bmop, bmop.slots_in, "verts", 2);
1319  verts[0] = v_a;
1320  verts[1] = v_b;
1321 
1324 
1325  BMO_op_exec(bm, &bmop);
1326  BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
1327  BMO_op_finish(bm, &bmop);
1328  return (bm->totedge != totedge_orig);
1329 }
1330 
1332 {
1333  /* Logic is as follows:
1334  *
1335  * - If there are any isolated/wire verts - connect as edges.
1336  * - Otherwise connect faces.
1337  * - If all edges have been created already, closed the loop.
1338  */
1339  if (BLI_listbase_count_at_most(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) {
1340  BMEditSelection *ese;
1341  int tot = 0;
1342  bool changed = false;
1343  bool has_wire = false;
1344  // bool all_verts;
1345 
1346  /* ensure all verts have history */
1347  for (ese = bm->selected.first; ese; ese = ese->next, tot++) {
1348  BMVert *v;
1349  if (ese->htype != BM_VERT) {
1350  break;
1351  }
1352  v = (BMVert *)ese->ele;
1353  if ((has_wire == false) && ((v->e == NULL) || BM_vert_is_wire(v))) {
1354  has_wire = true;
1355  }
1356  }
1357  // all_verts = (ese == NULL);
1358 
1359  if (has_wire == false) {
1360  /* all verts have faces , connect verts via faces! */
1361  if (tot == bm->totvertsel) {
1362  BMEditSelection *ese_last;
1363  ese_last = bm->selected.first;
1364  ese = ese_last->next;
1365 
1366  do {
1367 
1368  if (BM_edge_exists((BMVert *)ese_last->ele, (BMVert *)ese->ele)) {
1369  /* pass, edge exists (and will be selected) */
1370  }
1371  else {
1372  changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele);
1373  }
1374  } while ((void)(ese_last = ese), (ese = ese->next));
1375 
1376  if (changed) {
1377  return true;
1378  }
1379  }
1380 
1381  if (changed == false) {
1382  /* existing loops: close the selection */
1384  changed |= bm_vert_connect_pair(bm,
1385  (BMVert *)((BMEditSelection *)bm->selected.first)->ele,
1386  (BMVert *)((BMEditSelection *)bm->selected.last)->ele);
1387 
1388  if (changed) {
1389  return true;
1390  }
1391  }
1392  }
1393  }
1394 
1395  else {
1396  /* no faces, simply connect the verts by edges */
1397  BMEditSelection *ese_prev;
1398  ese_prev = bm->selected.first;
1399  ese = ese_prev->next;
1400 
1401  do {
1402  if (BM_edge_exists((BMVert *)ese_prev->ele, (BMVert *)ese->ele)) {
1403  /* pass, edge exists (and will be selected) */
1404  }
1405  else {
1406  BMEdge *e;
1407  e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
1408  BM_edge_select_set(bm, e, true);
1409  changed = true;
1410  }
1411  } while ((void)(ese_prev = ese), (ese = ese->next));
1412 
1413  if (changed == false) {
1414  /* existing loops: close the selection */
1416  BMEdge *e;
1417  ese_prev = bm->selected.first;
1418  ese = bm->selected.last;
1419  e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
1420  BM_edge_select_set(bm, e, true);
1421  }
1422  }
1423 
1424  return true;
1425  }
1426  }
1427 
1428  return false;
1429 }
1430 
1436 {
1437  ListBase selected_orig = {NULL, NULL};
1438  BMEditSelection *ese;
1439  int edges_len = 0;
1440  bool side = false;
1441 
1442  /* first check all edges are OK */
1443  for (ese = bm->selected.first; ese; ese = ese->next) {
1444  if (ese->htype == BM_EDGE) {
1445  edges_len += 1;
1446  }
1447  else {
1448  return false;
1449  }
1450  }
1451  /* if this is a mixed selection, bail out! */
1452  if (bm->totedgesel != edges_len) {
1453  return false;
1454  }
1455 
1456  SWAP(ListBase, bm->selected, selected_orig);
1457 
1458  /* convert edge selection into 2 ordered loops (where the first edge ends up in the middle) */
1459  for (ese = selected_orig.first; ese; ese = ese->next) {
1460  BMEdge *e_curr = (BMEdge *)ese->ele;
1461  BMEdge *e_prev = ese->prev ? (BMEdge *)ese->prev->ele : NULL;
1462  BMLoop *l_curr;
1463  BMLoop *l_prev;
1464  BMVert *v;
1465 
1466  if (e_prev) {
1467  BMFace *f = BM_edge_pair_share_face_by_len(e_curr, e_prev, &l_curr, &l_prev, true);
1468  if (f) {
1469  if ((e_curr->v1 != l_curr->v) == (e_prev->v1 != l_prev->v)) {
1470  side = !side;
1471  }
1472  }
1473  else if (is_quad_flip_v3(e_curr->v1->co, e_curr->v2->co, e_prev->v2->co, e_prev->v1->co)) {
1474  side = !side;
1475  }
1476  }
1477 
1478  v = (&e_curr->v1)[side];
1479  if (!bm->selected.last || (BMVert *)((BMEditSelection *)bm->selected.last)->ele != v) {
1481  }
1482 
1483  v = (&e_curr->v1)[!side];
1484  if (!bm->selected.first || (BMVert *)((BMEditSelection *)bm->selected.first)->ele != v) {
1486  }
1487 
1488  e_prev = e_curr;
1489  }
1490 
1491  *r_selected = bm->selected;
1492  bm->selected = selected_orig;
1493 
1494  return true;
1495 }
1496 
1498 {
1499  ViewLayer *view_layer = CTX_data_view_layer(C);
1500  uint objects_len = 0;
1501  uint failed_selection_order_len = 0;
1502  uint failed_connect_len = 0;
1504  view_layer, CTX_wm_view3d(C), &objects_len);
1505 
1506  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1507  Object *obedit = objects[ob_index];
1508  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1509  BMesh *bm = em->bm;
1510  const bool is_pair = (em->bm->totvertsel == 2);
1511  ListBase selected_orig = {NULL, NULL};
1512 
1513  if (bm->totvertsel == 0) {
1514  continue;
1515  }
1516 
1517  /* when there is only 2 vertices, we can ignore selection order */
1518  if (is_pair) {
1519  if (!edbm_connect_vert_pair(em, obedit->data, op)) {
1520  failed_connect_len++;
1521  }
1522  continue;
1523  }
1524 
1525  if (bm->selected.first) {
1526  BMEditSelection *ese = bm->selected.first;
1527  if (ese->htype == BM_EDGE) {
1529  SWAP(ListBase, bm->selected, selected_orig);
1530  }
1531  }
1532  }
1533 
1535 
1538 
1540 
1541  EDBM_update_generic(obedit->data, true, true);
1542  }
1543  else {
1544  failed_selection_order_len++;
1545  }
1546 
1547  if (!BLI_listbase_is_empty(&selected_orig)) {
1549  bm->selected = selected_orig;
1550  }
1551  }
1552 
1553  MEM_freeN(objects);
1554 
1555  if (failed_selection_order_len == objects_len) {
1556  BKE_report(op->reports, RPT_ERROR, "Invalid selection order");
1557  return OPERATOR_CANCELLED;
1558  }
1559  if (failed_connect_len == objects_len) {
1560  BKE_report(op->reports, RPT_ERROR, "Could not connect vertices");
1561  return OPERATOR_CANCELLED;
1562  }
1563 
1564  return OPERATOR_FINISHED;
1565 }
1566 
1568 {
1569  /* identifiers */
1570  ot->name = "Vertex Connect Path";
1571  ot->idname = "MESH_OT_vert_connect_path";
1572  ot->description = "Connect vertices by their selection order, creating edges, splitting faces";
1573 
1574  /* api callbacks */
1577 
1578  /* flags */
1580 }
1581 
1584 /* -------------------------------------------------------------------- */
1589 {
1590  ViewLayer *view_layer = CTX_data_view_layer(C);
1591  uint objects_len = 0;
1593  view_layer, CTX_wm_view3d(C), &objects_len);
1594  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1595  Object *obedit = objects[ob_index];
1596  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1597 
1598  if (em->bm->totfacesel == 0) {
1599  continue;
1600  }
1601 
1603  em, op, "faces.out", true, "connect_verts_concave faces=%hf", BM_ELEM_SELECT)) {
1604  continue;
1605  }
1606  EDBM_update_generic(obedit->data, true, true);
1607  }
1608 
1609  MEM_freeN(objects);
1610  return OPERATOR_FINISHED;
1611 }
1612 
1614 {
1615  /* identifiers */
1616  ot->name = "Split Concave Faces";
1617  ot->idname = "MESH_OT_vert_connect_concave";
1618  ot->description = "Make all faces convex";
1619 
1620  /* api callbacks */
1623 
1624  /* flags */
1626 }
1627 
1630 /* -------------------------------------------------------------------- */
1635 {
1636  ViewLayer *view_layer = CTX_data_view_layer(C);
1637  const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
1638  uint objects_len = 0;
1640  view_layer, CTX_wm_view3d(C), &objects_len);
1641 
1642  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1643  Object *obedit = objects[ob_index];
1644  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1645 
1646  if (em->bm->totfacesel == 0) {
1647  continue;
1648  }
1649 
1650  if (!EDBM_op_call_and_selectf(em,
1651  op,
1652  "faces.out",
1653  true,
1654  "connect_verts_nonplanar faces=%hf angle_limit=%f",
1656  angle_limit)) {
1657  continue;
1658  }
1659 
1660  EDBM_update_generic(obedit->data, true, true);
1661  }
1662  MEM_freeN(objects);
1663 
1664  return OPERATOR_FINISHED;
1665 }
1666 
1668 {
1669  PropertyRNA *prop;
1670 
1671  /* identifiers */
1672  ot->name = "Split Non-Planar Faces";
1673  ot->idname = "MESH_OT_vert_connect_nonplanar";
1674  ot->description = "Split non-planar faces that exceed the angle threshold";
1675 
1676  /* api callbacks */
1679 
1680  /* flags */
1682 
1683  /* props */
1684  prop = RNA_def_float_rotation(ot->srna,
1685  "angle_limit",
1686  0,
1687  NULL,
1688  0.0f,
1689  DEG2RADF(180.0f),
1690  "Max Angle",
1691  "Angle limit",
1692  0.0f,
1693  DEG2RADF(180.0f));
1695 }
1696 
1699 /* -------------------------------------------------------------------- */
1704 {
1705  ViewLayer *view_layer = CTX_data_view_layer(C);
1706  uint objects_len = 0;
1708  view_layer, CTX_wm_view3d(C), &objects_len);
1709 
1710  const int repeat = RNA_int_get(op->ptr, "repeat");
1711  const float fac = RNA_float_get(op->ptr, "factor");
1712 
1713  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1714  Object *obedit = objects[ob_index];
1715  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1716  if (em->bm->totfacesel == 0) {
1717  continue;
1718  }
1719 
1720  if (!EDBM_op_callf(em,
1721  op,
1722  "planar_faces faces=%hf iterations=%i factor=%f",
1724  repeat,
1725  fac)) {
1726  continue;
1727  }
1728 
1729  EDBM_update_generic(obedit->data, true, true);
1730  }
1731  MEM_freeN(objects);
1732 
1733  return OPERATOR_FINISHED;
1734 }
1735 
1737 {
1738  /* identifiers */
1739  ot->name = "Make Planar Faces";
1740  ot->idname = "MESH_OT_face_make_planar";
1741  ot->description = "Flatten selected faces";
1742 
1743  /* api callbacks */
1746 
1747  /* flags */
1749 
1750  /* props */
1751  RNA_def_float(ot->srna, "factor", 1.0f, -10.0f, 10.0f, "Factor", "", 0.0f, 1.0f);
1752  RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
1753 }
1754 
1757 /* -------------------------------------------------------------------- */
1762 {
1763  BMesh *bm = em->bm;
1764  if (bm->totedgesel == 0) {
1765  return false;
1766  }
1767 
1769 
1771  em, op, "edges.out", false, "split_edges edges=%he", BM_ELEM_SELECT)) {
1772  return false;
1773  }
1774 
1776 
1777  EDBM_select_flush(em);
1778  EDBM_update_generic(obedit->data, true, true);
1779 
1780  return true;
1781 }
1782 
1784 {
1785  BMesh *bm = em->bm;
1786 
1787  /* Note that tracking vertices through the 'split_edges' operator is complicated.
1788  * Instead, tag loops for selection. */
1789  if (bm->totvertsel == 0) {
1790  return false;
1791  }
1792 
1794 
1795  /* Flush from vertices to edges. */
1796  BMIter iter;
1797  BMEdge *eed;
1798  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
1800  if (eed->l != NULL) {
1801  if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
1805  }
1806  /* Store selection in loop tags. */
1807  BMLoop *l_iter = eed->l;
1808  do {
1810  } while ((l_iter = l_iter->radial_next) != eed->l);
1811  }
1812  }
1813 
1814  if (!EDBM_op_callf(em,
1815  op,
1816  "split_edges edges=%he verts=%hv use_verts=%b",
1817  BM_ELEM_TAG,
1819  true)) {
1820  return false;
1821  }
1822 
1823  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1824  if (eed->l != NULL) {
1825  BMLoop *l_iter = eed->l;
1826  do {
1827  if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
1828  BM_vert_select_set(em->bm, l_iter->v, true);
1829  }
1830  } while ((l_iter = l_iter->radial_next) != eed->l);
1831  }
1832  else {
1833  /* Split out wire. */
1834  for (int i = 0; i < 2; i++) {
1835  BMVert *v = *(&eed->v1 + i);
1837  if (eed != BM_DISK_EDGE_NEXT(eed, v)) {
1838  BM_vert_separate(bm, v, &eed, 1, true, NULL, NULL);
1839  }
1840  }
1841  }
1842  }
1843  }
1844 
1846 
1847  EDBM_select_flush(em);
1848  EDBM_update_generic(obedit->data, true, true);
1849 
1850  return true;
1851 }
1852 
1854 {
1855  const int type = RNA_enum_get(op->ptr, "type");
1856 
1857  ViewLayer *view_layer = CTX_data_view_layer(C);
1858  uint objects_len = 0;
1860  view_layer, CTX_wm_view3d(C), &objects_len);
1861  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1862  Object *obedit = objects[ob_index];
1863  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1864 
1865  switch (type) {
1866  case BM_VERT:
1867  if (!edbm_edge_split_selected_verts(op, obedit, em)) {
1868  continue;
1869  }
1870  break;
1871  case BM_EDGE:
1872  if (!edbm_edge_split_selected_edges(op, obedit, em)) {
1873  continue;
1874  }
1875  break;
1876  default:
1877  BLI_assert(0);
1878  }
1879  }
1880  MEM_freeN(objects);
1881 
1882  return OPERATOR_FINISHED;
1883 }
1884 
1886 {
1887  /* identifiers */
1888  ot->name = "Edge Split";
1889  ot->idname = "MESH_OT_edge_split";
1890  ot->description = "Split selected edges so that each neighbor face gets its own copy";
1891 
1892  /* api callbacks */
1895 
1896  /* flags */
1898 
1899  /* properties */
1900  static const EnumPropertyItem merge_type_items[] = {
1901  {BM_EDGE, "EDGE", 0, "Faces by Edges", "Split faces along selected edges"},
1902  {BM_VERT,
1903  "VERT",
1904  0,
1905  "Faces & Edges by Vertices",
1906  "Split faces and edges connected to selected vertices"},
1907  {0, NULL, 0, NULL, NULL},
1908  };
1909 
1910  ot->prop = RNA_def_enum(
1911  ot->srna, "type", merge_type_items, BM_EDGE, "Type", "Method to use for splitting");
1912 }
1913 
1916 /* -------------------------------------------------------------------- */
1921 {
1922  ViewLayer *view_layer = CTX_data_view_layer(C);
1923  uint objects_len = 0;
1925  view_layer, CTX_wm_view3d(C), &objects_len);
1926 
1927  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1928  Object *obedit = objects[ob_index];
1929  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1930  if (em->bm->totvertsel == 0) {
1931  continue;
1932  }
1933 
1934  BMOperator bmop;
1935  BMesh *bm = em->bm;
1936 
1937  EDBM_op_init(em,
1938  &bmop,
1939  op,
1940  "duplicate geom=%hvef use_select_history=%b use_edge_flip_from_face=%b",
1942  true,
1943  true);
1944 
1945  BMO_op_exec(bm, &bmop);
1946 
1947  /* de-select all would clear otherwise */
1949 
1951 
1953  bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
1954 
1955  /* rebuild editselection */
1957 
1958  if (!EDBM_op_finish(em, &bmop, op, true)) {
1959  continue;
1960  }
1961  EDBM_update_generic(obedit->data, true, true);
1962  }
1963  MEM_freeN(objects);
1964 
1965  return OPERATOR_FINISHED;
1966 }
1967 
1968 static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1969 {
1970  WM_cursor_wait(true);
1971  edbm_duplicate_exec(C, op);
1972  WM_cursor_wait(false);
1973 
1974  return OPERATOR_FINISHED;
1975 }
1976 
1978 {
1979  /* identifiers */
1980  ot->name = "Duplicate";
1981  ot->description = "Duplicate selected vertices, edges or faces";
1982  ot->idname = "MESH_OT_duplicate";
1983 
1984  /* api callbacks */
1987 
1989 
1990  /* to give to transform */
1991  RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
1992 }
1993 
1995 {
1996  BMLoopNorEditDataArray *lnors_ed_arr = NULL;
1998  /* The mesh has custom normal data, update these too.
1999  * Otherwise they will be left in a mangled state.
2000  */
2002  lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, true);
2003  }
2004 
2005  return lnors_ed_arr;
2006 }
2007 
2009 {
2010  if (!lnors_ed_arr) {
2011  return false;
2012  }
2013 
2014  if (lnors_ed_arr->totloop == 0) {
2015  /* No loops normals to flip, exit early! */
2016  return false;
2017  }
2018 
2021 
2022  /* We need to recreate the custom normal array because the clnors_data will
2023  * be mangled because we swapped the loops around when we flipped the faces. */
2024  BMLoopNorEditDataArray *lnors_ed_arr_new_full = BM_loop_normal_editdata_array_init(bm, true);
2025 
2026  {
2027  /* We need to recalculate all loop normals in the affected area. Even the ones that are not
2028  * going to be flipped because the clnors data is mangled. */
2029 
2030  BMLoopNorEditData *lnor_ed_new_full = lnors_ed_arr_new_full->lnor_editdata;
2031  for (int i = 0; i < lnors_ed_arr_new_full->totloop; i++, lnor_ed_new_full++) {
2032 
2033  BMLoopNorEditData *lnor_ed =
2034  lnors_ed_arr->lidx_to_lnor_editdata[lnor_ed_new_full->loop_index];
2035 
2036  BLI_assert(lnor_ed != NULL);
2037 
2039  bm->lnor_spacearr->lspacearr[lnor_ed_new_full->loop_index],
2040  lnor_ed->nloc,
2041  lnor_ed_new_full->clnors_data);
2042  }
2043  }
2044 
2045  BMFace *f;
2046  BMLoop *l, *l_start;
2047  BMIter iter_f;
2048  BM_ITER_MESH (f, &iter_f, bm, BM_FACES_OF_MESH) {
2049  /* Flip all the custom loop normals on the selected faces. */
2050  if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
2051  continue;
2052  }
2053 
2054  /* Because the winding has changed, we need to go the reverse way around the face to get the
2055  * correct placement of the normals. However we need to derive the old loop index to get the
2056  * correct data. Note that the first loop index is the same though. So the loop starts and ends
2057  * in the same place as before the flip.
2058  */
2059 
2060  l_start = l = BM_FACE_FIRST_LOOP(f);
2061  int old_index = BM_elem_index_get(l);
2062  do {
2063  int loop_index = BM_elem_index_get(l);
2064 
2065  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lidx_to_lnor_editdata[old_index];
2066  BMLoopNorEditData *lnor_ed_new = lnors_ed_arr_new_full->lidx_to_lnor_editdata[loop_index];
2067  BLI_assert(lnor_ed != NULL && lnor_ed_new != NULL);
2068 
2069  negate_v3(lnor_ed->nloc);
2070 
2072  bm->lnor_spacearr->lspacearr[loop_index], lnor_ed->nloc, lnor_ed_new->clnors_data);
2073 
2074  old_index++;
2075  l = l->prev;
2076  } while (l != l_start);
2077  }
2078  BM_loop_normal_editdata_array_free(lnors_ed_arr_new_full);
2079  return true;
2080 }
2081 
2084 /* -------------------------------------------------------------------- */
2088 {
2089  const bool only_clnors = RNA_boolean_get(op->ptr, "only_clnors");
2090 
2091  ViewLayer *view_layer = CTX_data_view_layer(C);
2092  uint objects_len = 0;
2094  view_layer, CTX_wm_view3d(C), &objects_len);
2095 
2096  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2097  Object *obedit = objects[ob_index];
2098  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2099 
2100  if (only_clnors) {
2102  /* The mesh has custom normal data, flip them. */
2103  BMesh *bm = em->bm;
2104 
2107  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
2108 
2109  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
2110  negate_v3(lnor_ed->nloc);
2111 
2113  lnor_ed->nloc,
2114  lnor_ed->clnors_data);
2115  }
2116  BM_loop_normal_editdata_array_free(lnors_ed_arr);
2117  EDBM_update_generic(obedit->data, true, false);
2118  }
2119  continue;
2120  }
2121 
2122  if (em->bm->totfacesel == 0) {
2123  continue;
2124  }
2125 
2126  bool has_flipped_faces = false;
2127 
2128  /* See if we have any custom normals to flip. */
2130 
2131  if (EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) {
2132  has_flipped_faces = true;
2133  }
2134 
2135  if (flip_custom_normals(em->bm, lnors_ed_arr) || has_flipped_faces) {
2136  EDBM_update_generic(obedit->data, true, false);
2137  }
2138 
2139  if (lnors_ed_arr != NULL) {
2140  BM_loop_normal_editdata_array_free(lnors_ed_arr);
2141  }
2142  }
2143 
2144  MEM_freeN(objects);
2145  return OPERATOR_FINISHED;
2146 }
2147 
2149 {
2150  /* identifiers */
2151  ot->name = "Flip Normals";
2152  ot->description = "Flip the direction of selected faces' normals (and of their vertices)";
2153  ot->idname = "MESH_OT_flip_normals";
2154 
2155  /* api callbacks */
2158 
2159  /* flags */
2161 
2163  "only_clnors",
2164  false,
2165  "Custom Normals Only",
2166  "Only flip the custom loop normals of the selected elements");
2167 }
2168 
2171 /* -------------------------------------------------------------------- */
2179 {
2180  BMEdge *eed;
2181  BMIter iter;
2182  const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
2183 
2184  int tot_rotate_all = 0, tot_failed_all = 0;
2185  bool no_selected_edges = true, invalid_selected_edges = true;
2186 
2187  ViewLayer *view_layer = CTX_data_view_layer(C);
2188  uint objects_len = 0;
2190  view_layer, CTX_wm_view3d(C), &objects_len);
2191  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2192  Object *obedit = objects[ob_index];
2193  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2194  int tot = 0;
2195 
2196  if (em->bm->totedgesel == 0) {
2197  continue;
2198  }
2199  no_selected_edges = false;
2200 
2201  /* first see if we have two adjacent faces */
2202  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2204  if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2205  BMFace *fa, *fb;
2206  if (BM_edge_face_pair(eed, &fa, &fb)) {
2207  /* if both faces are selected we rotate between them,
2208  * otherwise - rotate between 2 unselected - but not mixed */
2211  tot++;
2212  }
2213  }
2214  }
2215  }
2216 
2217  /* ok, we don't have two adjacent faces, but we do have two selected ones.
2218  * that's an error condition.*/
2219  if (tot == 0) {
2220  continue;
2221  }
2222  invalid_selected_edges = false;
2223 
2224  BMOperator bmop;
2225  EDBM_op_init(em, &bmop, op, "rotate_edges edges=%he use_ccw=%b", BM_ELEM_TAG, use_ccw);
2226 
2227  /* avoids leaving old verts selected which can be a problem running multiple times,
2228  * since this means the edges become selected around the face
2229  * which then attempt to rotate */
2230  BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "edges", BM_EDGE, BM_ELEM_SELECT, true);
2231 
2232  BMO_op_exec(em->bm, &bmop);
2233  /* edges may rotate into hidden vertices, if this does _not_ run we get an illogical state */
2235  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true);
2237  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
2238 
2239  const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out");
2240  const int tot_failed = tot - tot_rotate;
2241 
2242  tot_rotate_all += tot_rotate;
2243  tot_failed_all += tot_failed;
2244 
2245  if (tot_failed != 0) {
2246  /* If some edges fail to rotate, we need to re-select them,
2247  * otherwise we can end up with invalid selection
2248  * (unselected edge between 2 selected faces). */
2250  }
2251 
2253 
2254  if (!EDBM_op_finish(em, &bmop, op, true)) {
2255  continue;
2256  }
2257 
2258  EDBM_update_generic(obedit->data, true, true);
2259  }
2260  MEM_freeN(objects);
2261 
2262  if (no_selected_edges) {
2263  BKE_report(
2264  op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about");
2265  return OPERATOR_CANCELLED;
2266  }
2267 
2268  /* Ok, we don't have two adjacent faces, but we do have two selected ones.
2269  * that's an error condition. */
2270  if (invalid_selected_edges) {
2271  BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated");
2272  return OPERATOR_CANCELLED;
2273  }
2274 
2275  if (tot_failed_all != 0) {
2276  BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all);
2277  }
2278 
2279  return OPERATOR_FINISHED;
2280 }
2281 
2283 {
2284  /* identifiers */
2285  ot->name = "Rotate Selected Edge";
2286  ot->description = "Rotate selected edge or adjoining faces";
2287  ot->idname = "MESH_OT_edge_rotate";
2288 
2289  /* api callbacks */
2292 
2293  /* flags */
2295 
2296  /* props */
2297  RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
2298 }
2299 
2302 /* -------------------------------------------------------------------- */
2307 {
2308  const bool unselected = RNA_boolean_get(op->ptr, "unselected");
2309  ViewLayer *view_layer = CTX_data_view_layer(C);
2310  bool changed = false;
2311 
2312  uint objects_len = 0;
2314  view_layer, CTX_wm_view3d(C), &objects_len);
2315  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2316  Object *obedit = objects[ob_index];
2317  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2318  BMesh *bm = em->bm;
2319 
2320  if (unselected) {
2321  if (em->selectmode & SCE_SELECT_VERTEX) {
2322  if (bm->totvertsel == bm->totvert) {
2323  continue;
2324  }
2325  }
2326  else if (em->selectmode & SCE_SELECT_EDGE) {
2327  if (bm->totedgesel == bm->totedge) {
2328  continue;
2329  }
2330  }
2331  else if (em->selectmode & SCE_SELECT_FACE) {
2332  if (bm->totfacesel == bm->totface) {
2333  continue;
2334  }
2335  }
2336  }
2337  else {
2338  if (bm->totvertsel == 0) {
2339  continue;
2340  }
2341  }
2342 
2343  if (EDBM_mesh_hide(em, unselected)) {
2344  EDBM_update_generic(obedit->data, true, false);
2345  changed = true;
2346  }
2347  }
2348  MEM_freeN(objects);
2349 
2350  if (!changed) {
2351  return OPERATOR_CANCELLED;
2352  }
2353 
2354  return OPERATOR_FINISHED;
2355 }
2356 
2358 {
2359  /* identifiers */
2360  ot->name = "Hide Selected";
2361  ot->idname = "MESH_OT_hide";
2362  ot->description = "Hide (un)selected vertices, edges or faces";
2363 
2364  /* api callbacks */
2365  ot->exec = edbm_hide_exec;
2367 
2368  /* flags */
2370 
2371  /* props */
2373  ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
2374 }
2375 
2378 /* -------------------------------------------------------------------- */
2383 {
2384  const bool select = RNA_boolean_get(op->ptr, "select");
2385  ViewLayer *view_layer = CTX_data_view_layer(C);
2386 
2387  uint objects_len = 0;
2389  view_layer, CTX_wm_view3d(C), &objects_len);
2390  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2391  Object *obedit = objects[ob_index];
2392  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2393 
2394  if (EDBM_mesh_reveal(em, select)) {
2395  EDBM_update_generic(obedit->data, true, false);
2396  }
2397  }
2398  MEM_freeN(objects);
2399 
2400  return OPERATOR_FINISHED;
2401 }
2402 
2404 {
2405  /* identifiers */
2406  ot->name = "Reveal Hidden";
2407  ot->idname = "MESH_OT_reveal";
2408  ot->description = "Reveal all hidden vertices, edges and faces";
2409 
2410  /* api callbacks */
2413 
2414  /* flags */
2416 
2417  RNA_def_boolean(ot->srna, "select", true, "Select", "");
2418 }
2419 
2422 /* -------------------------------------------------------------------- */
2427 {
2428  ViewLayer *view_layer = CTX_data_view_layer(C);
2429  const bool inside = RNA_boolean_get(op->ptr, "inside");
2430 
2431  uint objects_len = 0;
2433  view_layer, CTX_wm_view3d(C), &objects_len);
2434  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2435  Object *obedit = objects[ob_index];
2436  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2437 
2438  if (em->bm->totfacesel == 0) {
2439  continue;
2440  }
2441 
2442  BMLoopNorEditDataArray *lnors_ed_arr = NULL;
2443 
2444  if (inside) {
2445  /* Save custom normal data for later so we can flip them correctly. */
2446  lnors_ed_arr = flip_custom_normals_init_data(em->bm);
2447  }
2448 
2449  if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) {
2450  continue;
2451  }
2452 
2453  if (inside) {
2454  EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
2455  flip_custom_normals(em->bm, lnors_ed_arr);
2456  if (lnors_ed_arr != NULL) {
2457  BM_loop_normal_editdata_array_free(lnors_ed_arr);
2458  }
2459  }
2460 
2461  EDBM_update_generic(obedit->data, true, false);
2462  }
2463  MEM_freeN(objects);
2464 
2465  return OPERATOR_FINISHED;
2466 }
2467 
2469 {
2470  /* identifiers */
2471  ot->name = "Recalculate Normals";
2472  ot->description = "Make face and vertex normals point either outside or inside the mesh";
2473  ot->idname = "MESH_OT_normals_make_consistent";
2474 
2475  /* api callbacks */
2478 
2479  /* flags */
2481 
2482  RNA_def_boolean(ot->srna, "inside", false, "Inside", "");
2483 }
2484 
2487 /* -------------------------------------------------------------------- */
2492 {
2493  const float fac = RNA_float_get(op->ptr, "factor");
2494 
2495  const bool xaxis = RNA_boolean_get(op->ptr, "xaxis");
2496  const bool yaxis = RNA_boolean_get(op->ptr, "yaxis");
2497  const bool zaxis = RNA_boolean_get(op->ptr, "zaxis");
2498  int repeat = RNA_int_get(op->ptr, "repeat");
2499 
2500  if (!repeat) {
2501  repeat = 1;
2502  }
2503 
2504  ViewLayer *view_layer = CTX_data_view_layer(C);
2505  uint objects_len = 0;
2507  view_layer, CTX_wm_view3d(C), &objects_len);
2508  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2509  Object *obedit = objects[ob_index];
2510  Mesh *me = obedit->data;
2511  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2512  bool mirrx = false, mirry = false, mirrz = false;
2513  float clip_dist = 0.0f;
2514  const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
2515 
2516  if (em->bm->totvertsel == 0) {
2517  continue;
2518  }
2519 
2520  /* mirror before smooth */
2521  if (((Mesh *)obedit->data)->symmetry & ME_SYMMETRY_X) {
2522  EDBM_verts_mirror_cache_begin(em, 0, false, true, false, use_topology);
2523  }
2524 
2525  /* if there is a mirror modifier with clipping, flag the verts that
2526  * are within tolerance of the plane(s) of reflection
2527  */
2528  LISTBASE_FOREACH (ModifierData *, md, &obedit->modifiers) {
2529  if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
2531 
2532  if (mmd->flag & MOD_MIR_CLIPPING) {
2533  if (mmd->flag & MOD_MIR_AXIS_X) {
2534  mirrx = true;
2535  }
2536  if (mmd->flag & MOD_MIR_AXIS_Y) {
2537  mirry = true;
2538  }
2539  if (mmd->flag & MOD_MIR_AXIS_Z) {
2540  mirrz = true;
2541  }
2542 
2543  clip_dist = mmd->tolerance;
2544  }
2545  }
2546  }
2547 
2548  for (int i = 0; i < repeat; i++) {
2549  if (!EDBM_op_callf(
2550  em,
2551  op,
2552  "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
2553  "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
2555  fac,
2556  mirrx,
2557  mirry,
2558  mirrz,
2559  clip_dist,
2560  xaxis,
2561  yaxis,
2562  zaxis)) {
2563  continue;
2564  }
2565  }
2566 
2567  /* apply mirror */
2568  if (((Mesh *)obedit->data)->symmetry & ME_SYMMETRY_X) {
2571  }
2572 
2573  EDBM_update_generic(obedit->data, true, false);
2574  }
2575  MEM_freeN(objects);
2576 
2577  return OPERATOR_FINISHED;
2578 }
2579 
2581 {
2582  /* identifiers */
2583  ot->name = "Smooth Vertices";
2584  ot->description = "Flatten angles of selected vertices";
2585  ot->idname = "MESH_OT_vertices_smooth";
2586 
2587  /* api callbacks */
2590 
2591  /* flags */
2593 
2595  ot->srna, "factor", 0.0f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
2596  RNA_def_int(
2597  ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100);
2598 
2600 
2601  RNA_def_boolean(ot->srna, "xaxis", true, "X-Axis", "Smooth along the X axis");
2602  RNA_def_boolean(ot->srna, "yaxis", true, "Y-Axis", "Smooth along the Y axis");
2603  RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis");
2604 
2605  /* Set generic modal callbacks. */
2607 }
2608 
2611 /* -------------------------------------------------------------------- */
2616 {
2617  BMIter fiter;
2618  BMFace *f;
2619  int tot_invalid = 0;
2620  int tot_unselected = 0;
2621  ViewLayer *view_layer = CTX_data_view_layer(C);
2622 
2623  const float lambda_factor = RNA_float_get(op->ptr, "lambda_factor");
2624  const float lambda_border = RNA_float_get(op->ptr, "lambda_border");
2625  const bool usex = RNA_boolean_get(op->ptr, "use_x");
2626  const bool usey = RNA_boolean_get(op->ptr, "use_y");
2627  const bool usez = RNA_boolean_get(op->ptr, "use_z");
2628  const bool preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume");
2629  int repeat = RNA_int_get(op->ptr, "repeat");
2630 
2631  if (!repeat) {
2632  repeat = 1;
2633  }
2634 
2635  uint objects_len = 0;
2637  view_layer, CTX_wm_view3d(C), &objects_len);
2638  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2639  Object *obedit = objects[ob_index];
2640  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2641  Mesh *me = obedit->data;
2642  bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
2643 
2644  if (em->bm->totvertsel == 0) {
2645  tot_unselected++;
2646  tot_invalid++;
2647  continue;
2648  }
2649 
2650  bool is_invalid = false;
2651  /* Check if select faces are triangles. */
2652  BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) {
2654  if (f->len > 4) {
2655  tot_invalid++;
2656  is_invalid = true;
2657  break;
2658  }
2659  }
2660  }
2661  if (is_invalid) {
2662  continue;
2663  }
2664 
2665  /* Mirror before smooth. */
2666  if (((Mesh *)obedit->data)->symmetry & ME_SYMMETRY_X) {
2667  EDBM_verts_mirror_cache_begin(em, 0, false, true, false, use_topology);
2668  }
2669 
2670  bool failed_repeat_loop = false;
2671  for (int i = 0; i < repeat; i++) {
2672  if (!EDBM_op_callf(em,
2673  op,
2674  "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f "
2675  "use_x=%b use_y=%b use_z=%b preserve_volume=%b",
2677  lambda_factor,
2678  lambda_border,
2679  usex,
2680  usey,
2681  usez,
2682  preserve_volume)) {
2683  failed_repeat_loop = true;
2684  break;
2685  }
2686  }
2687  if (failed_repeat_loop) {
2688  continue;
2689  }
2690 
2691  /* Apply mirror. */
2692  if (((Mesh *)obedit->data)->symmetry & ME_SYMMETRY_X) {
2695  }
2696 
2697  EDBM_update_generic(obedit->data, true, false);
2698  }
2699  MEM_freeN(objects);
2700 
2701  if (tot_unselected == objects_len) {
2702  BKE_report(op->reports, RPT_WARNING, "No selected vertex");
2703  return OPERATOR_CANCELLED;
2704  }
2705  if (tot_invalid == objects_len) {
2706  BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads");
2707  return OPERATOR_CANCELLED;
2708  }
2709 
2710  return OPERATOR_FINISHED;
2711 }
2712 
2714 {
2715  /* identifiers */
2716  ot->name = "Laplacian Smooth Vertices";
2717  ot->description = "Laplacian smooth of selected vertices";
2718  ot->idname = "MESH_OT_vertices_smooth_laplacian";
2719 
2720  /* api callbacks */
2723 
2724  /* flags */
2726 
2727  RNA_def_int(
2728  ot->srna, "repeat", 1, 1, 1000, "Number of iterations to smooth the mesh", "", 1, 200);
2729  RNA_def_float(
2730  ot->srna, "lambda_factor", 1.0f, 1e-7f, 1000.0f, "Lambda factor", "", 1e-7f, 1000.0f);
2732  "lambda_border",
2733  5e-5f,
2734  1e-7f,
2735  1000.0f,
2736  "Lambda factor in border",
2737  "",
2738  1e-7f,
2739  1000.0f);
2740 
2742 
2743  RNA_def_boolean(ot->srna, "use_x", true, "Smooth X Axis", "Smooth object along X axis");
2744  RNA_def_boolean(ot->srna, "use_y", true, "Smooth Y Axis", "Smooth object along Y axis");
2745  RNA_def_boolean(ot->srna, "use_z", true, "Smooth Z Axis", "Smooth object along Z axis");
2747  "preserve_volume",
2748  true,
2749  "Preserve Volume",
2750  "Apply volume preservation after smooth");
2751 }
2752 
2755 /* -------------------------------------------------------------------- */
2759 static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
2760 {
2761  BMIter iter;
2762  BMFace *efa;
2763 
2764  if (em == NULL) {
2765  return;
2766  }
2767 
2768  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2769  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2771  }
2772  }
2773 }
2774 
2776 {
2777  ViewLayer *view_layer = CTX_data_view_layer(C);
2778  uint objects_len = 0;
2780  view_layer, CTX_wm_view3d(C), &objects_len);
2781  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2782  Object *obedit = objects[ob_index];
2783  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2784 
2785  if (em->bm->totfacesel == 0) {
2786  continue;
2787  }
2788 
2789  mesh_set_smooth_faces(em, 1);
2790  EDBM_update_generic(obedit->data, false, false);
2791  }
2792  MEM_freeN(objects);
2793 
2794  return OPERATOR_FINISHED;
2795 }
2796 
2798 {
2799  /* identifiers */
2800  ot->name = "Shade Smooth";
2801  ot->description = "Display faces smooth (using vertex normals)";
2802  ot->idname = "MESH_OT_faces_shade_smooth";
2803 
2804  /* api callbacks */
2807 
2808  /* flags */
2810 }
2811 
2814 /* -------------------------------------------------------------------- */
2819 {
2820  ViewLayer *view_layer = CTX_data_view_layer(C);
2821  uint objects_len = 0;
2823  view_layer, CTX_wm_view3d(C), &objects_len);
2824  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2825  Object *obedit = objects[ob_index];
2826  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2827 
2828  if (em->bm->totfacesel == 0) {
2829  continue;
2830  }
2831 
2832  mesh_set_smooth_faces(em, 0);
2833  EDBM_update_generic(obedit->data, false, false);
2834  }
2835  MEM_freeN(objects);
2836 
2837  return OPERATOR_FINISHED;
2838 }
2839 
2841 {
2842  /* identifiers */
2843  ot->name = "Shade Flat";
2844  ot->description = "Display faces flat";
2845  ot->idname = "MESH_OT_faces_shade_flat";
2846 
2847  /* api callbacks */
2850 
2851  /* flags */
2853 }
2854 
2857 /* -------------------------------------------------------------------- */
2862 {
2863  /* get the direction from RNA */
2864  const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
2865 
2866  ViewLayer *view_layer = CTX_data_view_layer(C);
2867  uint objects_len = 0;
2869  view_layer, CTX_wm_view3d(C), &objects_len);
2870  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2871  Object *obedit = objects[ob_index];
2872  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2873 
2874  if (em->bm->totfacesel == 0) {
2875  continue;
2876  }
2877 
2878  BMOperator bmop;
2879 
2880  /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2881  EDBM_op_init(em, &bmop, op, "rotate_uvs faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
2882 
2883  /* execute the operator */
2884  BMO_op_exec(em->bm, &bmop);
2885 
2886  if (!EDBM_op_finish(em, &bmop, op, true)) {
2887  continue;
2888  }
2889 
2890  EDBM_update_generic(obedit->data, false, false);
2891  }
2892 
2893  MEM_freeN(objects);
2894  return OPERATOR_FINISHED;
2895 }
2896 
2898 {
2899  ViewLayer *view_layer = CTX_data_view_layer(C);
2900  uint objects_len = 0;
2902  view_layer, CTX_wm_view3d(C), &objects_len);
2903  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2904  Object *obedit = objects[ob_index];
2905  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2906 
2907  if (em->bm->totfacesel == 0) {
2908  continue;
2909  }
2910 
2911  BMOperator bmop;
2912 
2913  /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2914  EDBM_op_init(em, &bmop, op, "reverse_uvs faces=%hf", BM_ELEM_SELECT);
2915 
2916  /* execute the operator */
2917  BMO_op_exec(em->bm, &bmop);
2918 
2919  /* finish the operator */
2920  if (!EDBM_op_finish(em, &bmop, op, true)) {
2921  continue;
2922  }
2923  EDBM_update_generic(obedit->data, false, false);
2924  }
2925 
2926  MEM_freeN(objects);
2927  return OPERATOR_FINISHED;
2928 }
2929 
2931 {
2932  /* get the direction from RNA */
2933  const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
2934 
2935  ViewLayer *view_layer = CTX_data_view_layer(C);
2936  uint objects_len = 0;
2938  view_layer, CTX_wm_view3d(C), &objects_len);
2939 
2940  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2941  Object *ob = objects[ob_index];
2943  if (em->bm->totfacesel == 0) {
2944  continue;
2945  }
2946 
2947  BMOperator bmop;
2948 
2949  /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2950  EDBM_op_init(em, &bmop, op, "rotate_colors faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
2951 
2952  /* execute the operator */
2953  BMO_op_exec(em->bm, &bmop);
2954 
2955  /* finish the operator */
2956  if (!EDBM_op_finish(em, &bmop, op, true)) {
2957  continue;
2958  }
2959 
2960  /* dependencies graph and notification stuff */
2961  EDBM_update_generic(ob->data, false, false);
2962  }
2963 
2964  MEM_freeN(objects);
2965 
2966  return OPERATOR_FINISHED;
2967 }
2968 
2970 {
2971  ViewLayer *view_layer = CTX_data_view_layer(C);
2972  uint objects_len = 0;
2974  view_layer, CTX_wm_view3d(C), &objects_len);
2975 
2976  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2977  Object *obedit = objects[ob_index];
2978  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2979 
2980  if (em->bm->totfacesel == 0) {
2981  continue;
2982  }
2983 
2984  BMOperator bmop;
2985 
2986  /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2987  EDBM_op_init(em, &bmop, op, "reverse_colors faces=%hf", BM_ELEM_SELECT);
2988 
2989  /* execute the operator */
2990  BMO_op_exec(em->bm, &bmop);
2991 
2992  /* finish the operator */
2993  if (!EDBM_op_finish(em, &bmop, op, true)) {
2994  return OPERATOR_CANCELLED;
2995  }
2996 
2997  EDBM_update_generic(obedit->data, false, false);
2998  }
2999  MEM_freeN(objects);
3000 
3001  return OPERATOR_FINISHED;
3002 }
3003 
3005 {
3006  /* identifiers */
3007  ot->name = "Rotate UVs";
3008  ot->idname = "MESH_OT_uvs_rotate";
3009  ot->description = "Rotate UV coordinates inside faces";
3010 
3011  /* api callbacks */
3014 
3015  /* flags */
3017 
3018  /* props */
3019  RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
3020 }
3021 
3023 {
3024  /* identifiers */
3025  ot->name = "Reverse UVs";
3026  ot->idname = "MESH_OT_uvs_reverse";
3027  ot->description = "Flip direction of UV coordinates inside faces";
3028 
3029  /* api callbacks */
3032 
3033  /* flags */
3035 
3036  /* props */
3037  // RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around");
3038 }
3039 
3041 {
3042  /* identifiers */
3043  ot->name = "Rotate Colors";
3044  ot->idname = "MESH_OT_colors_rotate";
3045  ot->description = "Rotate vertex colors inside faces";
3046 
3047  /* api callbacks */
3050 
3051  /* flags */
3053 
3054  /* props */
3055  RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
3056 }
3057 
3059 {
3060  /* identifiers */
3061  ot->name = "Reverse Colors";
3062  ot->idname = "MESH_OT_colors_reverse";
3063  ot->description = "Flip direction of vertex colors inside faces";
3064 
3065  /* api callbacks */
3068 
3069  /* flags */
3071 
3072  /* props */
3073 #if 0
3074  RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around");
3075 #endif
3076 }
3077 
3080 /* -------------------------------------------------------------------- */
3084 enum {
3090 };
3091 
3092 static bool merge_firstlast(BMEditMesh *em,
3093  const bool use_first,
3094  const bool use_uvmerge,
3095  wmOperator *wmop)
3096 {
3097  BMVert *mergevert;
3098  BMEditSelection *ese;
3099 
3100  /* operator could be called directly from shortcut or python,
3101  * so do extra check for data here
3102  */
3103 
3104  /* While #merge_type_itemf does a sanity check, this operation runs on all edit-mode objects.
3105  * Some of them may not have the expected selection state. */
3106  if (use_first == false) {
3107  if (!em->bm->selected.last || ((BMEditSelection *)em->bm->selected.last)->htype != BM_VERT) {
3108  return false;
3109  }
3110 
3111  ese = em->bm->selected.last;
3112  mergevert = (BMVert *)ese->ele;
3113  }
3114  else {
3115  if (!em->bm->selected.first || ((BMEditSelection *)em->bm->selected.first)->htype != BM_VERT) {
3116  return false;
3117  }
3118 
3119  ese = em->bm->selected.first;
3120  mergevert = (BMVert *)ese->ele;
3121  }
3122 
3123  if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT)) {
3124  return false;
3125  }
3126 
3127  if (use_uvmerge) {
3128  if (!EDBM_op_callf(
3129  em, wmop, "pointmerge_facedata verts=%hv vert_snap=%e", BM_ELEM_SELECT, mergevert)) {
3130  return false;
3131  }
3132  }
3133 
3134  if (!EDBM_op_callf(
3135  em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, mergevert->co)) {
3136  return false;
3137  }
3138 
3139  return true;
3140 }
3141 
3142 static bool merge_target(BMEditMesh *em,
3143  Scene *scene,
3144  Object *ob,
3145  const bool use_cursor,
3146  const bool use_uvmerge,
3147  wmOperator *wmop)
3148 {
3149  BMIter iter;
3150  BMVert *v;
3151  float co[3], cent[3] = {0.0f, 0.0f, 0.0f};
3152  const float *vco = NULL;
3153 
3154  if (use_cursor) {
3155  vco = scene->cursor.location;
3156  copy_v3_v3(co, vco);
3157  invert_m4_m4(ob->imat, ob->obmat);
3158  mul_m4_v3(ob->imat, co);
3159  }
3160  else {
3161  float fac;
3162  int i = 0;
3163  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
3165  continue;
3166  }
3167  add_v3_v3(cent, v->co);
3168  i++;
3169  }
3170 
3171  if (!i) {
3172  return false;
3173  }
3174 
3175  fac = 1.0f / (float)i;
3176  mul_v3_fl(cent, fac);
3177  copy_v3_v3(co, cent);
3178  vco = co;
3179  }
3180 
3181  if (!vco) {
3182  return false;
3183  }
3184 
3185  if (use_uvmerge) {
3186  if (!EDBM_op_callf(em, wmop, "average_vert_facedata verts=%hv", BM_ELEM_SELECT)) {
3187  return false;
3188  }
3189  }
3190 
3191  if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, co)) {
3192  return false;
3193  }
3194 
3195  return true;
3196 }
3197 
3199 {
3201  ViewLayer *view_layer = CTX_data_view_layer(C);
3202  uint objects_len = 0;
3204  view_layer, CTX_wm_view3d(C), &objects_len);
3205  const int type = RNA_enum_get(op->ptr, "type");
3206  const bool uvs = RNA_boolean_get(op->ptr, "uvs");
3207 
3208  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3209  Object *obedit = objects[ob_index];
3210  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3211 
3212  if (em->bm->totvertsel == 0) {
3213  continue;
3214  }
3215 
3217 
3218  bool ok = false;
3219  switch (type) {
3220  case MESH_MERGE_CENTER:
3221  ok = merge_target(em, scene, obedit, false, uvs, op);
3222  break;
3223  case MESH_MERGE_CURSOR:
3224  ok = merge_target(em, scene, obedit, true, uvs, op);
3225  break;
3226  case MESH_MERGE_LAST:
3227  ok = merge_firstlast(em, false, uvs, op);
3228  break;
3229  case MESH_MERGE_FIRST:
3230  ok = merge_firstlast(em, true, uvs, op);
3231  break;
3232  case MESH_MERGE_COLLAPSE:
3233  ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs);
3234  break;
3235  default:
3236  BLI_assert(0);
3237  break;
3238  }
3239 
3240  if (!ok) {
3241  continue;
3242  }
3243 
3245 
3246  EDBM_update_generic(obedit->data, true, true);
3247 
3248  /* once collapsed, we can't have edge/face selection */
3249  if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
3251  }
3252  /* Only active object supported, see comment below. */
3254  break;
3255  }
3256  }
3257 
3258  MEM_freeN(objects);
3259 
3260  return OPERATOR_FINISHED;
3261 }
3262 
3264  {MESH_MERGE_CENTER, "CENTER", 0, "At Center", ""},
3265  {MESH_MERGE_CURSOR, "CURSOR", 0, "At Cursor", ""},
3266  {MESH_MERGE_COLLAPSE, "COLLAPSE", 0, "Collapse", ""},
3267  {MESH_MERGE_FIRST, "FIRST", 0, "At First", ""},
3268  {MESH_MERGE_LAST, "LAST", 0, "At Last", ""},
3269  {0, NULL, 0, NULL, NULL},
3270 };
3271 
3273  PointerRNA *UNUSED(ptr),
3274  PropertyRNA *UNUSED(prop),
3275  bool *r_free)
3276 {
3277  if (!C) { /* needed for docs */
3278  return merge_type_items;
3279  }
3280 
3281  Object *obedit = CTX_data_edit_object(C);
3282  if (obedit && obedit->type == OB_MESH) {
3283  EnumPropertyItem *item = NULL;
3284  int totitem = 0;
3285  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3286 
3287  /* Keep these first so that their automatic shortcuts don't change. */
3291 
3292  /* Only active object supported:
3293  * In practice it doesn't make sense to run this operation on non-active meshes
3294  * since selecting will activate - we could have own code-path for these but it's a hassle
3295  * for now just apply to the active (first) object. */
3296  if (em->selectmode & SCE_SELECT_VERTEX) {
3297  if (em->bm->selected.first && em->bm->selected.last &&
3298  ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT &&
3299  ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
3302  }
3303  else if (em->bm->selected.first &&
3304  ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) {
3306  }
3307  else if (em->bm->selected.last &&
3308  ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
3310  }
3311  }
3312 
3313  RNA_enum_item_end(&item, &totitem);
3314 
3315  *r_free = true;
3316 
3317  return item;
3318  }
3319 
3320  /* Get all items e.g. when creating keymap item. */
3321  return merge_type_items;
3322 }
3323 
3325 {
3326  /* identifiers */
3327  ot->name = "Merge";
3328  ot->description = "Merge selected vertices";
3329  ot->idname = "MESH_OT_merge";
3330 
3331  /* api callbacks */
3332  ot->exec = edbm_merge_exec;
3335 
3336  /* flags */
3338 
3339  /* properties */
3340  ot->prop = RNA_def_enum(
3341  ot->srna, "type", merge_type_items, MESH_MERGE_CENTER, "Type", "Merge method to use");
3343 
3345 
3346  RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge");
3347 }
3348 
3351 /* -------------------------------------------------------------------- */
3356 {
3357  const float threshold = RNA_float_get(op->ptr, "threshold");
3358  const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected");
3359  const bool use_sharp_edge_from_normals = RNA_boolean_get(op->ptr, "use_sharp_edge_from_normals");
3360 
3361  int count_multi = 0;
3362 
3363  ViewLayer *view_layer = CTX_data_view_layer(C);
3364  uint objects_len = 0;
3366  view_layer, CTX_wm_view3d(C), &objects_len);
3367 
3368  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3369  Object *obedit = objects[ob_index];
3370  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3371 
3372  /* Selection used as target with 'use_unselected'. */
3373  if (em->bm->totvertsel == 0) {
3374  continue;
3375  }
3376 
3377  BMOperator bmop;
3378  const int totvert_orig = em->bm->totvert;
3379 
3380  /* avoid losing selection state (select -> tags) */
3381  char htype_select;
3382  if (em->selectmode & SCE_SELECT_VERTEX) {
3383  htype_select = BM_VERT;
3384  }
3385  else if (em->selectmode & SCE_SELECT_EDGE) {
3386  htype_select = BM_EDGE;
3387  }
3388  else {
3389  htype_select = BM_FACE;
3390  }
3391 
3393 
3394  /* store selection as tags */
3395  BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT);
3396 
3397  if (use_unselected) {
3398  EDBM_automerge(obedit, false, BM_ELEM_SELECT, threshold);
3399  }
3400  else {
3401  EDBM_op_init(em, &bmop, op, "find_doubles verts=%hv dist=%f", BM_ELEM_SELECT, threshold);
3402 
3403  BMO_op_exec(em->bm, &bmop);
3404 
3405  if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) {
3406  BMO_op_finish(em->bm, &bmop);
3407  continue;
3408  }
3409 
3410  if (!EDBM_op_finish(em, &bmop, op, true)) {
3411  continue;
3412  }
3413  }
3414 
3415  const int count = (totvert_orig - em->bm->totvert);
3416 
3417  /* restore selection from tags */
3418  BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_SELECT, true, true, BM_ELEM_TAG);
3420 
3421  BM_custom_loop_normals_from_vector_layer(em->bm, use_sharp_edge_from_normals);
3422 
3423  if (count) {
3424  count_multi += count;
3425  EDBM_update_generic(obedit->data, true, true);
3426  }
3427  }
3428  MEM_freeN(objects);
3429 
3430  BKE_reportf(op->reports, RPT_INFO, "Removed %d vertice(s)", count_multi);
3431 
3432  return OPERATOR_FINISHED;
3433 }
3434 
3436 {
3437  /* identifiers */
3438  ot->name = "Merge by Distance";
3439  ot->description = "Merge vertices based on their proximity";
3440  ot->idname = "MESH_OT_remove_doubles";
3441 
3442  /* api callbacks */
3445 
3446  /* flags */
3448 
3450  "threshold",
3451  1e-4f,
3452  1e-6f,
3453  50.0f,
3454  "Merge Distance",
3455  "Maximum distance between elements to merge",
3456  1e-5f,
3457  10.0f);
3459  "use_unselected",
3460  false,
3461  "Unselected",
3462  "Merge selected to other unselected vertices");
3463 
3465  "use_sharp_edge_from_normals",
3466  false,
3467  "Sharp Edges",
3468  "Calculate sharp edges using custom normal data (when available)");
3469 }
3470 
3473 /* -------------------------------------------------------------------- */
3477 /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
3478 static bool shape_propagate(BMEditMesh *em)
3479 {
3480  BMIter iter;
3481  BMVert *eve = NULL;
3482  float *co;
3483  int totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
3484 
3485  if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
3486  return false;
3487  }
3488 
3489  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
3491  continue;
3492  }
3493 
3494  for (int i = 0; i < totshape; i++) {
3495  co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
3496  copy_v3_v3(co, eve->co);
3497  }
3498  }
3499  return true;
3500 }
3501 
3503 {
3504  ViewLayer *view_layer = CTX_data_view_layer(C);
3505  int tot_shapekeys = 0;
3506  int tot_selected_verts_objects = 0;
3507 
3508  uint objects_len = 0;
3510  view_layer, CTX_wm_view3d(C), &objects_len);
3511  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3512  Object *obedit = objects[ob_index];
3513  Mesh *me = obedit->data;
3514  BMEditMesh *em = me->edit_mesh;
3515 
3516  if (em->bm->totvertsel == 0) {
3517  continue;
3518  }
3519  tot_selected_verts_objects++;
3520 
3521  if (shape_propagate(em)) {
3522  tot_shapekeys++;
3523  }
3524 
3525  EDBM_update_generic(me, false, false);
3526  }
3527  MEM_freeN(objects);
3528 
3529  if (tot_selected_verts_objects == 0) {
3530  BKE_report(op->reports, RPT_ERROR, "No selected vertex");
3531  return OPERATOR_CANCELLED;
3532  }
3533  if (tot_shapekeys == 0) {
3534  BKE_report(op->reports,
3535  RPT_ERROR,
3536  objects_len > 1 ? "Meshes do not have shape keys" :
3537  "Mesh does not have shape keys");
3538  return OPERATOR_CANCELLED;
3539  }
3540 
3541  return OPERATOR_FINISHED;
3542 }
3543 
3545 {
3546  /* identifiers */
3547  ot->name = "Shape Propagate";
3548  ot->description = "Apply selected vertex locations to all other shape keys";
3549  ot->idname = "MESH_OT_shape_propagate_to_all";
3550 
3551  /* api callbacks */
3554 
3555  /* flags */
3557 }
3558 
3561 /* -------------------------------------------------------------------- */
3565 /* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
3567 {
3568  Object *obedit_ref = CTX_data_edit_object(C);
3569  Mesh *me_ref = obedit_ref->data;
3570  Key *key_ref = me_ref->key;
3571  KeyBlock *kb_ref = NULL;
3572  BMEditMesh *em_ref = me_ref->edit_mesh;
3573  BMVert *eve;
3574  BMIter iter;
3575  ViewLayer *view_layer = CTX_data_view_layer(C);
3576  float co[3], *sco;
3577  int totshape_ref = 0;
3578 
3579  const float blend = RNA_float_get(op->ptr, "blend");
3580  int shape_ref = RNA_enum_get(op->ptr, "shape");
3581  const bool use_add = RNA_boolean_get(op->ptr, "add");
3582 
3583  /* Sanity check. */
3584  totshape_ref = CustomData_number_of_layers(&em_ref->bm->vdata, CD_SHAPEKEY);
3585 
3586  if (totshape_ref == 0 || shape_ref < 0) {
3587  BKE_report(op->reports, RPT_ERROR, "Active mesh does not have shape keys");
3588  return OPERATOR_CANCELLED;
3589  }
3590  if (shape_ref >= totshape_ref) {
3591  /* This case occurs if operator was used before on object with more keys than current one. */
3592  shape_ref = 0; /* default to basis */
3593  }
3594 
3595  /* Get shape key - needed for finding reference shape (for add mode only). */
3596  if (key_ref) {
3597  kb_ref = BLI_findlink(&key_ref->block, shape_ref);
3598  }
3599 
3600  int tot_selected_verts_objects = 0;
3601  uint objects_len = 0;
3603  view_layer, CTX_wm_view3d(C), &objects_len);
3604  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3605  Object *obedit = objects[ob_index];
3606  Mesh *me = obedit->data;
3607  Key *key = me->key;
3608  KeyBlock *kb = NULL;
3609  BMEditMesh *em = me->edit_mesh;
3610  int shape;
3611 
3612  if (em->bm->totvertsel == 0) {
3613  continue;
3614  }
3615  tot_selected_verts_objects++;
3616 
3617  if (!key) {
3618  continue;
3619  }
3620  kb = BKE_keyblock_find_name(key, kb_ref->name);
3621  shape = BLI_findindex(&key->block, kb);
3622 
3623  if (kb) {
3624  /* Perform blending on selected vertices. */
3625  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
3627  continue;
3628  }
3629 
3630  /* Get coordinates of shapekey we're blending from. */
3631  sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
3632  copy_v3_v3(co, sco);
3633 
3634  if (use_add) {
3635  /* In add mode, we add relative shape key offset. */
3636  const float *rco = CustomData_bmesh_get_n(
3637  &em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative);
3638  sub_v3_v3v3(co, co, rco);
3639 
3640  madd_v3_v3fl(eve->co, co, blend);
3641  }
3642  else {
3643  /* In blend mode, we interpolate to the shape key. */
3644  interp_v3_v3v3(eve->co, eve->co, co, blend);
3645  }
3646  }
3647  EDBM_update_generic(me, true, false);
3648  }
3649  }
3650  MEM_freeN(objects);
3651 
3652  if (tot_selected_verts_objects == 0) {
3653  BKE_report(op->reports, RPT_ERROR, "No selected vertex");
3654  return OPERATOR_CANCELLED;
3655  }
3656 
3657  return OPERATOR_FINISHED;
3658 }
3659 
3661  PointerRNA *UNUSED(ptr),
3662  PropertyRNA *UNUSED(prop),
3663  bool *r_free)
3664 {
3665  Object *obedit = CTX_data_edit_object(C);
3666  BMEditMesh *em;
3667  EnumPropertyItem *item = NULL;
3668  int totitem = 0;
3669 
3670  if ((obedit && obedit->type == OB_MESH) && (em = BKE_editmesh_from_object(obedit)) &&
3672  EnumPropertyItem tmp = {0, "", 0, "", ""};
3673  int a;
3674 
3675  for (a = 0; a < em->bm->vdata.totlayer; a++) {
3676  if (em->bm->vdata.layers[a].type != CD_SHAPEKEY) {
3677  continue;
3678  }
3679 
3680  tmp.value = totitem;
3681  tmp.identifier = em->bm->vdata.layers[a].name;
3682  tmp.name = em->bm->vdata.layers[a].name;
3683  /* RNA_enum_item_add sets totitem itself! */
3684  RNA_enum_item_add(&item, &totitem, &tmp);
3685  }
3686  }
3687 
3688  RNA_enum_item_end(&item, &totitem);
3689  *r_free = true;
3690 
3691  return item;
3692 }
3693 
3695 {
3696  uiLayout *layout = op->layout;
3698  PointerRNA ptr;
3699  Object *obedit = CTX_data_edit_object(C);
3700  Mesh *me = obedit->data;
3701  PointerRNA ptr_key;
3702 
3703  RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
3704  RNA_id_pointer_create((ID *)me->key, &ptr_key);
3705 
3706  uiLayoutSetPropSep(layout, true);
3707  uiLayoutSetPropDecorate(layout, false);
3708 
3709  uiItemPointerR(layout, &ptr, "shape", &ptr_key, "key_blocks", NULL, ICON_SHAPEKEY_DATA);
3710  uiItemR(layout, &ptr, "blend", 0, NULL, ICON_NONE);
3711  uiItemR(layout, &ptr, "add", 0, NULL, ICON_NONE);
3712 }
3713 
3715 {
3716  PropertyRNA *prop;
3717 
3718  /* identifiers */
3719  ot->name = "Blend from Shape";
3720  ot->description = "Blend in shape from a shape key";
3721  ot->idname = "MESH_OT_blend_from_shape";
3722 
3723  /* api callbacks */
3725  /* disable because search popup closes too easily */
3726  // ot->invoke = WM_operator_props_popup_call;
3729 
3730  /* flags */
3732 
3733  /* properties */
3734  prop = RNA_def_enum(
3735  ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending");
3738  RNA_def_float(ot->srna, "blend", 1.0f, -1e3f, 1e3f, "Blend", "Blending factor", -2.0f, 2.0f);
3739  RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes");
3740 }
3741 
3744 /* -------------------------------------------------------------------- */
3749 {
3750  const float thickness = RNA_float_get(op->ptr, "thickness");
3751 
3752  ViewLayer *view_layer = CTX_data_view_layer(C);
3753  uint objects_len = 0;
3755  view_layer, CTX_wm_view3d(C), &objects_len);
3756  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3757  Object *obedit = objects[ob_index];
3758  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3759  BMesh *bm = em->bm;
3760 
3761  if (em->bm->totfacesel == 0) {
3762  continue;
3763  }
3764 
3765  BMOperator bmop;
3766 
3767  if (!EDBM_op_init(
3768  em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) {
3769  continue;
3770  }
3771 
3772  /* deselect only the faces in the region to be solidified (leave wire
3773  * edges and loose verts selected, as there will be no corresponding
3774  * geometry selected below) */
3776 
3777  /* run the solidify operator */
3778  BMO_op_exec(bm, &bmop);
3779 
3780  /* select the newly generated faces */
3781  BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
3782 
3783  if (!EDBM_op_finish(em, &bmop, op, true)) {
3784  continue;
3785  }
3786 
3787  EDBM_update_generic(obedit->data, true, true);
3788  }
3789 
3790  MEM_freeN(objects);
3791  return OPERATOR_FINISHED;
3792 }
3793 
3795 {
3796  PropertyRNA *prop;
3797  /* identifiers */
3798  ot->name = "Solidify";
3799  ot->description = "Create a solid skin by extruding, compensating for sharp angles";
3800  ot->idname = "MESH_OT_solidify";
3801 
3802  /* api callbacks */
3805 
3806  /* flags */
3808 
3809  prop = RNA_def_float_distance(
3810  ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f);
3811  RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4);
3812 }
3813 
3816 /* -------------------------------------------------------------------- */
3820 #define KNIFE_EXACT 1
3821 #define KNIFE_MIDPOINT 2
3822 #define KNIFE_MULTICUT 3
3823 
3824 static const EnumPropertyItem knife_items[] = {
3825  {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
3826  {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
3827  {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
3828  {0, NULL, 0, NULL, NULL},
3829 };
3830 
3831 /* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */
3832 
3833 static float bm_edge_seg_isect(const float sco_a[2],
3834  const float sco_b[2],
3835  float (*mouse_path)[2],
3836  int len,
3837  char mode,
3838  int *isected)
3839 {
3840 #define MAXSLOPE 100000
3841  float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max;
3842  float y2min, dist, lastdist = 0, xdiff2, xdiff1;
3843  float m1, b1, m2, b2, x21, x22, y21, y22, xi;
3844  float yi, x1min, x1max, y1max, y1min, perc = 0;
3845  float threshold = 0.0;
3846  int i;
3847 
3848  // threshold = 0.000001; /* tolerance for vertex intersection */
3849  // XXX threshold = scene->toolsettings->select_thresh / 100;
3850 
3851  /* Get screen coords of verts */
3852  x21 = sco_a[0];
3853  y21 = sco_a[1];
3854 
3855  x22 = sco_b[0];
3856  y22 = sco_b[1];
3857 
3858  xdiff2 = (x22 - x21);
3859  if (xdiff2) {
3860  m2 = (y22 - y21) / xdiff2;
3861  b2 = ((x22 * y21) - (x21 * y22)) / xdiff2;
3862  }
3863  else {
3864  m2 = MAXSLOPE; /* Vertical slope */
3865  b2 = x22;
3866  }
3867 
3868  *isected = 0;
3869 
3870  /* check for _exact_ vertex intersection first */
3871  if (mode != KNIFE_MULTICUT) {
3872  for (i = 0; i < len; i++) {
3873  if (i > 0) {
3874  x11 = x12;
3875  y11 = y12;
3876  }
3877  else {
3878  x11 = mouse_path[i][0];
3879  y11 = mouse_path[i][1];
3880  }
3881  x12 = mouse_path[i][0];
3882  y12 = mouse_path[i][1];
3883 
3884  /* test e->v1 */
3885  if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) {
3886  perc = 0;
3887  *isected = 1;
3888  return perc;
3889  }
3890  /* test e->v2 */
3891  if ((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)) {
3892  perc = 0;
3893  *isected = 2;
3894  return perc;
3895  }
3896  }
3897  }
3898 
3899  /* now check for edge intersect (may produce vertex intersection as well) */
3900  for (i = 0; i < len; i++) {
3901  if (i > 0) {
3902  x11 = x12;
3903  y11 = y12;
3904  }
3905  else {
3906  x11 = mouse_path[i][0];
3907  y11 = mouse_path[i][1];
3908  }
3909  x12 = mouse_path[i][0];
3910  y12 = mouse_path[i][1];
3911 
3912  /* Calculate the distance from point to line. */
3913  if (m2 != MAXSLOPE) {
3914  /* sqrt(m2 * m2 + 1); Only looking for change in sign. Skip extra math .*/
3915  dist = (y12 - m2 * x12 - b2);
3916  }
3917  else {
3918  dist = x22 - x12;
3919  }
3920 
3921  if (i == 0) {
3922  lastdist = dist;
3923  }
3924 
3925  /* if dist changes sign, and intersect point in edge's Bound Box */
3926  if ((lastdist * dist) <= 0) {
3927  xdiff1 = (x12 - x11); /* Equation of line between last 2 points */
3928  if (xdiff1) {
3929  m1 = (y12 - y11) / xdiff1;
3930  b1 = ((x12 * y11) - (x11 * y12)) / xdiff1;
3931  }
3932  else {
3933  m1 = MAXSLOPE;
3934  b1 = x12;
3935  }
3936  x2max = max_ff(x21, x22) + 0.001f; /* prevent missed edges */
3937  x2min = min_ff(x21, x22) - 0.001f; /* due to round off error */
3938  y2max = max_ff(y21, y22) + 0.001f;
3939  y2min = min_ff(y21, y22) - 0.001f;
3940 
3941  /* Found an intersect, calc intersect point */
3942  if (m1 == m2) { /* co-incident lines */
3943  /* cut at 50% of overlap area */
3944  x1max = max_ff(x11, x12);
3945  x1min = min_ff(x11, x12);
3946  xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f;
3947 
3948  y1max = max_ff(y11, y12);
3949  y1min = min_ff(y11, y12);
3950  yi = (min_ff(y2max, y1max) + max_ff(y2min, y1min)) / 2.0f;
3951  }
3952  else if (m2 == MAXSLOPE) {
3953  xi = x22;
3954  yi = m1 * x22 + b1;
3955  }
3956  else if (m1 == MAXSLOPE) {
3957  xi = x12;
3958  yi = m2 * x12 + b2;
3959  }
3960  else {
3961  xi = (b1 - b2) / (m2 - m1);
3962  yi = (b1 * m2 - m1 * b2) / (m2 - m1);
3963  }
3964 
3965  /* Intersect inside bounding box of edge?*/
3966  if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) {
3967  /* test for vertex intersect that may be 'close enough'*/
3968  if (mode != KNIFE_MULTICUT) {
3969  if (xi <= (x21 + threshold) && xi >= (x21 - threshold)) {
3970  if (yi <= (y21 + threshold) && yi >= (y21 - threshold)) {
3971  *isected = 1;
3972  perc = 0;
3973  break;
3974  }
3975  }
3976  if (xi <= (x22 + threshold) && xi >= (x22 - threshold)) {
3977  if (yi <= (y22 + threshold) && yi >= (y22 - threshold)) {
3978  *isected = 2;
3979  perc = 0;
3980  break;
3981  }
3982  }
3983  }
3984  if ((m2 <= 1.0f) && (m2 >= -1.0f)) {
3985  perc = (xi - x21) / (x22 - x21);
3986  }
3987  else {
3988  perc = (yi - y21) / (y22 - y21); /* lower slope more accurate */
3989  }
3990  // isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */
3991 
3992  break;
3993  }
3994  }
3995  lastdist = dist;
3996  }
3997  return perc;
3998 }
3999 
4000 #define ELE_EDGE_CUT 1
4001 
4003 {
4004  Object *obedit = CTX_data_edit_object(C);
4005  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4006  BMesh *bm = em->bm;
4007  ARegion *region = CTX_wm_region(C);
4008  BMVert *bv;
4009  BMIter iter;
4010  BMEdge *be;
4011  BMOperator bmop;
4012  float isect = 0.0f;
4013  int isected, i;
4014  short numcuts = 1;
4015  const short mode = RNA_int_get(op->ptr, "type");
4016 
4017  /* Allocated variables. */
4018  float(*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2];
4019 
4020  /* edit-object needed for matrix, and region->regiondata for projections to work */
4021  if (ELEM(NULL, obedit, region, region->regiondata)) {
4022  return OPERATOR_CANCELLED;
4023  }
4024 
4025  if (bm->totvertsel < 2) {
4026  BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on");
4027  return OPERATOR_CANCELLED;
4028  }
4029 
4030  const int len = RNA_collection_length(op->ptr, "path");
4031 
4032  if (len < 2) {
4033  BKE_report(op->reports, RPT_ERROR, "Mouse path too short");
4034  return OPERATOR_CANCELLED;
4035  }
4036 
4037  mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__);
4038 
4039  /* get the cut curve */
4040  RNA_BEGIN (op->ptr, itemptr, "path") {
4041  RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]);
4042  }
4043  RNA_END;
4044 
4045  /* for ED_view3d_project_float_object */
4046  ED_view3d_init_mats_rv3d(obedit, region->regiondata);
4047 
4048  /* TODO, investigate using index lookup for screen_vert_coords() rather than a hash table */
4049 
4050  /* the floating point coordinates of verts in screen space will be
4051  * stored in a hash table according to the vertices pointer */
4052  screen_vert_coords = sco = MEM_mallocN(sizeof(float[2]) * bm->totvert, __func__);
4053 
4054  BM_ITER_MESH_INDEX (bv, &iter, bm, BM_VERTS_OF_MESH, i) {
4055  if (ED_view3d_project_float_object(region, bv->co, *sco, V3D_PROJ_TEST_CLIP_NEAR) !=
4056  V3D_PROJ_RET_OK) {
4057  copy_v2_fl(*sco, FLT_MAX); /* set error value */
4058  }
4059  BM_elem_index_set(bv, i); /* set_inline */
4060  sco++;
4061  }
4062  bm->elem_index_dirty &= ~BM_VERT; /* clear dirty flag */
4063 
4064  if (!EDBM_op_init(em, &bmop, op, "subdivide_edges")) {
4065  MEM_freeN(mouse_path);
4066  MEM_freeN(screen_vert_coords);
4067  return OPERATOR_CANCELLED;
4068  }
4069 
4070  /* store percentage of edge cut for KNIFE_EXACT here.*/
4071  BMOpSlot *slot_edge_percents = BMO_slot_get(bmop.slots_in, "edge_percents");
4072  BM_ITER_MESH (be, &iter, bm, BM_EDGES_OF_MESH) {
4073  bool is_cut = false;
4074  if (BM_elem_flag_test(be, BM_ELEM_SELECT)) {
4075  const float *sco_a = screen_vert_coords[BM_elem_index_get(be->v1)];
4076  const float *sco_b = screen_vert_coords[BM_elem_index_get(be->v2)];
4077 
4078  /* check for error value (vert cant be projected) */
4079  if ((sco_a[0] != FLT_MAX) && (sco_b[0] != FLT_MAX)) {
4080  isect = bm_edge_seg_isect(sco_a, sco_b, mouse_path, len, mode, &isected);
4081 
4082  if (isect != 0.0f) {
4083  if (!ELEM(mode, KNIFE_MULTICUT, KNIFE_MIDPOINT)) {
4084  BMO_slot_map_float_insert(&bmop, slot_edge_percents, be, isect);
4085  }
4086  }
4087  }
4088  }
4089 
4090  BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
4091  }
4092 
4093  /* free all allocs */
4094  MEM_freeN(screen_vert_coords);
4095  MEM_freeN(mouse_path);
4096 
4098 
4100 
4101  if (mode == KNIFE_MIDPOINT) {
4102  numcuts = 1;
4103  }
4104  BMO_slot_int_set(bmop.slots_in, "cuts", numcuts);
4105 
4106  BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_CORNER_STRAIGHT_CUT);
4107  BMO_slot_bool_set(bmop.slots_in, "use_single_edge", false);
4108  BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false);
4109 
4110  BMO_slot_float_set(bmop.slots_in, "radius", 0);
4111 
4112  BMO_op_exec(bm, &bmop);
4113  if (!EDBM_op_finish(em, &bmop, op, true)) {
4114  return OPERATOR_CANCELLED;
4115  }
4116 
4118 
4119  EDBM_update_generic(obedit->data, true, true);
4120 
4121  return OPERATOR_FINISHED;
4122 }
4123 
4124 #undef ELE_EDGE_CUT
4125 
4127 {
4128  ot->name = "Knife Cut";
4129  ot->description = "Cut selected edges and faces into parts";
4130  ot->idname = "MESH_OT_knife_cut";
4131 
4135 
4137 
4138  /* flags */
4140 
4141  /* properties */
4142  PropertyRNA *prop;
4143  prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
4145 
4146  RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
4147 
4148  /* internal */
4149  RNA_def_int(
4150  ot->srna, "cursor", WM_CURSOR_KNIFE, 0, WM_CURSOR_NUM, "Cursor", "", 0, WM_CURSOR_NUM);
4151 }
4152 
4155 /* -------------------------------------------------------------------- */
4159 enum {
4163 };
4164 
4167  Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
4168 {
4169  Object *obedit = base_old->object;
4171  &((struct BMeshCreateParams){
4172  .use_toolflags = true,
4173  }));
4174  BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */
4175 
4177 
4178  /* Take into account user preferences for duplicating actions. */
4179  const eDupli_ID_Flags dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT);
4180  Base *base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, dupflag);
4181 
4182  /* normally would call directly after but in this case delay recalc */
4183  /* DAG_relations_tag_update(bmain); */
4184 
4185  /* new in 2.5 */
4187  base_new->object,
4189  *BKE_object_material_len_p(obedit),
4190  false);
4191 
4192  ED_object_base_select(base_new, BA_SELECT);
4193 
4194  BMO_op_callf(bm_old,
4196  "duplicate geom=%hvef dest=%p",
4197  BM_ELEM_TAG,
4198  bm_new);
4199  BMO_op_callf(bm_old,
4201  "delete geom=%hvef context=%i",
4202  BM_ELEM_TAG,
4203  DEL_FACES);
4204 
4205  /* deselect loose data - this used to get deleted,
4206  * we could de-select edges and verts only, but this turns out to be less complicated
4207  * since de-selecting all skips selection flushing logic */
4209 
4210  BM_mesh_normals_update(bm_new);
4211 
4212  BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
4213 
4214  BM_mesh_free(bm_new);
4215  ((Mesh *)base_new->object->data)->edit_mesh = NULL;
4216 
4217  return base_new;
4218 }
4219 
4221  Scene *scene,
4222  ViewLayer *view_layer,
4223  Base *base_old,
4224  BMesh *bm_old,
4225  BMVert **verts,
4226  uint verts_len,
4227  BMEdge **edges,
4228  uint edges_len,
4229  BMFace **faces,
4230  uint faces_len)
4231 {
4232  const BMAllocTemplate bm_new_allocsize = {
4233  .totvert = verts_len,
4234  .totedge = edges_len,
4235  .totloop = faces_len * 3,
4236  .totface = faces_len,
4237  };
4238  const bool use_custom_normals = (bm_old->lnor_spacearr != NULL);
4239 
4240  Object *obedit = base_old->object;
4241 
4242  BMesh *bm_new = BM_mesh_create(&bm_new_allocsize, &((struct BMeshCreateParams){0}));
4243 
4244  if (use_custom_normals) {
4245  /* Needed so the temporary normal layer is copied too. */
4246  BM_mesh_copy_init_customdata_all_layers(bm_new, bm_old, BM_ALL, &bm_new_allocsize);
4247  }
4248  else {
4249  BM_mesh_copy_init_customdata(bm_new, bm_old, &bm_new_allocsize);
4250  }
4251 
4252  /* Take into account user preferences for duplicating actions. */
4253  const eDupli_ID_Flags dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT);
4254  Base *base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, dupflag);
4255 
4256  /* normally would call directly after but in this case delay recalc */
4257  /* DAG_relations_tag_update(bmain); */
4258 
4259  /* new in 2.5 */
4261  base_new->object,
4263  *BKE_object_material_len_p(obedit),
4264  false);
4265 
4266  ED_object_base_select(base_new, BA_SELECT);
4267 
4268  BM_mesh_copy_arrays(bm_old, bm_new, verts, verts_len, edges, edges_len, faces, faces_len);
4269 
4270  if (use_custom_normals) {
4272  }
4273 
4274  for (uint i = 0; i < verts_len; i++) {
4275  BM_vert_kill(bm_old, verts[i]);
4276  }
4277 
4278  BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
4279 
4280  BM_mesh_free(bm_new);
4281  ((Mesh *)base_new->object->data)->edit_mesh = NULL;
4282 
4283  return base_new;
4284 }
4285 
4287  Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
4288 {
4289  /* we may have tags from previous operators */
4291 
4292  /* sel -> tag */
4294  bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, false, BM_ELEM_SELECT);
4295 
4296  return (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL);
4297 }
4298 
4305 static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const short mat_nr)
4306 {
4307  ID *obdata = ob->data;
4308 
4309  const short *totcolp = BKE_id_material_len_p(obdata);
4310  Material ***matarar = BKE_id_material_array_p(obdata);
4311 
4312  if ((totcolp && matarar) == 0) {
4313  BLI_assert(0);
4314  return;
4315  }
4316 
4317  if (*totcolp) {
4318  Material *ma_ob;
4319  Material *ma_obdata;
4320  char matbit;
4321 
4322  if (mat_nr < ob->totcol) {
4323  ma_ob = ob->mat[mat_nr];
4324  matbit = ob->matbits[mat_nr];
4325  }
4326  else {
4327  ma_ob = NULL;
4328  matbit = 0;
4329  }
4330 
4331  if (mat_nr < *totcolp) {
4332  ma_obdata = (*matarar)[mat_nr];
4333  }
4334  else {
4335  ma_obdata = NULL;
4336  }
4337 
4338  BKE_id_material_clear(bmain, obdata);
4339  BKE_object_material_resize(bmain, ob, 1, true);
4340  BKE_id_material_resize(bmain, obdata, 1, true);
4341 
4342  ob->mat[0] = ma_ob;
4343  id_us_plus((ID *)ma_ob);
4344  ob->matbits[0] = matbit;
4345  (*matarar)[0] = ma_obdata;
4346  id_us_plus((ID *)ma_obdata);
4347  }
4348  else {
4349  BKE_id_material_clear(bmain, obdata);
4350  BKE_object_material_resize(bmain, ob, 0, true);
4351  BKE_id_material_resize(bmain, obdata, 0, true);
4352  }
4353 }
4354 
4356  Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
4357 {
4358  BMFace *f_cmp, *f;
4359  BMIter iter;
4360  bool result = false;
4361 
4362  while ((f_cmp = BM_iter_at_index(bm_old, BM_FACES_OF_MESH, NULL, 0))) {
4363  Base *base_new;
4364  const short mat_nr = f_cmp->mat_nr;
4365  int tot = 0;
4366 
4368 
4369  BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) {
4370  if (f->mat_nr == mat_nr) {
4371  BMLoop *l_iter;
4372  BMLoop *l_first;
4373 
4375  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
4376  do {
4377  BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
4378  BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
4379  } while ((l_iter = l_iter->next) != l_first);
4380 
4381  tot++;
4382  }
4383  }
4384 
4385  /* leave the current object with some materials */
4386  if (tot == bm_old->totface) {
4387  mesh_separate_material_assign_mat_nr(bmain, base_old->object, mat_nr);
4388 
4389  /* since we're in editmode, must set faces here */
4390  BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) {
4391  f->mat_nr = 0;
4392  }
4393  break;
4394  }
4395 
4396  /* Move selection into a separate object */
4397  base_new = mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old);
4398  if (base_new) {
4399  mesh_separate_material_assign_mat_nr(bmain, base_new->object, mat_nr);
4400  }
4401 
4402  result |= (base_new != NULL);
4403  }
4404 
4405  return result;
4406 }
4407 
4409  Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
4410 {
4411  /* Without this, we duplicate the object mode mesh for each loose part.
4412  * This can get very slow especially for large meshes with many parts
4413  * which would duplicate the mesh on entering edit-mode. */
4414  const bool clear_object_data = true;
4415 
4416  bool result = false;
4417 
4418  BMVert **vert_groups = MEM_mallocN(sizeof(*vert_groups) * bm_old->totvert, __func__);
4419  BMEdge **edge_groups = MEM_mallocN(sizeof(*edge_groups) * bm_old->totedge, __func__);
4420  BMFace **face_groups = MEM_mallocN(sizeof(*face_groups) * bm_old->totface, __func__);
4421 
4422  int(*groups)[3] = NULL;
4423  int groups_len = BM_mesh_calc_edge_groups_as_arrays(
4424  bm_old, vert_groups, edge_groups, face_groups, &groups);
4425  if (groups_len <= 1) {
4426  goto finally;
4427  }
4428 
4429  if (clear_object_data) {
4430  ED_mesh_geometry_clear(base_old->object->data);
4431  }
4432 
4434 
4435  /* Separate out all groups except the first. */
4436  uint group_ofs[3] = {UNPACK3(groups[0])};
4437  for (int i = 1; i < groups_len; i++) {
4438  Base *base_new = mesh_separate_arrays(bmain,
4439  scene,
4440  view_layer,
4441  base_old,
4442  bm_old,
4443  vert_groups + group_ofs[0],
4444  groups[i][0],
4445  edge_groups + group_ofs[1],
4446  groups[i][1],
4447  face_groups + group_ofs[2],
4448  groups[i][2]);
4449  result |= (base_new != NULL);
4450 
4451  group_ofs[0] += groups[i][0];
4452  group_ofs[1] += groups[i][1];
4453  group_ofs[2] += groups[i][2];
4454  }
4455 
4456  Mesh *me_old = base_old->object->data;
4458 
4459  if (clear_object_data) {
4461  bm_old,
4462  me_old,
4463  (&(struct BMeshToMeshParams){
4464  .update_shapekey_indices = true,
4465  }));
4466  }
4467 
4468 finally:
4469  MEM_freeN(vert_groups);
4470  MEM_freeN(edge_groups);
4471  MEM_freeN(face_groups);
4472 
4473  MEM_freeN(groups);
4474 
4475  return result;
4476 }
4477 
4479 {
4480  Main *bmain = CTX_data_main(C);
4482  ViewLayer *view_layer = CTX_data_view_layer(C);
4483  const int type = RNA_enum_get(op->ptr, "type");
4484  bool changed_multi = false;
4485 
4486  if (ED_operator_editmesh(C)) {
4487  uint bases_len = 0;
4488  uint empty_selection_len = 0;
4490  view_layer, CTX_wm_view3d(C), &bases_len);
4491  for (uint bs_index = 0; bs_index < bases_len; bs_index++) {
4492  Base *base = bases[bs_index];
4494  bool changed = false;
4495 
4496  if (type == 0) {
4497  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
4498  /* when all objects has no selection */
4499  if (++empty_selection_len == bases_len) {
4500  BKE_report(op->reports, RPT_ERROR, "Nothing selected");
4501  }
4502  continue;
4503  }
4504  }
4505 
4506  /* editmode separate */
4507  switch (type) {
4509  changed = mesh_separate_selected(bmain, scene, view_layer, base, em->bm);
4510  break;
4512  changed = mesh_separate_material(bmain, scene, view_layer, base, em->bm);
4513  break;
4514  case MESH_SEPARATE_LOOSE:
4515  changed = mesh_separate_loose(bmain, scene, view_layer, base, em->bm);
4516  break;
4517  default:
4518  BLI_assert(0);
4519  break;
4520  }
4521 
4522  if (changed) {
4523  EDBM_update_generic(base->object->data, true, true);
4524  }
4525  changed_multi |= changed;
4526  }
4527  MEM_freeN(bases);
4528  }
4529  else {
4530  if (type == MESH_SEPARATE_SELECTED) {
4531  BKE_report(op->reports, RPT_ERROR, "Selection not supported in object mode");
4532  return OPERATOR_CANCELLED;
4533  }
4534 
4535  /* object mode separate */
4536  CTX_DATA_BEGIN (C, Base *, base_iter, selected_editable_bases) {
4537  Object *ob = base_iter->object;
4538  if (ob->type == OB_MESH) {
4539  Mesh *me = ob->data;
4540  if (!ID_IS_LINKED(me)) {
4541  BMesh *bm_old = NULL;
4542  bool changed = false;
4543 
4545  &((struct BMeshCreateParams){
4546  .use_toolflags = true,
4547  }));
4548 
4549  BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0}));
4550 
4551  switch (type) {
4553  changed = mesh_separate_material(bmain, scene, view_layer, base_iter, bm_old);
4554  break;
4555  case MESH_SEPARATE_LOOSE:
4556  changed = mesh_separate_loose(bmain, scene, view_layer, base_iter, bm_old);
4557  break;
4558  default:
4559  BLI_assert(0);
4560  break;
4561  }
4562 
4563  if (changed) {
4564  BM_mesh_bm_to_me(bmain,
4565  bm_old,
4566  me,
4567  (&(struct BMeshToMeshParams){
4568  .calc_object_remap = true,
4569  }));
4570 
4573  }
4574 
4575  BM_mesh_free(bm_old);
4576 
4577  changed_multi |= changed;
4578  }
4579  }
4580  }
4581  CTX_DATA_END;
4582  }
4583 
4584  if (changed_multi) {
4585  /* delay depsgraph recalc until all objects are duplicated */
4586  DEG_relations_tag_update(bmain);
4589 
4590  return OPERATOR_FINISHED;
4591  }
4592 
4593  return OPERATOR_CANCELLED;
4594 }
4595 
4597 {
4598  static const EnumPropertyItem prop_separate_types[] = {
4599  {MESH_SEPARATE_SELECTED, "SELECTED", 0, "Selection", ""},
4600  {MESH_SEPARATE_MATERIAL, "MATERIAL", 0, "By Material", ""},
4601  {MESH_SEPARATE_LOOSE, "LOOSE", 0, "By Loose Parts", ""},
4602  {0, NULL, 0, NULL, NULL},
4603  };
4604 
4605  /* identifiers */
4606  ot->name = "Separate";
4607  ot->description = "Separate selected geometry into a new mesh";
4608  ot->idname = "MESH_OT_separate";
4609 
4610  /* api callbacks */
4613  ot->poll = ED_operator_scene_editable; /* object and editmode */
4614 
4615  /* flags */
4616  ot->flag = OPTYPE_UNDO;
4617 
4618  ot->prop = RNA_def_enum(
4619  ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", "");
4620 }
4621 
4624 /* -------------------------------------------------------------------- */
4629 {
4630  const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty");
4631 
4632  bool has_selected_edges = false, has_faces_filled = false;
4633 
4634  ViewLayer *view_layer = CTX_data_view_layer(C);
4635  uint objects_len = 0;
4637  view_layer, CTX_wm_view3d(C), &objects_len);
4638  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4639  Object *obedit = objects[ob_index];
4640  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4641 
4642  const int totface_orig = em->bm->totface;
4643 
4644  if (em->bm->totedgesel == 0) {
4645  continue;
4646  }
4647  has_selected_edges = true;
4648 
4649  BMOperator bmop;
4650  if (!EDBM_op_init(
4651  em, &bmop, op, "triangle_fill edges=%he use_beauty=%b", BM_ELEM_SELECT, use_beauty)) {
4652  continue;
4653  }
4654 
4655  BMO_op_exec(em->bm, &bmop);
4656 
4657  /* cancel if nothing was done */
4658  if (totface_orig == em->bm->totface) {
4659  EDBM_op_finish(em, &bmop, op, true);
4660  continue;
4661  }
4662  has_faces_filled = true;
4663 
4664  /* select new geometry */
4666  em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
4667 
4668  if (!EDBM_op_finish(em, &bmop, op, true)) {
4669  continue;
4670  }
4671 
4672  EDBM_update_generic(obedit->data, true, true);
4673  }
4674  MEM_freeN(objects);
4675 
4676  if (!has_selected_edges) {
4677  BKE_report(op->reports, RPT_ERROR, "No edges selected");
4678  return OPERATOR_CANCELLED;
4679  }
4680 
4681  if (!has_faces_filled) {
4682  BKE_report(op->reports, RPT_WARNING, "No faces filled");
4683  return OPERATOR_CANCELLED;
4684  }
4685 
4686  return OPERATOR_FINISHED;
4687 }
4688 
4690 {
4691  /* identifiers */
4692  ot->name = "Fill";
4693  ot->idname = "MESH_OT_fill";
4694  ot->description = "Fill a selected edge loop with faces";
4695 
4696  /* api callbacks */
4697  ot->exec = edbm_fill_exec;
4699 
4700  /* flags */
4702 
4703  RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division");
4704 }
4705 
4708 /* -------------------------------------------------------------------- */
4712 static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v))
4713 {
4715 }
4716 
4718 {
4719  BMIter iter;
4720  BMEdge *e_iter;
4721  BMVert *v_pair[2];
4722  int i = 0;
4723  BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
4724  if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) {
4725  v_pair[i++] = BM_edge_other_vert(e_iter, v);
4726  }
4727  }
4728  BLI_assert(i == 2);
4729 
4730  return fabsf((float)M_PI - angle_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co));
4731 }
4732 
4736 static bool edbm_fill_grid_prepare(BMesh *bm, int offset, int *span_p, const bool span_calc)
4737 {
4738  /* angle differences below this value are considered 'even'
4739  * in that they shouldn't be used to calculate corners used for the 'span' */
4740  const float eps_even = 1e-3f;
4741  BMEdge *e;
4742  BMIter iter;
4743  int count;
4744  int span = *span_p;
4745 
4746  ListBase eloops = {NULL};
4747  struct BMEdgeLoopStore *el_store;
4748  // LinkData *el_store;
4749 
4751  el_store = eloops.first;
4752 
4753  if (count != 1) {
4754  /* Let the operator use the selection flags,
4755  * most likely failing with an error in this case. */
4756  BM_mesh_edgeloops_free(&eloops);
4757  return false;
4758  }
4759 
4760  /* Only tag edges that are part of a loop. */
4761  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
4763  }
4764  const int verts_len = BM_edgeloop_length_get(el_store);
4765  const int edges_len = verts_len - (BM_edgeloop_is_closed(el_store) ? 0 : 1);
4766  BMEdge **edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
4767  BM_edgeloop_edges_get(el_store, edges);
4768  for (int i = 0; i < edges_len; i++) {
4769  BM_elem_flag_enable(edges[i], BM_ELEM_TAG);
4770  }
4771 
4772  if (span_calc) {
4773  span = verts_len / 4;
4774  }
4775  else {
4776  span = min_ii(span, (verts_len / 2) - 1);
4777  }
4778  offset = mod_i(offset, verts_len);
4779 
4780  if ((count == 1) && ((verts_len & 1) == 0) && (verts_len == edges_len)) {
4781 
4782  /* be clever! detect 2 edge loops from one closed edge loop */
4783  ListBase *verts = BM_edgeloop_verts_get(el_store);
4784  BMVert *v_act = BM_mesh_active_vert_get(bm);
4785  LinkData *v_act_link;
4786  int i;
4787 
4788  if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) {
4789  /* pass */
4790  }
4791  else {
4792  /* find the vertex with the best angle (a corner vertex) */
4793  LinkData *v_link, *v_link_best = NULL;
4794  float angle_best = -1.0f;
4795  for (v_link = verts->first; v_link; v_link = v_link->next) {
4796  const float angle = edbm_fill_grid_vert_tag_angle(v_link->data);
4797  if ((angle > angle_best) || (v_link_best == NULL)) {
4798  angle_best = angle;
4799  v_link_best = v_link;
4800  }
4801  }
4802 
4803  v_act_link = v_link_best;
4804  v_act = v_act_link->data;
4805  }
4806 
4807  /* set this vertex first */
4808  BLI_listbase_rotate_first(verts, v_act_link);
4809 
4810  if (offset != 0) {
4811  v_act_link = BLI_findlink(verts, offset);
4812  v_act = v_act_link->data;
4813  BLI_listbase_rotate_first(verts, v_act_link);
4814  }
4815 
4816  /* Run again to update the edge order from the rotated vertex list. */
4817  BM_edgeloop_edges_get(el_store, edges);
4818 
4819  if (span_calc) {
4820  /* calculate the span by finding the next corner in 'verts'
4821  * we don't know what defines a corner exactly so find the 4 verts
4822  * in the loop with the greatest angle.
4823  * Tag them and use the first tagged vertex to calculate the span.
4824  *
4825  * NOTE: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each
4826  * vert, but advantage of de-duplicating is minimal. */
4827  struct SortPtrByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__);
4828  LinkData *v_link;
4829  for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) {
4830  BMVert *v = v_link->data;
4831  const float angle = edbm_fill_grid_vert_tag_angle(v);
4832  ele_sort[i].sort_value = angle;
4833  ele_sort[i].data = v;
4834 
4836  }
4837 
4838  qsort(ele_sort, verts_len, sizeof(*ele_sort), BLI_sortutil_cmp_float_reverse);
4839 
4840  /* check that we have at least 3 corners,
4841  * if the angle on the 3rd angle is roughly the same as the last,
4842  * then we can't calculate 3+ corners - fallback to the even span. */
4843  if ((ele_sort[2].sort_value - ele_sort[verts_len - 1].sort_value) > eps_even) {
4844  for (i = 0; i < 4; i++) {
4845  BMVert *v = ele_sort[i].data;
4847  }
4848 
4849  /* now find the first... */
4850  for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) {
4851  BMVert *v = v_link->data;
4853  if (v != v_act) {
4854  span = i;
4855  break;
4856  }
4857  }
4858  }
4859  }
4860  MEM_freeN(ele_sort);
4861  }
4862  /* end span calc */
4863 
4864  /* un-flag 'rails' */
4865  for (i = 0; i < span; i++) {
4866  BM_elem_flag_disable(edges[i], BM_ELEM_TAG);
4867  BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG);
4868  }
4869  }
4870  /* else let the bmesh-operator handle it */
4871 
4872  BM_mesh_edgeloops_free(&eloops);
4873  MEM_freeN(edges);
4874 
4875  *span_p = span;
4876 
4877  return true;
4878 }
4879 
4881 {
4882  const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple");
4883 
4884  ViewLayer *view_layer = CTX_data_view_layer(C);
4885  uint objects_len = 0;
4887  view_layer, CTX_wm_view3d(C), &objects_len);
4888  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4889 
4890  Object *obedit = objects[ob_index];
4891  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4892 
4893  bool use_prepare = true;
4894  const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
4895  const int totedge_orig = em->bm->totedge;
4896  const int totface_orig = em->bm->totface;
4897 
4898  if (em->bm->totedgesel == 0) {
4899  continue;
4900  }
4901 
4902  if (use_prepare) {
4903  /* use when we have a single loop selected */
4904  PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span");
4905  PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset");
4906  bool calc_span;
4907 
4908  int span;
4909  int offset;
4910 
4911  /* Only reuse on redo because these settings need to match the current selection.
4912  * We never want to use them on other geometry, repeat last for eg, see: T60777. */
4913  if (((op->flag & OP_IS_INVOKE) || (op->flag & OP_IS_REPEAT_LAST) == 0) &&
4914  RNA_property_is_set(op->ptr, prop_span)) {
4915  span = RNA_property_int_get(op->ptr, prop_span);
4916  calc_span = false;
4917  }
4918  else {
4919  /* Will be overwritten if possible. */
4920  span = 0;
4921  calc_span = true;
4922  }
4923 
4924  offset = RNA_property_int_get(op->ptr, prop_offset);
4925 
4926  /* in simple cases, move selection for tags, but also support more advanced cases */
4927  use_prepare = edbm_fill_grid_prepare(em->bm, offset, &span, calc_span);
4928 
4929  RNA_property_int_set(op->ptr, prop_span, span);
4930  }
4931  /* end tricky prepare code */
4932 
4933  BMOperator bmop;
4934  if (!EDBM_op_init(em,
4935  &bmop,
4936  op,
4937  "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
4938  use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT,
4939  em->mat_nr,
4940  use_smooth,
4941  use_interp_simple)) {
4942  continue;
4943  }
4944 
4945  BMO_op_exec(em->bm, &bmop);
4946 
4947  /* NOTE: EDBM_op_finish() will change bmesh pointer inside of edit mesh,
4948  * so need to tell evaluated objects to sync new bmesh pointer to their
4949  * edit mesh structures.
4950  */
4951  DEG_id_tag_update(&obedit->id, 0);
4952 
4953  /* cancel if nothing was done */
4954  if ((totedge_orig == em->bm->totedge) && (totface_orig == em->bm->totface)) {
4955  EDBM_op_finish(em, &bmop, op, true);
4956  continue;
4957  }
4958 
4960  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
4961 
4962  if (!EDBM_op_finish(em, &bmop, op, true)) {
4963  continue;
4964  }
4965 
4966  EDBM_update_generic(obedit->data, true, true);
4967  }
4968 
4969  MEM_freeN(objects);
4970 
4971  return OPERATOR_FINISHED;
4972 }
4973 
4975 {
4976  PropertyRNA *prop;
4977 
4978  /* identifiers */
4979  ot->name = "Grid Fill";
4980  ot->description = "Fill grid from two loops";
4981  ot->idname = "MESH_OT_fill_grid";
4982 
4983  /* api callbacks */
4986 
4987  /* flags */
4989 
4990  /* properties */
4991  prop = RNA_def_int(ot->srna, "span", 1, 1, 1000, "Span", "Number of grid columns", 1, 100);
4993  prop = RNA_def_int(ot->srna,
4994  "offset",
4995  0,
4996  -1000,
4997  1000,
4998  "Offset",
4999  "Vertex that is the corner of the grid",
5000  -100,
5001  100);
5004  "use_interp_simple",
5005  false,
5006  "Simple Blending",
5007  "Use simple interpolation of grid vertices");
5008 }
5009 
5012 /* -------------------------------------------------------------------- */
5017 {
5018  const int sides = RNA_int_get(op->ptr, "sides");
5019 
5020  ViewLayer *view_layer = CTX_data_view_layer(C);
5021  uint objects_len = 0;
5023  view_layer, CTX_wm_view3d(C), &objects_len);
5024 
5025  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5026  Object *obedit = objects[ob_index];
5027  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5028 
5029  if (em->bm->totedgesel == 0) {
5030  continue;
5031  }
5032 
5034  em, op, "faces.out", true, "holes_fill edges=%he sides=%i", BM_ELEM_SELECT, sides)) {
5035  continue;
5036  }
5037 
5038  EDBM_update_generic(obedit->data, true, true);
5039  }
5040  MEM_freeN(objects);
5041 
5042  return OPERATOR_FINISHED;
5043 }
5044 
5046 {
5047  /* identifiers */
5048  ot->name = "Fill Holes";
5049  ot->idname = "MESH_OT_fill_holes";
5050  ot->description = "Fill in holes (boundary edge loops)";
5051 
5052  /* api callbacks */
5055 
5056  /* flags */
5058 
5059  RNA_def_int(ot->srna,
5060  "sides",
5061  4,
5062  0,
5063  1000,
5064  "Sides",
5065  "Number of sides in hole required to fill (zero fills all holes)",
5066  0,
5067  100);
5068 }
5069 
5072 /* -------------------------------------------------------------------- */
5077 {
5078  ViewLayer *view_layer = CTX_data_view_layer(C);
5079  uint objects_len = 0;
5081  view_layer, CTX_wm_view3d(C), &objects_len);
5082 
5083  const float angle_max = M_PI;
5084  const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
5085  char hflag;
5086 
5087  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5088  Object *obedit = objects[ob_index];
5089  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5090 
5091  if (em->bm->totfacesel == 0) {
5092  continue;
5093  }
5094 
5095  if (angle_limit >= angle_max) {
5096  hflag = BM_ELEM_SELECT;
5097  }
5098  else {
5099  BMIter iter;
5100  BMEdge *e;
5101 
5102  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
5104  BM_ELEM_TAG,
5106  BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit));
5107  }
5108  hflag = BM_ELEM_TAG;
5109  }
5110 
5111  if (!EDBM_op_call_and_selectf(em,
5112  op,
5113  "geom.out",
5114  true,
5115  "beautify_fill faces=%hf edges=%he",
5117  hflag)) {
5118  continue;
5119  }
5120 
5121  EDBM_update_generic(obedit->data, true, true);
5122  }
5123 
5124  MEM_freeN(objects);
5125 
5126  return OPERATOR_FINISHED;
5127 }
5128 
5130 {
5131  PropertyRNA *prop;
5132 
5133  /* identifiers */
5134  ot->name = "Beautify Faces";
5135  ot->idname = "MESH_OT_beautify_fill";
5136  ot->description = "Rearrange some faces to try to get less degenerated geometry";
5137 
5138  /* api callbacks */
5141 
5142  /* flags */
5144 
5145  /* props */
5146  prop = RNA_def_float_rotation(ot->srna,
5147  "angle_limit",
5148  0,
5149  NULL,
5150  0.0f,
5151  DEG2RADF(180.0f),
5152  "Max Angle",
5153  "Angle limit",
5154  0.0f,
5155  DEG2RADF(180.0f));
5157 }
5158 
5161 /* -------------------------------------------------------------------- */
5166 {
5167  const float offset = RNA_float_get(op->ptr, "offset");
5168  const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset");
5169  const int center_mode = RNA_enum_get(op->ptr, "center_mode");
5170 
5171  ViewLayer *view_layer = CTX_data_view_layer(C);
5172  uint objects_len = 0;
5174  view_layer, CTX_wm_view3d(C), &objects_len);
5175  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5176  Object *obedit = objects[ob_index];
5177  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5178 
5179  if (em->bm->totfacesel == 0) {
5180  continue;
5181  }
5182 
5183  BMOperator bmop;
5184  EDBM_op_init(em,
5185  &bmop,
5186  op,
5187  "poke faces=%hf offset=%f use_relative_offset=%b center_mode=%i",
5189  offset,
5190  use_relative_offset,
5191  center_mode);
5192  BMO_op_exec(em->bm, &bmop);
5193 
5195 
5197  em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true);
5199  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
5200 
5201  if (!EDBM_op_finish(em, &bmop, op, true)) {
5202  continue;
5203  }
5204 
5206 
5207  EDBM_update_generic(obedit->data, true, true);
5208  }
5209  MEM_freeN(objects);
5210 
5211  return OPERATOR_FINISHED;
5212 }
5213 
5215 {
5216  static const EnumPropertyItem poke_center_modes[] = {
5218  "MEDIAN_WEIGHTED",
5219  0,
5220  "Weighted Median",
5221  "Weighted median face center"},
5222  {BMOP_POKE_MEDIAN, "MEDIAN", 0, "Median", "Median face center"},
5223  {BMOP_POKE_BOUNDS, "BOUNDS", 0, "Bounds", "Face bounds center"},
5224  {0, NULL, 0, NULL, NULL},
5225  };
5226 
5227  /* identifiers */
5228  ot->name = "Poke Faces";
5229  ot->idname = "MESH_OT_poke";
5230  ot->description = "Split a face into a fan";
5231 
5232  /* api callbacks */
5235 
5236  /* flags */
5238 
5240  ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
5242  "use_relative_offset",
5243  false,
5244  "Offset Relative",
5245  "Scale the offset by surrounding geometry");
5246  RNA_def_enum(ot->srna,
5247  "center_mode",
5248  poke_center_modes,
5250  "Poke Center",
5251  "Poke face center calculation");
5252 }
5253 
5256 /* -------------------------------------------------------------------- */
5261 {
5262  const int quad_method = RNA_enum_get(op->ptr, "quad_method");
5263  const int ngon_method = RNA_enum_get(op->ptr, "ngon_method");
5264  ViewLayer *view_layer = CTX_data_view_layer(C);
5265 
5266  uint objects_len = 0;
5268  view_layer, CTX_wm_view3d(C), &objects_len);
5269  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5270  Object *obedit = objects[ob_index];
5271  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5272 
5273  if (em->bm->totfacesel == 0) {
5274  continue;
5275  }
5276 
5277  BMOperator bmop;
5278  BMOIter oiter;
5279  BMFace *f;
5280 
5282 
5283  EDBM_op_init(em,
5284  &bmop,
5285  op,
5286  "triangulate faces=%hf quad_method=%i ngon_method=%i",
5288  quad_method,
5289  ngon_method);
5290  BMO_op_exec(em->bm, &bmop);
5291 
5292  /* select the output */
5294  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
5295 
5296  /* remove the doubles */
5297  BMO_ITER (f, &oiter, bmop.slots_out, "face_map_double.out", BM_FACE) {
5298  BM_face_kill(em->bm, f);
5299  }
5300 
5302 
5303  if (!EDBM_op_finish(em, &bmop, op, true)) {
5304  continue;
5305  }
5306 
5308 
5309  EDBM_update_generic(obedit->data, true, true);
5310  }
5311 
5312  MEM_freeN(objects);
5313 
5314  return OPERATOR_FINISHED;
5315 }
5316 
5318 {
5319  /* identifiers */
5320  ot->name = "Triangulate Faces";
5321  ot->idname = "MESH_OT_quads_convert_to_tris";
5322  ot->description = "Triangulate selected faces";
5323 
5324  /* api callbacks */
5327 
5328  /* flags */
5330 
5331  RNA_def_enum(ot->srna,
5332  "quad_method",
5335  "Quad Method",
5336  "Method for splitting the quads into triangles");
5337  RNA_def_enum(ot->srna,
5338  "ngon_method",
5341  "N-gon Method",
5342  "Method for splitting the n-gons into triangles");
5343 }
5344 
5347 /* -------------------------------------------------------------------- */
5352 {
5353  ViewLayer *view_layer = CTX_data_view_layer(C);
5354 
5355  uint objects_len = 0;
5357  view_layer, CTX_wm_view3d(C), &objects_len);
5358 
5359  bool is_face_pair;
5360 
5361  {
5362  int totelem_sel[3];
5363  EDBM_mesh_stats_multi(objects, objects_len, NULL, totelem_sel);
5364  is_face_pair = (totelem_sel[2] == 2);
5365  }
5366 
5367  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5368  Object *obedit = objects[ob_index];
5369 
5370  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5371  bool do_seam, do_sharp, do_uvs, do_vcols, do_materials;
5372  float angle_face_threshold, angle_shape_threshold;
5373  PropertyRNA *prop;
5374 
5375  /* When joining exactly 2 faces, no limit.
5376  * this is useful for one off joins while editing. */
5377  prop = RNA_struct_find_property(op->ptr, "face_threshold");
5378  if (is_face_pair && (RNA_property_is_set(op->ptr, prop) == false)) {
5379  angle_face_threshold = DEG2RADF(180.0f);
5380  }
5381  else {
5382  angle_face_threshold = RNA_property_float_get(op->ptr, prop);
5383  }
5384 
5385  prop = RNA_struct_find_property(op->ptr, "shape_threshold");
5386  if (is_face_pair && (RNA_property_is_set(op->ptr, prop) == false)) {
5387  angle_shape_threshold = DEG2RADF(180.0f);
5388  }
5389  else {
5390  angle_shape_threshold = RNA_property_float_get(op->ptr, prop);
5391  }
5392 
5393  do_seam = RNA_boolean_get(op->ptr, "seam");
5394  do_sharp = RNA_boolean_get(op->ptr, "sharp");
5395  do_uvs = RNA_boolean_get(op->ptr, "uvs");
5396  do_vcols = RNA_boolean_get(op->ptr, "vcols");
5397  do_materials = RNA_boolean_get(op->ptr, "materials");
5398 
5400 
5402  em,
5403  op,
5404  "faces.out",
5405  true,
5406  "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f "
5407  "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
5409  angle_face_threshold,
5410  angle_shape_threshold,
5411  do_seam,
5412  do_sharp,
5413  do_uvs,
5414  do_vcols,
5415  do_materials)) {
5416  continue;
5417  }
5418 
5420 
5421  EDBM_update_generic(obedit->data, true, true);
5422  }
5423  MEM_freeN(objects);
5424 
5425  return OPERATOR_FINISHED;
5426 }
5427 
5429 {
5430  PropertyRNA *prop;
5431 
5432  prop = RNA_def_float_rotation(ot->srna,
5433  "face_threshold",
5434  0,
5435  NULL,
5436  0.0f,
5437  DEG2RADF(180.0f),
5438  "Max Face Angle",
5439  "Face angle limit",
5440  0.0f,
5441  DEG2RADF(180.0f));
5443 
5444  prop = RNA_def_float_rotation(ot->srna,
5445  "shape_threshold",
5446  0,
5447  NULL,
5448  0.0f,
5449  DEG2RADF(180.0f),
5450  "Max Shape Angle",
5451  "Shape angle limit",
5452  0.0f,
5453  DEG2RADF(180.0f));
5455 
5456  RNA_def_boolean(ot->srna, "uvs", false, "Compare UVs", "");
5457  RNA_def_boolean(ot->srna, "vcols", false, "Compare VCols", "");
5458  RNA_def_boolean(ot->srna, "seam", false, "Compare Seam", "");
5459  RNA_def_boolean(ot->srna, "sharp", false, "Compare Sharp", "");
5460  RNA_def_boolean(ot->srna, "materials", false, "Compare Materials", "");
5461 }
5462 
5464 {
5465  /* identifiers */
5466  ot->name = "Tris to Quads";
5467  ot->idname = "MESH_OT_tris_convert_to_quads";
5468  ot->description = "Join triangles into quads";
5469 
5470  /* api callbacks */
5473 
5474  /* flags */
5476 
5478 }
5479 
5482 /* -------------------------------------------------------------------- */
5492 {
5493  const float ratio = RNA_float_get(op->ptr, "ratio");
5494  bool use_vertex_group = RNA_boolean_get(op->ptr, "use_vertex_group");
5495  const float vertex_group_factor = RNA_float_get(op->ptr, "vertex_group_factor");
5496  const bool invert_vertex_group = RNA_boolean_get(op->ptr, "invert_vertex_group");
5497  const bool use_symmetry = RNA_boolean_get(op->ptr, "use_symmetry");
5498  const float symmetry_eps = 0.00002f;
5499  const int symmetry_axis = use_symmetry ? RNA_enum_get(op->ptr, "symmetry_axis") : -1;
5500 
5501  /* nop */
5502  if (ratio == 1.0f) {
5503  return OPERATOR_FINISHED;
5504  }
5505 
5506  ViewLayer *view_layer = CTX_data_view_layer(C);
5507  uint objects_len = 0;
5509  view_layer, CTX_wm_view3d(C), &objects_len);
5510 
5511  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5512  Object *obedit = objects[ob_index];
5513  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5514  BMesh *bm = em->bm;
5515  if (bm->totedgesel == 0) {
5516  continue;
5517  }
5518 
5519  float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__);
5520  {
5521  const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
5522  const int defbase_act = obedit->actdef - 1;
5523 
5524  if (use_vertex_group && (cd_dvert_offset == -1)) {
5525  BKE_report(op->reports, RPT_WARNING, "No active vertex group");
5526  use_vertex_group = false;
5527  }
5528 
5529  BMIter iter;
5530  BMVert *v;
5531  int i;
5532  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
5533  float weight = 0.0f;
5535  if (use_vertex_group) {
5536  const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
5537  weight = BKE_defvert_find_weight(dv, defbase_act);
5538  if (invert_vertex_group) {
5539  weight = 1.0f - weight;
5540  }
5541  }
5542  else {
5543  weight = 1.0f;
5544  }
5545  }
5546 
5547  vweights[i] = weight;
5548  BM_elem_index_set(v, i); /* set_inline */
5549  }
5551  }
5552 
5553  float ratio_adjust;
5554 
5555  if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) {
5556  ratio_adjust = ratio;
5557  }
5558  else {
5567  int totface_basis = 0;
5568  int totface_adjacent = 0;
5569  BMIter iter;
5570  BMFace *f;
5571  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
5572  /* count faces during decimation, ngons are triangulated */
5573  const int f_len = f->len > 4 ? (f->len - 2) : 1;
5574  totface_basis += f_len;
5575 
5576  BMLoop *l_iter, *l_first;
5577  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
5578  do {
5579  if (vweights[BM_elem_index_get(l_iter->v)] != 0.0f) {
5580  totface_adjacent += f_len;
5581  break;
5582  }
5583  } while ((l_iter = l_iter->next) != l_first);
5584  }
5585 
5586  ratio_adjust = ratio;
5587  ratio_adjust = 1.0f - ratio_adjust;
5588  ratio_adjust *= (float)totface_adjacent / (float)totface_basis;
5589  ratio_adjust = 1.0f - ratio_adjust;
5590  }
5591 
5593  em->bm, ratio_adjust, vweights, vertex_group_factor, false, symmetry_axis, symmetry_eps);
5594 
5595  MEM_freeN(vweights);
5596 
5597  {
5598  short selectmode = em->selectmode;
5599  if ((selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
5600  /* ensure we flush edges -> faces */
5601  selectmode |= SCE_SELECT_EDGE;
5602  }
5603  EDBM_selectmode_flush_ex(em, selectmode);
5604  }
5605  EDBM_update_generic(obedit->data, true, true);
5606  }
5607  MEM_freeN(objects);
5608 
5609  return OPERATOR_FINISHED;
5610 }
5611 
5613 {
5614  return true;
5615 }
5616 
5618 {
5619  uiLayout *layout = op->layout, *row, *col, *sub;
5621  PointerRNA ptr;
5622 
5623  RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
5624 
5625  uiLayoutSetPropSep(layout, true);
5626 
5627  uiItemR(layout, &ptr, "ratio", 0, NULL, ICON_NONE);
5628 
5629  uiItemR(layout, &ptr, "use_vertex_group", 0, NULL, ICON_NONE);
5630  col = uiLayoutColumn(layout, false);
5631  uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_vertex_group"));
5632  uiItemR(col, &ptr, "vertex_group_factor", 0, NULL, ICON_NONE);
5633  uiItemR(col, &ptr, "invert_vertex_group", 0, NULL, ICON_NONE);
5634 
5635  row = uiLayoutRowWithHeading(layout, true, IFACE_("Symmetry"));
5636  uiItemR(row, &ptr, "use_symmetry", 0, "", ICON_NONE);
5637  sub = uiLayoutRow(row, true);
5638  uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_symmetry"));
5639  uiItemR(sub, &ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
5640 }
5641 
5643 {
5644  /* identifiers */
5645  ot->name = "Decimate Geometry";
5646  ot->idname = "MESH_OT_decimate";
5647  ot->description = "Simplify geometry by collapsing edges";
5648 
5649  /* api callbacks */
5652  ot->ui = edbm_decimate_ui;
5654 
5655  /* flags */
5657 
5658  /* Note, keep in sync with 'rna_def_modifier_decimate' */
5659  RNA_def_float(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f);
5660 
5662  "use_vertex_group",
5663  false,
5664  "Vertex Group",
5665  "Use active vertex group as an influence");
5667  "vertex_group_factor",
5668  1.0f,
5669  0.0f,
5670  1000.0f,
5671  "Weight",
5672  "Vertex group strength",
5673  0.0f,
5674  10.0f);
5676  ot->srna, "invert_vertex_group", false, "Invert", "Invert vertex group influence");
5677 
5678  RNA_def_boolean(ot->srna, "use_symmetry", false, "Symmetry", "Maintain symmetry on an axis");
5679 
5680  RNA_def_enum(ot->srna, "symmetry_axis", rna_enum_axis_xyz_items, 1, "Axis", "Axis of symmetry");
5681 }
5682 
5685 /* -------------------------------------------------------------------- */
5689 static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag)
5690 {
5691  PropertyRNA *prop;
5692 
5693  prop = RNA_def_boolean(
5694  ot->srna, "use_verts", value, "Dissolve Vertices", "Dissolve remaining vertices");
5695 
5696  if (flag) {
5697  RNA_def_property_flag(prop, flag);
5698  }
5699 }
5701 {
5703  "use_face_split",
5704  false,
5705  "Face Split",
5706  "Split off face corners to maintain surrounding geometry");
5707 }
5709 {
5711  "use_boundary_tear",
5712  false,
5713  "Tear Boundary",
5714  "Split off face corners instead of merging faces");
5715 }
5716 
5718 {
5719  const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
5720  const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
5721 
5722  ViewLayer *view_layer = CTX_data_view_layer(C);
5723  uint objects_len = 0;
5725  view_layer, CTX_wm_view3d(C), &objects_len);
5726 
5727  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5728  Object *obedit = objects[ob_index];
5729  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5730 
5731  if (em->bm->totvertsel == 0) {
5732  continue;
5733  }
5734 
5736 
5737  if (!EDBM_op_callf(em,
5738  op,
5739  "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
5741  use_face_split,
5742  use_boundary_tear)) {
5743  continue;
5744  }
5745 
5747 
5748  EDBM_update_generic(obedit->data, true, true);
5749  }
5750 
5751  MEM_freeN(objects);
5752  return OPERATOR_FINISHED;
5753 }
5754 
5756 {
5757  /* identifiers */
5758  ot->name = "Dissolve Vertices";
5759  ot->description = "Dissolve vertices, merge edges and faces";
5760  ot->idname = "MESH_OT_dissolve_verts";
5761 
5762  /* api callbacks */
5765 
5766  /* flags */
5768 
5771 }
5772 
5775 /* -------------------------------------------------------------------- */
5780 {
5781  const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
5782  const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
5783 
5784  ViewLayer *view_layer = CTX_data_view_layer(C);
5785  uint objects_len = 0;
5787  view_layer, CTX_wm_view3d(C), &objects_len);
5788  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5789  Object *obedit = objects[ob_index];
5790  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5791 
5792  if (em->bm->totedgesel == 0) {
5793  continue;
5794  }
5795 
5797 
5798  if (!EDBM_op_callf(em,
5799  op,
5800  "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
5802  use_verts,
5803  use_face_split)) {
5804  continue;
5805  }
5806 
5808 
5809  EDBM_update_generic(obedit->data, true, true);
5810  }
5811 
5812  MEM_freeN(objects);
5813 
5814  return OPERATOR_FINISHED;
5815 }
5816 
5818 {
5819  /* identifiers */
5820  ot->name = "Dissolve Edges";
5821  ot->description = "Dissolve edges, merging faces";
5822  ot->idname = "MESH_OT_dissolve_edges";
5823 
5824  /* api callbacks */
5827 
5828  /* flags */
5830 
5833 }
5834 
5837 /* -------------------------------------------------------------------- */
5842 {
5843  const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
5844  ViewLayer *view_layer = CTX_data_view_layer(C);
5845  uint objects_len = 0;
5847  view_layer, CTX_wm_view3d(C), &objects_len);
5848  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5849  Object *obedit = objects[ob_index];
5850  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5851 
5852  if (em->bm->totfacesel == 0) {
5853  continue;
5854  }
5855 
5857 
5858  if (!EDBM_op_call_and_selectf(em,
5859  op,
5860  "region.out",
5861  true,
5862  "dissolve_faces faces=%hf use_verts=%b",
5864  use_verts)) {
5865  continue;
5866  }
5867 
5869 
5870  EDBM_update_generic(obedit->data, true, true);
5871  }
5872  MEM_freeN(objects);
5873 
5874  return OPERATOR_FINISHED;
5875 }
5876 
5878 {
5879  /* identifiers */
5880  ot->name = "Dissolve Faces";
5881  ot->description = "Dissolve faces";
5882  ot->idname = "MESH_OT_dissolve_faces";
5883 
5884  /* api callbacks */
5887 
5888  /* flags */
5890 
5891  edbm_dissolve_prop__use_verts(ot, false, 0);
5892 }
5893 
5896 /* -------------------------------------------------------------------- */
5901 {
5902  Object *obedit = CTX_data_edit_object(C);
5903  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5904  PropertyRNA *prop;
5905 
5906  prop = RNA_struct_find_property(op->ptr, "use_verts");
5907  if (!RNA_property_is_set(op->ptr, prop)) {
5908  /* always enable in edge-mode */
5909  if ((em->selectmode & SCE_SELECT_FACE) == 0) {
5910  RNA_property_boolean_set(op->ptr, prop, true);
5911  }
5912  }
5913 
5914  if (em->selectmode & SCE_SELECT_VERTEX) {
5915  return edbm_dissolve_verts_exec(C, op);
5916  }
5917  if (em->selectmode & SCE_SELECT_EDGE) {
5918  return edbm_dissolve_edges_exec(C, op);
5919  }
5920  return edbm_dissolve_faces_exec(C, op);
5921 }
5922 
5924 {
5925  /* identifiers */
5926  ot->name = "Dissolve Selection";
5927  ot->description = "Dissolve geometry based on the selection mode";
5928  ot->idname = "MESH_OT_dissolve_mode";
5929 
5930  /* api callbacks */
5933 
5934  /* flags */
5936 
5940 }
5941 
5944 /* -------------------------------------------------------------------- */
5949 {
5950  const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
5951  const bool use_dissolve_boundaries = RNA_boolean_get(op->ptr, "use_dissolve_boundaries");
5952  const int delimit = RNA_enum_get(op->ptr, "delimit");
5953  char dissolve_flag;
5954 
5955  ViewLayer *view_layer = CTX_data_view_layer(C);
5956  uint objects_len = 0;
5958  view_layer, CTX_wm_view3d(C), &objects_len);
5959  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5960  Object *obedit = objects[ob_index];
5961  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5962  BMesh *bm = em->bm;
5963 
5964  if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) {
5965  continue;
5966  }
5967 
5969 
5970  if (em->selectmode == SCE_SELECT_FACE) {
5971  /* flush selection to tags and untag edges/verts with partially selected faces */
5972  BMIter iter;
5973  BMIter liter;
5974 
5975  BMElem *ele;
5976  BMFace *f;
5977  BMLoop *l;
5978 
5979  BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
5981  }
5982  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
5984  }
5985 
5986  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
5987  if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
5988  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
5991  }
5992  }
5993  }
5994 
5995  dissolve_flag = BM_ELEM_TAG;
5996  }
5997  else {
5998  dissolve_flag = BM_ELEM_SELECT;
5999  }
6000 
6002  em,
6003  op,
6004  "region.out",
6005  true,
6006  "dissolve_limit edges=%he verts=%hv angle_limit=%f use_dissolve_boundaries=%b delimit=%i",
6007  dissolve_flag,
6008  dissolve_flag,
6009  angle_limit,
6010  use_dissolve_boundaries,
6011  delimit);
6012 
6014 
6015  EDBM_update_generic(obedit->data, true, true);
6016  }
6017  MEM_freeN(objects);
6018 
6019  return OPERATOR_FINISHED;
6020 }
6021 
6023 {
6024  PropertyRNA *prop;
6025 
6026  /* identifiers */
6027  ot->name = "Limited Dissolve";
6028  ot->idname = "MESH_OT_dissolve_limited";
6029  ot->description =
6030  "Dissolve selected edges and vertices, limited by the angle of surrounding geometry";
6031 
6032  /* api callbacks */
6035 
6036  /* flags */
6038 
6039  prop = RNA_def_float_rotation(ot->srna,
6040  "angle_limit",
6041  0,
6042  NULL,
6043  0.0f,
6044  DEG2RADF(180.0f),
6045  "Max Angle",
6046  "Angle limit",
6047  0.0f,
6048  DEG2RADF(180.0f));
6051  "use_dissolve_boundaries",
6052  false,
6053  "All Boundaries",
6054  "Dissolve all vertices in between face boundaries");
6056  "delimit",
6059  "Delimit",
6060  "Delimit dissolve operation");
6061 }
6062 
6065 /* -------------------------------------------------------------------- */
6070 {
6071  ViewLayer *view_layer = CTX_data_view_layer(C);
6072  int totelem_old[3] = {0, 0, 0};
6073  int totelem_new[3] = {0, 0, 0};
6074 
6075  uint objects_len = 0;
6077  view_layer, CTX_wm_view3d(C), &objects_len);
6078 
6079  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6080  Object *obedit = objects[ob_index];
6081  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6082  BMesh *bm = em->bm;
6083  totelem_old[0] += bm->totvert;
6084  totelem_old[1] += bm->totedge;
6085  totelem_old[2] += bm->totface;
6086  } /* objects */
6087 
6088  const float thresh = RNA_float_get(op->ptr, "threshold");
6089 
6090  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6091  Object *obedit = objects[ob_index];
6092  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6093  BMesh *bm = em->bm;
6094 
6095  if (!EDBM_op_callf(em, op, "dissolve_degenerate edges=%he dist=%f", BM_ELEM_SELECT, thresh)) {
6096  continue;
6097  }
6098 
6099  /* tricky to maintain correct selection here, so just flush up from verts */
6100  EDBM_select_flush(em);
6101 
6102  EDBM_update_generic(obedit->data, true, true);
6103 
6104  totelem_new[0] += bm->totvert;
6105  totelem_new[1] += bm->totedge;
6106  totelem_new[2] += bm->totface;
6107  }
6108  MEM_freeN(objects);
6109 
6110  edbm_report_delete_info(op->reports, totelem_old, totelem_new);
6111 
6112  return OPERATOR_FINISHED;
6113 }
6114 
6116 {
6117  /* identifiers */
6118  ot->name = "Degenerate Dissolve";
6119  ot->idname = "MESH_OT_dissolve_degenerate";
6120  ot->description = "Dissolve zero area faces and zero length edges";
6121 
6122  /* api callbacks */
6125 
6126  /* flags */
6128 
6130  "threshold",
6131  1e-4f,
6132  1e-6f,
6133  50.0f,
6134  "Merge Distance",
6135  "Maximum distance between elements to merge",
6136  1e-5f,
6137  10.0f);
6138 }
6139 
6142 /* -------------------------------------------------------------------- */
6146 /* internally uses dissolve */
6148 {
6149  const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
6150  ViewLayer *view_layer = CTX_data_view_layer(C);
6151 
6152  uint objects_len = 0;
6154  view_layer, CTX_wm_view3d(C), &objects_len);
6155  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6156  Object *obedit = objects[ob_index];
6157  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6158 
6159  if (em->bm->totedgesel == 0) {
6160  continue;
6161  }
6162 
6163  /* deal with selection */
6164  {
6165  BMEdge *e;
6166  BMIter iter;
6167 
6169 
6170  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
6171  if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
6172  BMLoop *l_iter = e->l;
6173  do {
6174  BM_elem_flag_enable(l_iter->f, BM_ELEM_TAG);
6175  } while ((l_iter = l_iter->radial_next) != e->l);
6176  }
6177  }
6178  }
6179 
6180  if (!EDBM_op_callf(em,
6181  op,
6182  "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
6184  true,
6185  use_face_split)) {
6186  continue;
6187  }
6188 
6190 
6192 
6193  EDBM_update_generic(obedit->data, true, true);
6194  }
6195 
6196  MEM_freeN(objects);
6197  return OPERATOR_FINISHED;
6198 }
6199 
6201 {
6202  /* identifiers */
6203  ot->name = "Delete Edge Loop";
6204  ot->description = "Delete an edge loop by merging the faces on each side";
6205  ot->idname = "MESH_OT_delete_edgeloop";
6206 
6207  /* api callbacks */
6210 
6211  /* flags */
6213 
6215  "use_face_split",
6216  true,
6217  "Face Split",
6218  "Split off face corners to maintain surrounding geometry");
6219 }
6220 
6223 /* -------------------------------------------------------------------- */
6228 {
6229  ViewLayer *view_layer = CTX_data_view_layer(C);
6230  uint objects_len = 0;
6232  view_layer, CTX_wm_view3d(C), &objects_len);
6233  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6234  Object *obedit = objects[ob_index];
6235  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6236  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
6237  continue;
6238  }
6240 
6241  BMOperator bmop;
6242  EDBM_op_init(em, &bmop, op, "split geom=%hvef use_only_faces=%b", BM_ELEM_SELECT, false);
6243  BMO_op_exec(em->bm, &bmop);
6246  em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
6247 
6249 
6250  if (!EDBM_op_finish(em, &bmop, op, true)) {
6251  continue;
6252  }
6253 
6254  /* Geometry has changed, need to recalc normals and looptris */
6256 
6257  EDBM_update_generic(obedit->data, true, true);
6258  }
6259  MEM_freeN(objects);
6260 
6261  return OPERATOR_FINISHED;
6262 }
6263 
6265 {
6266  /* identifiers */
6267  ot->name = "Split";
6268  ot->idname = "MESH_OT_split";
6269  ot->description = "Split off selected geometry from connected unselected geometry";
6270 
6271  /* api callbacks */
6272  ot->exec = edbm_split_exec;
6274 
6275  /* flags */
6277 }
6278 
6281 /* -------------------------------------------------------------------- */
6288 enum {
6304 };
6305 
6306 typedef struct BMElemSort {
6308  float srt;
6310  int org_idx;
6312 
6313 static int bmelemsort_comp(const void *v1, const void *v2)
6314 {
6315  const BMElemSort *x1 = v1, *x2 = v2;
6316 
6317  return (x1->srt > x2->srt) - (x1->srt < x2->srt);
6318 }
6319 
6320 /* Reorders vertices/edges/faces using a given methods. Loops are not supported. */
6322  Scene *scene,
6323  Object *ob,
6324  RegionView3D *rv3d,
6325  const int types,
6326  const int flag,
6327  const int action,
6328  const int reverse,
6329  const uint seed)
6330 {
6332 
6333  BMVert *ve;
6334  BMEdge *ed;
6335  BMFace *fa;
6336  BMIter iter;
6337 
6338  /* In all five elements below, 0 = vertices, 1 = edges, 2 = faces. */
6339  /* Just to mark protected elements. */
6340  char *pblock[3] = {NULL, NULL, NULL}, *pb;
6341  BMElemSort *sblock[3] = {NULL, NULL, NULL}, *sb;
6342  uint *map[3] = {NULL, NULL, NULL}, *mp;
6343  int totelem[3] = {0, 0, 0};
6344  int affected[3] = {0, 0, 0};
6345  int i, j;
6346 
6347  if (!(types && flag && action)) {
6348  return;
6349  }
6350 
6351  if (types & BM_VERT) {
6352  totelem[0] = em->bm->totvert;
6353  }
6354  if (types & BM_EDGE) {
6355  totelem[1] = em->bm->totedge;
6356  }
6357  if (types & BM_FACE) {
6358  totelem[2] = em->bm->totface;
6359  }
6360 
6361  if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) {
6362  float mat[4][4];
6363  float fact = reverse ? -1.0 : 1.0;
6364  int coidx = (action == SRT_VIEW_ZAXIS) ? 2 : 0;
6365 
6366  /* Apply the view matrix to the object matrix. */
6367  mul_m4_m4m4(mat, rv3d->viewmat, ob->obmat);
6368 
6369  if (totelem[0]) {
6370  pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
6371  sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock");
6372 
6373  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6374  if (BM_elem_flag_test(ve, flag)) {
6375  float co[3];
6376  mul_v3_m4v3(co, mat, ve->co);
6377 
6378  pb[i] = false;
6379  sb[affected[0]].org_idx = i;
6380  sb[affected[0]++].srt = co[coidx] * fact;
6381  }
6382  else {
6383  pb[i] = true;
6384  }
6385  }
6386  }
6387 
6388  if (totelem[1]) {
6389  pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
6390  sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock");
6391 
6392  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6393  if (BM_elem_flag_test(ed, flag)) {
6394  float co[3];
6395  mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
6396  mul_m4_v3(mat, co);
6397 
6398  pb[i] = false;
6399  sb[affected[1]].org_idx = i;
6400  sb[affected[1]++].srt = co[coidx] * fact;
6401  }
6402  else {
6403  pb[i] = true;
6404  }
6405  }
6406  }
6407 
6408  if (totelem[2]) {
6409  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6410  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6411 
6412  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6413  if (BM_elem_flag_test(fa, flag)) {
6414  float co[3];
6416  mul_m4_v3(mat, co);
6417 
6418  pb[i] = false;
6419  sb[affected[2]].org_idx = i;
6420  sb[affected[2]++].srt = co[coidx] * fact;
6421  }
6422  else {
6423  pb[i] = true;
6424  }
6425  }
6426  }
6427  }
6428 
6429  else if (action == SRT_CURSOR_DISTANCE) {
6430  float cur[3];
6431  float mat[4][4];
6432  float fact = reverse ? -1.0 : 1.0;
6433 
6435 
6436  invert_m4_m4(mat, ob->obmat);
6437  mul_m4_v3(mat, cur);
6438 
6439  if (totelem[0]) {
6440  pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
6441  sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock");
6442 
6443  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6444  if (BM_elem_flag_test(ve, flag)) {
6445  pb[i] = false;
6446  sb[affected[0]].org_idx = i;
6447  sb[affected[0]++].srt = len_squared_v3v3(cur, ve->co) * fact;
6448  }
6449  else {
6450  pb[i] = true;
6451  }
6452  }
6453  }
6454 
6455  if (totelem[1]) {
6456  pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
6457  sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock");
6458 
6459  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6460  if (BM_elem_flag_test(ed, flag)) {
6461  float co[3];
6462  mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
6463 
6464  pb[i] = false;
6465  sb[affected[1]].org_idx = i;
6466  sb[affected[1]++].srt = len_squared_v3v3(cur, co) * fact;
6467  }
6468  else {
6469  pb[i] = true;
6470  }
6471  }
6472  }
6473 
6474  if (totelem[2]) {
6475  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6476  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6477 
6478  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6479  if (BM_elem_flag_test(fa, flag)) {
6480  float co[3];
6482 
6483  pb[i] = false;
6484  sb[affected[2]].org_idx = i;
6485  sb[affected[2]++].srt = len_squared_v3v3(cur, co) * fact;
6486  }
6487  else {
6488  pb[i] = true;
6489  }
6490  }
6491  }
6492  }
6493 
6494  /* Faces only! */
6495  else if (action == SRT_MATERIAL && totelem[2]) {
6496  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6497  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6498 
6499  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6500  if (BM_elem_flag_test(fa, flag)) {
6501  /* Reverse materials' order, not order of faces inside each mat! */
6502  /* Note: cannot use totcol, as mat_nr may sometimes be greater... */
6503  float srt = reverse ? (float)(MAXMAT - fa->mat_nr) : (float)fa->mat_nr;
6504  pb[i] = false;
6505  sb[affected[2]].org_idx = i;
6506  /* Multiplying with totface and adding i ensures us
6507  * we keep current order for all faces of same mat. */
6508  sb[affected[2]++].srt = srt * ((float)totelem[2]) + ((float)i);
6509  // printf("e: %d; srt: %f; final: %f\n",
6510  // i, srt, srt * ((float)totface) + ((float)i));
6511  }
6512  else {
6513  pb[i] = true;
6514  }
6515  }
6516  }
6517 
6518  else if (action == SRT_SELECTED) {
6519  uint *tbuf[3] = {NULL, NULL, NULL}, *tb;
6520 
6521  if (totelem[0]) {
6522  tb = tbuf[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert tbuf");
6523  mp = map[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert map");
6524 
6525  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6526  if (BM_elem_flag_test(ve, flag)) {
6527  mp[affected[0]++] = i;
6528  }
6529  else {
6530  *tb = i;
6531  tb++;
6532  }
6533  }
6534  }
6535 
6536  if (totelem[1]) {
6537  tb = tbuf[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge tbuf");
6538  mp = map[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge map");
6539 
6540  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6541  if (BM_elem_flag_test(ed, flag)) {
6542  mp[affected[1]++] = i;
6543  }
6544  else {
6545  *tb = i;
6546  tb++;
6547  }
6548  }
6549  }
6550 
6551  if (totelem[2]) {
6552  tb = tbuf[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face tbuf");
6553  mp = map[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face map");
6554 
6555  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6556  if (BM_elem_flag_test(fa, flag)) {
6557  mp[affected[2]++] = i;
6558  }
6559  else {
6560  *tb = i;
6561  tb++;
6562  }
6563  }
6564  }
6565 
6566  for (j = 3; j--;) {
6567  int tot = totelem[j];
6568  int aff = affected[j];
6569  tb = tbuf[j];
6570  mp = map[j];
6571  if (!(tb && mp)) {
6572  continue;
6573  }
6574  if (ELEM(aff, 0, tot)) {
6575  MEM_freeN(tb);
6576  MEM_freeN(mp);
6577  map[j] = NULL;
6578  continue;
6579  }
6580  if (reverse) {
6581  memcpy(tb + (tot - aff), mp, aff * sizeof(int));
6582  }
6583  else {
6584  memcpy(mp + aff, tb, (tot - aff) * sizeof(int));
6585  tb = mp;
6586  mp = map[j] = tbuf[j];
6587  tbuf[j] = tb;
6588  }
6589 
6590  /* Reverse mapping, we want an org2new one! */
6591  for (i = tot, tb = tbuf[j] + tot - 1; i--; tb--) {
6592  mp[*tb] = i;
6593  }
6594  MEM_freeN(tbuf[j]);
6595  }
6596  }
6597 
6598  else if (action == SRT_RANDOMIZE) {
6599  if (totelem[0]) {
6600  /* Re-init random generator for each element type, to get consistent random when
6601  * enabling/disabling an element type. */
6602  RNG *rng = BLI_rng_new_srandom(seed);
6603  pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
6604  sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock");
6605 
6606  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6607  if (BM_elem_flag_test(ve, flag)) {
6608  pb[i] = false;
6609  sb[affected[0]].org_idx = i;
6610  sb[affected[0]++].srt = BLI_rng_get_float(rng);
6611  }
6612  else {
6613  pb[i] = true;
6614  }
6615  }
6616 
6617  BLI_rng_free(rng);
6618  }
6619 
6620  if (totelem[1]) {
6621  RNG *rng = BLI_rng_new_srandom(seed);
6622  pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
6623  sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock");
6624 
6625  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6626  if (BM_elem_flag_test(ed, flag)) {
6627  pb[i] = false;
6628  sb[affected[1]].org_idx = i;
6629  sb[affected[1]++].srt = BLI_rng_get_float(rng);
6630  }
6631  else {
6632  pb[i] = true;
6633  }
6634  }
6635 
6636  BLI_rng_free(rng);
6637  }
6638 
6639  if (totelem[2]) {
6640  RNG *rng = BLI_rng_new_srandom(seed);
6641  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6642  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6643 
6644  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6645  if (BM_elem_flag_test(fa, flag)) {
6646  pb[i] = false;
6647  sb[affected[2]].org_idx = i;
6648  sb[affected[2]++].srt = BLI_rng_get_float(rng);
6649  }
6650  else {
6651  pb[i] = true;
6652  }
6653  }
6654 
6655  BLI_rng_free(rng);
6656  }
6657  }
6658 
6659  else if (action == SRT_REVERSE) {
6660  if (totelem[0]) {
6661  pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
6662  sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock");
6663 
6664  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6665  if (BM_elem_flag_test(ve, flag)) {
6666  pb[i] = false;
6667  sb[affected[0]].org_idx = i;
6668  sb[affected[0]++].srt = (float)-i;
6669  }
6670  else {
6671  pb[i] = true;
6672  }
6673  }
6674  }
6675 
6676  if (totelem[1]) {
6677  pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
6678  sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock");
6679 
6680  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6681  if (BM_elem_flag_test(ed, flag)) {
6682  pb[i] = false;
6683  sb[affected[1]].org_idx = i;
6684  sb[affected[1]++].srt = (float)-i;
6685  }
6686  else {
6687  pb[i] = true;
6688  }
6689  }
6690  }
6691 
6692  if (totelem[2]) {
6693  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6694  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6695 
6696  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6697  if (BM_elem_flag_test(fa, flag)) {
6698  pb[i] = false;
6699  sb[affected[2]].org_idx = i;
6700  sb[affected[2]++].srt = (float)-i;
6701  }
6702  else {
6703  pb[i] = true;
6704  }
6705  }
6706  }
6707  }
6708 
6709  /* printf("%d vertices: %d to be affected...\n", totelem[0], affected[0]);*/
6710  /* printf("%d edges: %d to be affected...\n", totelem[1], affected[1]);*/
6711  /* printf("%d faces: %d to be affected...\n", totelem[2], affected[2]);*/
6712  if (affected[0] == 0 && affected[1] == 0 && affected[2] == 0) {
6713  for (j = 3; j--;) {
6714  if (pblock[j]) {
6715  MEM_freeN(pblock[j]);
6716  }
6717  if (sblock[j]) {
6718  MEM_freeN(sblock[j]);
6719  }
6720  if (map[j]) {
6721  MEM_freeN(map[j]);
6722  }
6723  }
6724  return;
6725  }
6726 
6727  /* Sort affected elements, and populate mapping arrays, if needed. */
6728  for (j = 3; j--;) {
6729  pb = pblock[j];
6730  sb = sblock[j];
6731  if (pb && sb && !map[j]) {
6732  const char *p_blk;
6733  BMElemSort *s_blk;
6734  int tot = totelem[j];
6735  int aff = affected[j];
6736 
6737  qsort(sb, aff, sizeof(BMElemSort), bmelemsort_comp);
6738 
6739  mp = map[j] = MEM_mallocN(sizeof(int) * tot, "sort_bmelem map");
6740  p_blk = pb + tot - 1;
6741  s_blk = sb + aff - 1;
6742  for (i = tot; i--; p_blk--) {
6743  if (*p_blk) { /* Protected! */
6744  mp[i] = i;
6745  }
6746  else {
6747  mp[s_blk->org_idx] = i;
6748  s_blk--;
6749  }
6750  }
6751  }
6752  if (pb) {
6753  MEM_freeN(pb);
6754  }
6755  if (sb) {
6756  MEM_freeN(sb);
6757  }
6758  }
6759 
6760  BM_mesh_remap(em->bm, map[0], map[1], map[2]);
6763 
6764  for (j = 3; j--;) {
6765  if (map[j]) {
6766  MEM_freeN(map[j]);
6767  }
6768  }
6769 }
6770 
6772 {
6774  ViewLayer *view_layer = CTX_data_view_layer(C);
6775  Object *ob_active = CTX_data_edit_object(C);
6776 
6777  /* may be NULL */
6779 
6780  const int action = RNA_enum_get(op->ptr, "type");
6781  PropertyRNA *prop_elem_types = RNA_struct_find_property(op->ptr, "elements");
6782  const bool use_reverse = RNA_boolean_get(op->ptr, "reverse");
6783  uint seed = RNA_int_get(op->ptr, "seed");
6784  int elem_types = 0;
6785 
6786  if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) {
6787  if (rv3d == NULL) {
6788  BKE_report(op->reports, RPT_ERROR, "View not found, cannot sort by view axis");
6789  return OPERATOR_CANCELLED;
6790  }
6791  }
6792 
6793  /* If no elem_types set, use current selection mode to set it! */
6794  if (RNA_property_is_set(op->ptr, prop_elem_types)) {
6795  elem_types = RNA_property_enum_get(op->ptr, prop_elem_types);
6796  }
6797  else {
6798  BMEditMesh *em = BKE_editmesh_from_object(ob_active);
6799  if (em->selectmode & SCE_SELECT_VERTEX) {
6800  elem_types |= BM_VERT;
6801  }
6802  if (em->selectmode & SCE_SELECT_EDGE) {
6803  elem_types |= BM_EDGE;
6804  }
6805  if (em->selectmode & SCE_SELECT_FACE) {
6806  elem_types |= BM_FACE;
6807  }
6808  RNA_enum_set(op->ptr, "elements", elem_types);
6809  }
6810 
6811  uint objects_len = 0;
6813  view_layer, CTX_wm_view3d(C), &objects_len);
6814 
6815  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6816  Object *ob = objects[ob_index];
6818  BMesh *bm = em->bm;
6819 
6820  if (!((elem_types & BM_VERT && bm->totvertsel > 0) ||
6821  (elem_types & BM_EDGE && bm->totedgesel > 0) ||
6822  (elem_types & BM_FACE && bm->totfacesel > 0))) {
6823  continue;
6824  }
6825 
6826  int seed_iter = seed;
6827 
6828  /* This gives a consistent result regardless of object order */
6829  if (ob_index) {
6830  seed_iter += BLI_ghashutil_strhash_p(ob->id.name);
6831  }
6832 
6834  C, scene, ob, rv3d, elem_types, BM_ELEM_SELECT, action, use_reverse, seed_iter);
6835  }
6836  MEM_freeN(objects);
6837  return OPERATOR_FINISHED;
6838 }
6839 
6841  wmOperator *op,
6842  const PropertyRNA *prop)
6843 {
6844  const char *prop_id = RNA_property_identifier(prop);
6845  const int action = RNA_enum_get(op->ptr, "type");
6846 
6847  /* Only show seed for randomize action! */
6848  if (STREQ(prop_id, "seed")) {
6849  if (action == SRT_RANDOMIZE) {
6850  return true;
6851  }
6852  return false;
6853  }
6854 
6855  /* Hide seed for reverse and randomize actions! */
6856  if (STREQ(prop_id, "reverse")) {
6857  if (ELEM(action, SRT_RANDOMIZE, SRT_REVERSE)) {
6858  return false;
6859  }
6860  return true;
6861  }
6862 
6863  return true;
6864 }
6865 
6867 {
6868  static const EnumPropertyItem type_items[] = {
6869  {SRT_VIEW_ZAXIS,
6870  "VIEW_ZAXIS",
6871  0,
6872  "View Z Axis",
6873  "Sort selected elements from farthest to nearest one in current view"},
6874  {SRT_VIEW_XAXIS,
6875  "VIEW_XAXIS",
6876  0,
6877  "View X Axis",
6878  "Sort selected elements from left to right one in current view"},
6880  "CURSOR_DISTANCE",
6881  0,
6882  "Cursor Distance",
6883  "Sort selected elements from nearest to farthest from 3D cursor"},
6884  {SRT_MATERIAL,
6885  "MATERIAL",
6886  0,
6887  "Material",
6888  "Sort selected faces from smallest to greatest material index"},
6889  {SRT_SELECTED,
6890  "SELECTED",
6891  0,
6892  "Selected",
6893  "Move all selected elements in first places, preserving their relative order.\n"
6894  "Warning: This will affect unselected elements' indices as well"},
6895  {SRT_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Randomize order of selected elements"},
6896  {SRT_REVERSE, "REVERSE", 0, "Reverse", "Reverse current order of selected elements"},
6897  {0, NULL, 0, NULL, NULL},
6898  };
6899 
6900  static const EnumPropertyItem elem_items[] = {
6901  {BM_VERT, "VERT", 0, "Vertices", ""},
6902  {BM_EDGE, "EDGE", 0, "Edges", ""},
6903  {BM_FACE, "FACE", 0, "Faces", ""},
6904  {0, NULL, 0, NULL, NULL},
6905  };
6906 
6907  /* identifiers */
6908  ot->name = "Sort Mesh Elements";
6909  ot->description =
6910  "The order of selected vertices/edges/faces is modified, based on a given method";
6911  ot->idname = "MESH_OT_sort_elements";
6912 
6913  /* api callbacks */
6918 
6919  /* flags */
6921 
6922  /* properties */
6923  ot->prop = RNA_def_enum(ot->srna,
6924  "type",
6925  type_items,
6927  "Type",
6928  "Type of reordering operation to apply");
6930  "elements",
6931  elem_items,
6932  BM_VERT,
6933  "Elements",
6934  "Which elements to affect (vertices, edges and/or faces)");
6935  RNA_def_boolean(ot->srna, "reverse", false, "Reverse", "Reverse the sorting effect");
6936  RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255);
6937 }
6938 
6941 /* -------------------------------------------------------------------- */
6945 enum {
6949 };
6950 
6952 {
6953  /* tags boundary edges from a face selection */
6954  BMIter iter;
6955  BMFace *f;
6956  BMEdge *e;
6957  int totface_del = 0;
6958 
6960 
6961  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
6965  }
6966  else {
6967  BMIter fiter;
6968  bool is_all_sel = true;
6969  /* check if its only used by selected faces */
6970  BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
6972  /* tag face for removal*/
6973  if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
6975  totface_del++;
6976  }
6977  }
6978  else {
6979  is_all_sel = false;
6980  }
6981  }
6982 
6983  if (is_all_sel == false) {
6985  }
6986  }
6987  }
6988  }
6989 
6990  return totface_del;
6991 }
6992 
6994  BMEditMesh *em,
6995  struct Mesh *me,
6996  const bool use_pairs,
6997  const bool use_cyclic,
6998  const bool use_merge,
6999  const float merge_factor,
7000  const int twist_offset)
7001 {
7002  BMOperator bmop;
7003  char edge_hflag;
7004  int totface_del = 0;
7005  BMFace **totface_del_arr = NULL;
7006  const bool use_faces = (em->bm->totfacesel != 0);
7007 
7008  if (use_faces) {
7009  BMIter iter;
7010  BMFace *f;
7011  int i;
7012 
7013  totface_del = edbm_bridge_tag_boundary_edges(em->bm);
7014  totface_del_arr = MEM_mallocN(sizeof(*totface_del_arr) * totface_del, __func__);
7015 
7016  i = 0;
7017  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
7018  if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
7019  totface_del_arr[i++] = f;
7020  }
7021  }
7022  edge_hflag = BM_ELEM_TAG;
7023  }
7024  else {
7025  edge_hflag = BM_ELEM_SELECT;
7026  }
7027 
7028  EDBM_op_init(em,
7029  &bmop,
7030  op,
7031  "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f "
7032  "twist_offset=%i",
7033  edge_hflag,
7034  use_pairs,
7035  use_cyclic,
7036  use_merge,
7037  merge_factor,
7038  twist_offset);
7039 
7040  if (use_faces && totface_del) {
7041  int i;
7043  for (i = 0; i < totface_del; i++) {
7044  BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG);
7045  }
7046  BMO_op_callf(em->bm,
7048  "delete geom=%hf context=%i",
7049  BM_ELEM_TAG,
7051  }
7052 
7053  BMO_op_exec(em->bm, &bmop);
7054 
7055  if (!BMO_error_occurred(em->bm)) {
7056  /* when merge is used the edges are joined and remain selected */
7057  if (use_merge == false) {
7060  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
7061  }
7062 
7063  if (use_merge == false) {
7064  struct EdgeRingOpSubdProps op_props;
7065  mesh_operator_edgering_props_get(op, &op_props);
7066 
7067  if (op_props.cuts) {
7068  BMOperator bmop_subd;
7069  /* we only need face normals updated */
7071 
7072  BMO_op_initf(em->bm,
7073  &bmop_subd,
7074  0,
7075  "subdivide_edgering edges=%S interp_mode=%i cuts=%i smooth=%f "
7076  "profile_shape=%i profile_shape_factor=%f",
7077  &bmop,
7078  "edges.out",
7079  op_props.interp_mode,
7080  op_props.cuts,
7081  op_props.smooth,
7082  op_props.profile_shape,
7083  op_props.profile_shape_factor);
7084  BMO_op_exec(em->bm, &bmop_subd);
7086  em->bm, bmop_subd.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
7087  BMO_op_finish(em->bm, &bmop_subd);
7088  }
7089  }
7090  }
7091 
7092  if (totface_del_arr) {
7093  MEM_freeN(totface_del_arr);
7094  }
7095 
7096  if (EDBM_op_finish(em, &bmop, op, true)) {
7097  EDBM_update_generic(me, true, true);
7098  }
7099 
7100  /* Always return finished so the user can select different options. */
7101  return OPERATOR_FINISHED;
7102 }
7103 
7105 {
7106  const int type = RNA_enum_get(op->ptr, "type");
7107  const bool use_pairs = (type == MESH_BRIDGELOOP_PAIRS);
7108  const bool use_cyclic = (type == MESH_BRIDGELOOP_CLOSED);
7109  const bool use_merge = RNA_boolean_get(op->ptr, "use_merge");
7110  const float merge_factor = RNA_float_get(op->ptr, "merge_factor");
7111  const int twist_offset = RNA_int_get(op->ptr, "twist_offset");
7112  ViewLayer *view_layer = CTX_data_view_layer(C);
7113 
7114  uint objects_len = 0;
7116  view_layer, CTX_wm_view3d(C), &objects_len);
7117  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7118  Object *obedit = objects[ob_index];
7119  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7120 
7121  if (em->bm->totvertsel == 0) {
7122  continue;
7123  }
7124 
7126  op, em, obedit->data, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
7127  }
7128  MEM_freeN(objects);
7129  return OPERATOR_FINISHED;
7130 }
7131 
7133 {
7134  static const EnumPropertyItem type_items[] = {
7135  {MESH_BRIDGELOOP_SINGLE, "SINGLE", 0, "Open Loop", ""},
7136  {MESH_BRIDGELOOP_CLOSED, "CLOSED", 0, "Closed Loop", ""},
7137  {MESH_BRIDGELOOP_PAIRS, "PAIRS", 0, "Loop Pairs", ""},
7138  {0, NULL, 0, NULL, NULL},
7139  };
7140 
7141  /* identifiers */
7142  ot->name = "Bridge Edge Loops";
7143  ot->description = "Create a bridge of faces between two or more selected edge loops";
7144  ot->idname = "MESH_OT_bridge_edge_loops";
7145 
7146  /* api callbacks */
7149 
7150  /* flags */
7152 
7153  ot->prop = RNA_def_enum(ot->srna,
7154  "type",
7155  type_items,
7157  "Connect Loops",
7158  "Method of bridging multiple loops");
7159 
7160  RNA_def_boolean(ot->srna, "use_merge", false, "Merge", "Merge rather than creating faces");
7161  RNA_def_float(ot->srna, "merge_factor", 0.5f, 0.0f, 1.0f, "Merge Factor", "", 0.0f, 1.0f);
7162  RNA_def_int(ot->srna,
7163  "twist_offset",
7164  0,
7165  -1000,
7166  1000,
7167  "Twist",
7168  "Twist offset for closed loops",
7169  -1000,
7170  1000);
7171 
7173 }
7174 
7177 /* -------------------------------------------------------------------- */
7182 {
7183  const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
7184  const bool use_even_offset = RNA_boolean_get(op->ptr, "use_even_offset");
7185  const bool use_replace = RNA_boolean_get(op->ptr, "use_replace");
7186  const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset");
7187  const bool use_crease = RNA_boolean_get(op->ptr, "use_crease");
7188  const float crease_weight = RNA_float_get(op->ptr, "crease_weight");
7189  const float thickness = RNA_float_get(op->ptr, "thickness");
7190  const float offset = RNA_float_get(op->ptr, "offset");
7191 
7192  ViewLayer *view_layer = CTX_data_view_layer(C);
7193  uint objects_len = 0;
7195  view_layer, CTX_wm_view3d(C), &objects_len);
7196  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7197  Object *obedit = objects[ob_index];
7198  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7199 
7200  if (em->bm->totfacesel == 0) {
7201  continue;
7202  }
7203 
7204  BMOperator bmop;
7205 
7206  EDBM_op_init(em,
7207  &bmop,
7208  op,
7209  "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b "
7210  "use_relative_offset=%b "
7211  "use_crease=%b crease_weight=%f thickness=%f offset=%f",
7213  use_replace,
7214  use_boundary,
7215  use_even_offset,
7216  use_relative_offset,
7217  use_crease,
7218  crease_weight,
7219  thickness,
7220  offset);
7221 
7222  BMO_op_exec(em->bm, &bmop);
7223 
7226  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
7227 
7228  if (!EDBM_op_finish(em, &bmop, op, true)) {
7229  continue;
7230  }
7231 
7232  EDBM_update_generic(obedit->data, true, true);
7233  }
7234 
7235  MEM_freeN(objects);
7236 
7237  return OPERATOR_FINISHED;
7238 }
7239 
7241 {
7242  PropertyRNA *prop;
7243 
7244  /* identifiers */
7245  ot->name = "Wireframe";
7246  ot->idname = "MESH_OT_wireframe";
7247  ot->description = "Create a solid wireframe from faces";
7248 
7249  /* api callbacks */
7252 
7253  /* flags */
7255 
7256  /* properties */
7257  RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
7259  "use_even_offset",
7260  true,
7261  "Offset Even",
7262  "Scale the offset to give more even thickness");
7264  "use_relative_offset",
7265  false,
7266  "Offset Relative",
7267  "Scale the offset by surrounding geometry");
7268  RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces");
7269  prop = RNA_def_float_distance(
7270  ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f);
7271  /* use 1 rather than 10 for max else dragging the button moves too far */
7272  RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
7273  RNA_def_float_distance(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f);
7275  "use_crease",
7276  false,
7277  "Crease",
7278  "Crease hub edges for an improved subdivision surface");
7279  prop = RNA_def_float(
7280  ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease Weight", "", 0.0f, 1.0f);
7281  RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
7282 }
7283 
7286 /* -------------------------------------------------------------------- */
7291 {
7292  const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint");
7293  bool changed_multi = false;
7295  ViewLayer *view_layer = CTX_data_view_layer(C);
7296  uint bases_len = 0;
7298  view_layer, CTX_wm_view3d(C), &bases_len);
7299  for (uint base_index = 0; base_index < bases_len; base_index++) {
7300  Object *obedit = bases[base_index]->object;
7301  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7302 
7303  if (em->bm->totedgesel == 0) {
7304  continue;
7305  }
7306 
7307  BMOperator bmop;
7308  EDBM_op_init(em,
7309  &bmop,
7310  op,
7311  "offset_edgeloops edges=%he use_cap_endpoint=%b",
7313  use_cap_endpoint);
7314 
7315  BMO_op_exec(em->bm, &bmop);
7316 
7318 
7320  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
7321 
7322  if (EDBM_op_finish(em, &bmop, op, true)) {
7323  EDBM_update_generic(obedit->data, true, true);
7324  changed_multi = true;
7325  }
7326  }
7327 
7328  if (changed_multi) {
7336  }
7337  }
7338 
7339  MEM_freeN(bases);
7340 
7341  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
7342 }
7343 
7345 {
7346  /* identifiers */
7347  ot->name = "Offset Edge Loop";
7348  ot->idname = "MESH_OT_offset_edge_loops";
7349  ot->description = "Create offset edge loop from the current selection";
7350 
7351  /* api callbacks */
7354 
7355  /* Keep internal, since this is only meant to be accessed via
7356  * 'MESH_OT_offset_edge_loops_slide'. */
7357 
7358  /* flags */
7360 
7362  ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points");
7363 }
7364 
7367 /* -------------------------------------------------------------------- */
7371 #ifdef WITH_BULLET
7372 static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
7373 {
7374  const bool use_existing_faces = RNA_boolean_get(op->ptr, "use_existing_faces");
7375  const bool delete_unused = RNA_boolean_get(op->ptr, "delete_unused");
7376  const bool make_holes = RNA_boolean_get(op->ptr, "make_holes");
7377  const bool join_triangles = RNA_boolean_get(op->ptr, "join_triangles");
7378 
7379  float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold");
7380  float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold");
7381 
7382  ViewLayer *view_layer = CTX_data_view_layer(C);
7383  uint objects_len = 0;
7385  view_layer, CTX_wm_view3d(C), &objects_len);
7386  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7387  Object *obedit = objects[ob_index];
7388  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7389 
7390  if (em->bm->totvertsel == 0) {
7391  continue;
7392  }
7393 
7394  BMOperator bmop;
7395 
7396  EDBM_op_init(em,
7397  &bmop,
7398  op,
7399  "convex_hull input=%hvef "
7400  "use_existing_faces=%b",
7402  use_existing_faces);
7403  BMO_op_exec(em->bm, &bmop);
7404 
7405  /* Hull fails if input is coplanar */
7406  if (BMO_error_occurred(em->bm)) {
7407  EDBM_op_finish(em, &bmop, op, true);
7408  continue;
7409  }
7410 
7412  em->bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
7413 
7414  /* Delete unused vertices, edges, and faces */
7415  if (delete_unused) {
7416  if (!EDBM_op_callf(
7417  em, op, "delete geom=%S context=%i", &bmop, "geom_unused.out", DEL_ONLYTAGGED)) {
7418  EDBM_op_finish(em, &bmop, op, true);
7419  continue;
7420  }
7421  }
7422 
7423  /* Delete hole edges/faces */
7424  if (make_holes) {
7425  if (!EDBM_op_callf(
7426  em, op, "delete geom=%S context=%i", &bmop, "geom_holes.out", DEL_ONLYTAGGED)) {
7427  EDBM_op_finish(em, &bmop, op, true);
7428  continue;
7429  }
7430  }
7431 
7432  /* Merge adjacent triangles */
7433  if (join_triangles) {
7434  if (!EDBM_op_call_and_selectf(em,
7435  op,
7436  "faces.out",
7437  true,
7438  "join_triangles faces=%S "
7439  "angle_face_threshold=%f angle_shape_threshold=%f",
7440  &bmop,
7441  "geom.out",
7442  angle_face_threshold,
7443  angle_shape_threshold)) {
7444  EDBM_op_finish(em, &bmop, op, true);
7445  continue;
7446  }
7447  }
7448 
7449  if (!EDBM_op_finish(em, &bmop, op, true)) {
7450  continue;
7451  }
7452 
7453  EDBM_update_generic(obedit->data, true, true);
7455  }
7456 
7457  MEM_freeN(objects);
7458  return OPERATOR_FINISHED;
7459 }
7460 
7462 {
7463  /* identifiers */
7464  ot->name = "Convex Hull";
7465  ot->description = "Enclose selected vertices in a convex polyhedron";
7466  ot->idname = "MESH_OT_convex_hull";
7467 
7468  /* api callbacks */
7469  ot->exec = edbm_convex_hull_exec;
7471 
7472  /* flags */
7474 
7475  /* props */
7477  "delete_unused",
7478  true,
7479  "Delete Unused",
7480  "Delete selected elements that are not used by the hull");
7481 
7483  "use_existing_faces",
7484  true,
7485  "Use Existing Faces",
7486  "Skip hull triangles that are covered by a pre-existing face");
7487 
7489  "make_holes",
7490  false,
7491  "Make Holes",
7492  "Delete selected faces that are used by the hull");
7493 
7495  ot->srna, "join_triangles", true, "Join Triangles", "Merge adjacent triangles into quads");
7496 
7498 }
7499 #endif /* WITH_BULLET */
7500 
7503 /* -------------------------------------------------------------------- */
7508 {
7509  const float thresh = RNA_float_get(op->ptr, "threshold");
7510  ViewLayer *view_layer = CTX_data_view_layer(C);
7511  uint objects_len = 0;
7513  view_layer, CTX_wm_view3d(C), &objects_len);
7514 
7515  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7516  Object *obedit = objects[ob_index];
7517  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7518 
7519  if (em->bm->totvertsel == 0) {
7520  continue;
7521  }
7522 
7523  BMOperator bmop;
7524  EDBM_op_init(em,
7525  &bmop,
7526  op,
7527  "symmetrize input=%hvef direction=%i dist=%f",
7529  RNA_enum_get(op->ptr, "direction"),
7530  thresh);
7531  BMO_op_exec(em->bm, &bmop);
7532 
7534 
7536  em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
7537 
7538  if (!EDBM_op_finish(em, &bmop, op, true)) {
7539  continue;
7540  }
7541  EDBM_update_generic(obedit->data, true, true);
7543  }
7544  MEM_freeN(objects);
7545 
7546  return OPERATOR_FINISHED;
7547 }
7548 
7550 {
7551  /* identifiers */
7552  ot->name = "Symmetrize";
7553  ot->description = "Enforce symmetry (both form and topological) across an axis";
7554  ot->idname = "MESH_OT_symmetrize";
7555 
7556  /* api callbacks */
7559 
7560  /* flags */
7562 
7563  ot->prop = RNA_def_enum(ot->srna,
7564  "direction",
7567  "Direction",
7568  "Which sides to copy from and to");
7570  "threshold",
7571  1e-4f,
7572  0.0f,
7573  10.0f,
7574  "Threshold",
7575  "Limit for snap middle vertices to the axis center",
7576  1e-5f,
7577  0.1f);
7578 }
7579 
7582 /* -------------------------------------------------------------------- */
7587 {
7588  const float eps = 0.00001f;
7589  const float eps_sq = eps * eps;
7590  const bool use_topology = false;
7591 
7592  const float thresh = RNA_float_get(op->ptr, "threshold");
7593  const float fac = RNA_float_get(op->ptr, "factor");
7594  const bool use_center = RNA_boolean_get(op->ptr, "use_center");
7595  const int axis_dir = RNA_enum_get(op->ptr, "direction");
7596 
7597  /* Vertices stats (total over all selected objects). */
7598  int totvertfound = 0, totvertmirr = 0, totvertfail = 0;
7599 
7600  /* Axis. */
7601  int axis = axis_dir % 3;
7602  bool axis_sign = axis != axis_dir;
7603 
7604  ViewLayer *view_layer = CTX_data_view_layer(C);
7605  uint objects_len = 0;
7607  view_layer, CTX_wm_view3d(C), &objects_len);
7608 
7609  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7610  Object *obedit = objects[ob_index];
7611  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7612  BMesh *bm = em->bm;
7613 
7614  if (em->bm->totvertsel == 0) {
7615  continue;
7616  }
7617 
7618  /* Only allocate memory after checking whether to skip object. */
7619  int *index = MEM_mallocN(bm->totvert * sizeof(*index), __func__);
7620 
7621  /* Vertex iter. */
7622  BMIter iter;
7623  BMVert *v;
7624  int i;
7625 
7626  EDBM_verts_mirror_cache_begin_ex(em, axis, true, true, false, use_topology, thresh, index);
7627 
7629 
7631 
7632  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
7633  if ((BM_elem_flag_test(v, BM_ELEM_SELECT) != false) &&
7634  (BM_elem_flag_test(v, BM_ELEM_TAG) == false)) {
7635  int i_mirr = index[i];
7636  if (i_mirr != -1) {
7637 
7638  BMVert *v_mirr = BM_vert_at_index(bm, index[i]);
7639 
7640  if (v != v_mirr) {
7641  float co[3], co_mirr[3];
7642 
7643  if ((v->co[axis] > v_mirr->co[axis]) == axis_sign) {
7644  SWAP(BMVert *, v, v_mirr);
7645  }
7646 
7647  copy_v3_v3(co_mirr, v_mirr->co);
7648  co_mirr[axis] *= -1.0f;
7649 
7650  if (len_squared_v3v3(v->co, co_mirr) > eps_sq) {
7651  totvertmirr++;
7652  }
7653 
7654  interp_v3_v3v3(co, v->co, co_mirr, fac);
7655 
7656  copy_v3_v3(v->co, co);
7657 
7658  co[axis] *= -1.0f;
7659  copy_v3_v3(v_mirr->co, co);
7660 
7663  totvertfound++;
7664  }
7665  else {
7666  if (use_center) {
7667 
7668  if (fabsf(v->co[axis]) > eps) {
7669  totvertmirr++;
7670  }
7671 
7672  v->co[axis] = 0.0f;
7673  }
7675  totvertfound++;
7676  }
7677  }
7678  else {
7679  totvertfail++;
7680  }
7681  }
7682  }
7683  EDBM_update_generic(obedit->data, false, false);
7684 
7685  /* No need to end cache, just free the array. */
7686  MEM_freeN(index);
7687  }
7688  MEM_freeN(objects);
7689 
7690  if (totvertfail) {
7691  BKE_reportf(op->reports,
7692  RPT_WARNING,
7693  "%d already symmetrical, %d pairs mirrored, %d failed",
7694  totvertfound - totvertmirr,
7695  totvertmirr,
7696  totvertfail);
7697  }
7698  else {
7699  BKE_reportf(op->reports,
7700  RPT_INFO,
7701  "%d already symmetrical, %d pairs mirrored",
7702  totvertfound - totvertmirr,
7703  totvertmirr);
7704  }
7705 
7706  return OPERATOR_FINISHED;
7707 }
7708 
7710 {
7711  /* identifiers */
7712  ot->name = "Snap to Symmetry";
7713  ot->description = "Snap vertex pairs to their mirrored locations";
7714  ot->idname = "MESH_OT_symmetry_snap";
7715 
7716  /* api callbacks */
7719 
7720  /* flags */
7722 
7723  ot->prop = RNA_def_enum(ot->srna,
7724  "direction",
7727  "Direction",
7728  "Which sides to copy from and to");
7730  "threshold",
7731  0.05f,
7732  0.0f,
7733  10.0f,
7734  "Threshold",
7735  "Distance within which matching vertices are searched",
7736  1e-4f,
7737  1.0f);
7739  "factor",
7740  0.5f,
7741  0.0f,
7742  1.0f,
7743  "Factor",
7744  "Mix factor of the locations of the vertices",
7745  0.0f,
7746  1.0f);
7748  ot->srna, "use_center", true, "Center", "Snap middle vertices to the axis center");
7749 }
7750 
7753 #if defined(WITH_FREESTYLE)
7754 
7755 /* -------------------------------------------------------------------- */
7759 static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op)
7760 {
7761  BMEdge *eed;
7762  BMIter iter;
7763  FreestyleEdge *fed;
7764  const bool clear = RNA_boolean_get(op->ptr, "clear");
7765  ViewLayer *view_layer = CTX_data_view_layer(C);
7766 
7767  uint objects_len = 0;
7769  view_layer, CTX_wm_view3d(C), &objects_len);
7770  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7771  Object *obedit = objects[ob_index];
7772  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7773 
7774  if (em == NULL) {
7775  continue;
7776  }
7777 
7778  BMesh *bm = em->bm;
7779 
7780  if (bm->totedgesel == 0) {
7781  continue;
7782  }
7783 
7786  }
7787 
7788  if (clear) {
7789  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
7792  fed->flag &= ~FREESTYLE_EDGE_MARK;
7793  }
7794  }
7795  }
7796  else {
7797  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
7800  fed->flag |= FREESTYLE_EDGE_MARK;
7801  }
7802  }
7803  }
7804 
7807  }
7808  MEM_freeN(objects);
7809 
7810  return OPERATOR_FINISHED;
7811 }
7812 
7813 void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
7814 {
7815  PropertyRNA *prop;
7816 
7817  /* identifiers */
7818  ot->name = "Mark Freestyle Edge";
7819  ot->description = "(Un)mark selected edges as Freestyle feature edges";
7820  ot->idname = "MESH_OT_mark_freestyle_edge";
7821 
7822  /* api callbacks */
7823  ot->exec = edbm_mark_freestyle_edge_exec;
7825 
7826  /* flags */
7828 
7829  prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
7831 }
7832 
7835 /* -------------------------------------------------------------------- */
7839 static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
7840 {
7841  BMFace *efa;
7842  BMIter iter;
7843  FreestyleFace *ffa;
7844  const bool clear = RNA_boolean_get(op->ptr, "clear");
7845  ViewLayer *view_layer = CTX_data_view_layer(C);
7846 
7847  uint objects_len = 0;
7849  view_layer, CTX_wm_view3d(C), &objects_len);
7850  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7851  Object *obedit = objects[ob_index];
7852  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7853 
7854  if (em == NULL) {
7855  continue;
7856  }
7857 
7858  if (em->bm->totfacesel == 0) {
7859  continue;
7860  }
7861 
7864  }
7865 
7866  if (clear) {
7867  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
7870  ffa->flag &= ~FREESTYLE_FACE_MARK;
7871  }
7872  }
7873  }
7874  else {
7875  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
7878  ffa->flag |= FREESTYLE_FACE_MARK;
7879  }
7880  }
7881  }
7882 
7885  }
7886  MEM_freeN(objects);
7887 
7888  return OPERATOR_FINISHED;
7889 }
7890 
7891 void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
7892 {
7893  PropertyRNA *prop;
7894 
7895  /* identifiers */
7896  ot->name = "Mark Freestyle Face";
7897  ot->description = "(Un)mark selected faces for exclusion from Freestyle feature edge detection";
7898  ot->idname = "MESH_OT_mark_freestyle_face";
7899 
7900  /* api callbacks */
7901  ot->exec = edbm_mark_freestyle_face_exec;
7903 
7904  /* flags */
7906 
7907  prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
7909 }
7910 
7913 #endif /* WITH_FREESTYLE */
7914 
7915 /* -------------------------------------------------------------------- */
7919 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
7920 /* NOTE: We could add more here, like e.g. a switch between local or global coordinates of target,
7921  * use number-input to type in explicit vector values. */
7922 enum {
7923  /* Generic commands. */
7926 
7927  /* Point To operator. */
7932 
7938 };
7939 
7940 /* called in transform_ops.c, on each regeneration of keymaps */
7942 {
7943  static const EnumPropertyItem modal_items[] = {
7944  {EDBM_CLNOR_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
7945  {EDBM_CLNOR_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
7946 
7947  /* Point To operator. */
7948  {EDBM_CLNOR_MODAL_POINTTO_RESET, "RESET", 0, "Reset", "Reset normals to initial ones"},
7950  "INVERT",
7951  0,
7952  "Invert",
7953  "Toggle inversion of affected normals"},
7955  "SPHERIZE",
7956  0,
7957  "Spherize",
7958  "Interpolate between new and original normals"},
7959  {EDBM_CLNOR_MODAL_POINTTO_ALIGN, "ALIGN", 0, "Align", "Make all affected normals parallel"},
7960 
7962  "USE_MOUSE",
7963  0,
7964  "Use Mouse",
7965  "Follow mouse cursor position"},
7967  "USE_PIVOT",
7968  0,
7969  "Use Pivot",
7970  "Use current rotation/scaling pivot point coordinates"},
7972  "USE_OBJECT",
7973  0,
7974  "Use Object",
7975  "Use current edited object's location"},
7977  "SET_USE_3DCURSOR",
7978  0,
7979  "Set and Use 3D Cursor",
7980  "Set new 3D cursor position and use it"},
7982  "SET_USE_SELECTED",
7983  0,
7984  "Select and Use Mesh Item",
7985  "Select new active mesh element and use its location"},
7986  {0, NULL, 0, NULL, NULL},
7987  };
7988  static const char *keymap_name = "Custom Normals Modal Map";
7989 
7990  wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
7991 
7992  /* We only need to add map once */
7993  if (keymap && keymap->modal_items) {
7994  return NULL;
7995  }
7996 
7997  keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
7998 
7999  WM_modalkeymap_assign(keymap, "MESH_OT_point_normals");
8000 
8001  return keymap;
8002 }
8003 
8004 #define CLNORS_VALID_VEC_LEN (1e-4f)
8005 
8008 /* -------------------------------------------------------------------- */
8012 enum {
8015 };
8016 
8019  "COORDINATES",
8020  0,
8021  "Coordinates",
8022  "Use static coordinates (defined by various means)"},
8023  {EDBM_CLNOR_POINTTO_MODE_MOUSE, "MOUSE", 0, "Mouse", "Follow mouse cursor"},
8024  {0, NULL, 0, NULL, NULL},
8025 };
8026 
8027 /* Initialize loop normal data */
8029 {
8030  Object *obedit = CTX_data_edit_object(C);
8031  BMEditMesh *em = BKE_editmesh_from_object(obedit);
8032  BMesh *bm = em->bm;
8033 
8034  BKE_editmesh_ensure_autosmooth(em, obedit->data);
8035  BKE_editmesh_lnorspace_update(em, obedit->data);
8037 
8038  op->customdata = lnors_ed_arr;
8039 
8040  return (lnors_ed_arr->totloop != 0);
8041 }
8042 
8044 {
8045  if (op->customdata != NULL) {
8046  return true;
8047  }
8048  return point_normals_init(C, op);
8049 }
8050 
8052 {
8053  if (op->customdata != NULL) {
8054  BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
8055  BM_loop_normal_editdata_array_free(lnors_ed_arr);
8056  op->customdata = NULL;
8057  }
8058 }
8059 
8061 {
8062  point_normals_free(op);
8064 }
8065 
8067 {
8068  char header[UI_MAX_DRAW_STR];
8069  char buf[UI_MAX_DRAW_STR];
8070 
8071  char *p = buf;
8072  int available_len = sizeof(buf);
8073 
8074 #define WM_MODALKEY(_id) \
8075  WM_modalkeymap_operator_items_to_string_buf( \
8076  op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p)
8077 
8078  BLI_snprintf(header,
8079  sizeof(header),
8080  TIP_("%s: confirm, %s: cancel, "
8081  "%s: point to mouse (%s), %s: point to Pivot, "
8082  "%s: point to object origin, %s: reset normals, "
8083  "%s: set & point to 3D cursor, %s: select & point to mesh item, "
8084  "%s: invert normals (%s), %s: spherize (%s), %s: align (%s)"),
8095  WM_bool_as_string(RNA_boolean_get(op->ptr, "invert")),
8097  WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")),
8099  WM_bool_as_string(RNA_boolean_get(op->ptr, "align")));
8100 
8101 #undef WM_MODALKEY
8102 
8103  ED_area_status_text(CTX_wm_area(C), header);
8104 }
8105 
8106 /* TODO move that to generic function in BMesh? */
8107 static void bmesh_selected_verts_center_calc(BMesh *bm, float *r_center)
8108 {
8109  BMVert *v;
8110  BMIter viter;
8111  int i = 0;
8112 
8113  zero_v3(r_center);
8114  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
8116  add_v3_v3(r_center, v->co);
8117  i++;
8118  }
8119  }
8120  mul_v3_fl(r_center, 1.0f / (float)i);
8121 }
8122 
8123 static void point_normals_apply(bContext *C, wmOperator *op, float target[3], const bool do_reset)
8124 {
8125  Object *obedit = CTX_data_edit_object(C);
8126  BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
8127  BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
8128 
8129  const bool do_invert = RNA_boolean_get(op->ptr, "invert");
8130  const bool do_spherize = RNA_boolean_get(op->ptr, "spherize");
8131  const bool do_align = RNA_boolean_get(op->ptr, "align");
8132  float center[3];
8133 
8134  if (do_align && !do_reset) {
8136  }
8137 
8138  sub_v3_v3(target, obedit->loc); /* Move target to local coordinates. */
8139 
8140  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
8141  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
8142  if (do_reset) {
8143  copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
8144  }
8145  else if (do_spherize) {
8146  /* Note that this is *not* real spherical interpolation.
8147  * Probably good enough in this case though? */
8148  const float strength = RNA_float_get(op->ptr, "spherize_strength");
8149  float spherized_normal[3];
8150 
8151  sub_v3_v3v3(spherized_normal, target, lnor_ed->loc);
8152 
8153  /* otherwise, multiplication by strength is meaningless... */
8154  normalize_v3(spherized_normal);
8155 
8156  mul_v3_fl(spherized_normal, strength);
8157  mul_v3_v3fl(lnor_ed->nloc, lnor_ed->niloc, 1.0f - strength);
8158  add_v3_v3(lnor_ed->nloc, spherized_normal);
8159  }
8160  else if (do_align) {
8161  sub_v3_v3v3(lnor_ed->nloc, target, center);
8162  }
8163  else {
8164  sub_v3_v3v3(lnor_ed->nloc, target, lnor_ed->loc);
8165  }
8166 
8167  if (do_invert && !do_reset) {
8168  negate_v3(lnor_ed->nloc);
8169  }
8170  if (normalize_v3(lnor_ed->nloc) >= CLNORS_VALID_VEC_LEN) {
8172  bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
8173  }
8174  }
8175 }
8176 
8177 static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event)
8178 {
8179  /* As this operator passes events through, we can't be sure the user didn't exit edit-mode.
8180  * or performed some other operation. */
8181  if (!WM_operator_poll(C, op->type)) {
8182  point_normals_cancel(C, op);
8183  return OPERATOR_CANCELLED;
8184  }
8185 
8186  View3D *v3d = CTX_wm_view3d(C);
8188  Object *obedit = CTX_data_edit_object(C);
8189  BMEditMesh *em = BKE_editmesh_from_object(obedit);
8190  BMesh *bm = em->bm;
8191 
8192  float target[3];
8193 
8194  int ret = OPERATOR_PASS_THROUGH;
8195  int mode = RNA_enum_get(op->ptr, "mode");
8196  int new_mode = mode;
8197  bool force_mousemove = false;
8198  bool do_reset = false;
8199 
8200  PropertyRNA *prop_target = RNA_struct_find_property(op->ptr, "target_location");
8201 
8202  if (event->type == EVT_MODAL_MAP) {
8203  switch (event->val) {
8205  RNA_property_float_get_array(op->ptr, prop_target, target);
8207  break;
8208 
8210  do_reset = true;
8212  break;
8213 
8215  do_reset = true;
8217  break;
8218 
8220  PropertyRNA *prop_invert = RNA_struct_find_property(op->ptr, "invert");
8222  op->ptr, prop_invert, !RNA_property_boolean_get(op->ptr, prop_invert));
8223  RNA_property_float_get_array(op->ptr, prop_target, target);
8225  break;
8226  }
8227 
8229  PropertyRNA *prop_spherize = RNA_struct_find_property(op->ptr, "spherize");
8231  op->ptr, prop_spherize, !RNA_property_boolean_get(op->ptr, prop_spherize));
8232  RNA_property_float_get_array(op->ptr, prop_target, target);
8234  break;
8235  }
8236 
8238  PropertyRNA *prop_align = RNA_struct_find_property(op->ptr, "align");
8240  op->ptr, prop_align, !RNA_property_boolean_get(op->ptr, prop_align));
8241  RNA_property_float_get_array(op->ptr, prop_target, target);
8243  break;
8244  }
8245 
8247  new_mode = EDBM_CLNOR_POINTTO_MODE_MOUSE;
8248  /* We want to immediately update to mouse cursor position... */
8249  force_mousemove = true;
8251  break;
8252 
8255  copy_v3_v3(target, obedit->loc);
8257  break;
8258 
8262  copy_v3_v3(target, scene->cursor.location);
8264  break;
8265 
8269  if (EDBM_select_pick(C, event->mval, false, false, false)) {
8270  /* Point to newly selected active. */
8271  ED_object_calc_active_center_for_editmode(obedit, false, target);
8272 
8273  add_v3_v3(target, obedit->loc);
8275  }
8276  break;
8277 
8281  case V3D_AROUND_CENTER_BOUNDS: /* calculateCenterBound */
8282  {
8283  BMVert *v;
8284  BMIter viter;
8285  float min[3], max[3];
8286  int i = 0;
8287 
8288  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
8290  if (i) {
8291  minmax_v3v3_v3(min, max, v->co);
8292  }
8293  else {
8294  copy_v3_v3(min, v->co);
8295  copy_v3_v3(max, v->co);
8296  }
8297  i++;
8298  }
8299  }
8300  mid_v3_v3v3(target, min, max);
8301  add_v3_v3(target, obedit->loc);
8302  break;
8303  }
8304 
8305  case V3D_AROUND_CENTER_MEDIAN: {
8307  add_v3_v3(target, obedit->loc);
8308  break;
8309  }
8310 
8311  case V3D_AROUND_CURSOR:
8312  copy_v3_v3(target, scene->cursor.location);
8313  break;
8314 
8315  case V3D_AROUND_ACTIVE:
8316  if (!ED_object_calc_active_center_for_editmode(obedit, false, target)) {
8317  zero_v3(target);
8318  }
8319  add_v3_v3(target, obedit->loc);
8320  break;
8321 
8322  default:
8323  BKE_report(op->reports, RPT_WARNING, "Does not support Individual Origin as pivot");
8324  copy_v3_v3(target, obedit->loc);
8325  }
8327  break;
8328  default:
8329  break;
8330  }
8331  }
8332 
8333  if (new_mode != mode) {
8334  mode = new_mode;
8335  RNA_enum_set(op->ptr, "mode", mode);
8336  }
8337 
8338  /* Only handle mousemove event in case we are in mouse mode. */
8339  if (event->type == MOUSEMOVE || force_mousemove) {
8340  if (mode == EDBM_CLNOR_POINTTO_MODE_MOUSE) {
8341  ARegion *region = CTX_wm_region(C);
8342  float center[3];
8343 
8345 
8346  ED_view3d_win_to_3d_int(v3d, region, center, event->mval, target);
8347 
8349  }
8350  }
8351 
8352  if (ret != OPERATOR_PASS_THROUGH) {
8354  RNA_property_float_set_array(op->ptr, prop_target, target);
8355  }
8356 
8357  if (point_normals_ensure(C, op)) {
8358  point_normals_apply(C, op, target, do_reset);
8359  EDBM_update_generic(obedit->data, true, false); /* Recheck bools. */
8361  }
8362  else {
8364  }
8365  }
8366 
8368  point_normals_cancel(C, op);
8369  }
8370 
8371  /* If we allow other tools to run, we can't be sure if they will re-allocate
8372  * the data this operator uses, see: T68159.
8373  * Free the data here, then use #point_normals_ensure to add it back on demand. */
8374  if (ret == OPERATOR_PASS_THROUGH) {
8375  /* Don't free on mouse-move, causes creation/freeing of the loop data in an inefficient way. */
8376  if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
8377  point_normals_free(op);
8378  }
8379  }
8380  return ret;
8381 }
8382 
8384 {
8385  if (!point_normals_init(C, op)) {
8386  point_normals_cancel(C, op);
8387  return OPERATOR_CANCELLED;
8388  }
8389 
8391 
8393 
8395  return OPERATOR_RUNNING_MODAL;
8396 }
8397 
8398 /* TODO: make this work on multiple objects at once */
8400 {
8401  Object *obedit = CTX_data_edit_object(C);
8402 
8403  if (!point_normals_init(C, op)) {
8404  point_normals_cancel(C, op);
8405  return OPERATOR_CANCELLED;
8406  }
8407 
8408  /* Note that 'mode' is ignored in exec case,
8409  * we directly use vector stored in target_location, whatever that is. */
8410 
8411  float target[3];
8412  RNA_float_get_array(op->ptr, "target_location", target);
8413 
8414  point_normals_apply(C, op, target, false);
8415 
8416  EDBM_update_generic(obedit->data, true, false);
8417  point_normals_cancel(C, op);
8418 
8419  return OPERATOR_FINISHED;
8420 }
8421 
8423  PropertyRNA *prop,
8424  void *UNUSED(user_data))
8425 {
8426  const char *prop_id = RNA_property_identifier(prop);
8427 
8428  /* Only show strength option if spherize is enabled. */
8429  if (STREQ(prop_id, "spherize_strength")) {
8430  return (bool)RNA_boolean_get(ptr, "spherize");
8431  }
8432 
8433  /* Else, show it! */
8434  return true;
8435 }
8436 
8438 {
8439  uiLayout *layout = op->layout;
8441  PointerRNA ptr;
8442 
8443  RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
8444 
8445  uiLayoutSetPropSep(layout, true);
8446 
8447  /* Main auto-draw call */
8448  uiDefAutoButsRNA(layout, &ptr, point_normals_draw_check_prop, NULL, NULL, '\0', false);
8449 }
8450 
8452 {
8453  /* identifiers */
8454  ot->name = "Point Normals to Target";
8455  ot->description = "Point selected custom normals to specified Target";
8456  ot->idname = "MESH_OT_point_normals";
8457 
8458  /* api callbacks */
8465 
8466  /* flags */
8468 
8469  ot->prop = RNA_def_enum(ot->srna,
8470  "mode",
8473  "Mode",
8474  "How to define coordinates to point custom normals to");
8476 
8477  RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert affected normals");
8478 
8479  RNA_def_boolean(ot->srna, "align", false, "Align", "Make all affected normals parallel");
8480 
8482  "target_location",
8483  3,
8484  NULL,
8485  -FLT_MAX,
8486  FLT_MAX,
8487  "Target",
8488  "Target location to which normals will point",
8489  -1000.0f,
8490  1000.0f);
8491 
8493  ot->srna, "spherize", false, "Spherize", "Interpolate between original and new normals");
8494 
8496  "spherize_strength",
8497  0.1,
8498  0.0f,
8499  1.0f,
8500  "Spherize Strength",
8501  "Ratio of spherized normal to original normal",
8502  0.0f,
8503  1.0f);
8504 }
8505 
8508 /* -------------------------------------------------------------------- */
8512 static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
8513 {
8514  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
8515 
8516  BLI_SMALLSTACK_DECLARE(clnors, short *);
8517 
8519 
8521 
8522  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
8524 
8525  if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) {
8526  continue;
8527  }
8528 
8529  MLoopNorSpace *lnor_space = bm->lnor_spacearr->lspacearr[lnor_ed->loop_index];
8530 
8531  if ((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0) {
8532  LinkNode *loops = lnor_space->loops;
8533  float avg_normal[3] = {0.0f, 0.0f, 0.0f};
8534  short *clnors_data;
8535 
8536  for (; loops; loops = loops->next) {
8537  BMLoop *l = loops->link;
8538  const int loop_index = BM_elem_index_get(l);
8539 
8540  BMLoopNorEditData *lnor_ed_tmp = lnors_ed_arr->lidx_to_lnor_editdata[loop_index];
8541  BLI_assert(lnor_ed_tmp->loop_index == loop_index && lnor_ed_tmp->loop == l);
8542  add_v3_v3(avg_normal, lnor_ed_tmp->nloc);
8543  BLI_SMALLSTACK_PUSH(clnors, lnor_ed_tmp->clnors_data);
8545  }
8546  if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
8547  /* If avg normal is nearly 0, set clnor to default value. */
8548  zero_v3(avg_normal);
8549  }
8550  while ((clnors_data = BLI_SMALLSTACK_POP(clnors))) {
8551  BKE_lnor_space_custom_normal_to_data(lnor_space, avg_normal, clnors_data);
8552  }
8553  }
8554  }
8555 }
8556 
8557 static void normals_split(BMesh *bm)
8558 {
8559  BMFace *f;
8560  BMLoop *l, *l_curr, *l_first;
8561  BMIter fiter;
8562 
8564 
8566 
8567  BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
8568 
8569  const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
8570  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
8571  BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
8572 
8573  l_curr = l_first = BM_FACE_FIRST_LOOP(f);
8574  do {
8575  if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
8576  (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
8578  if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
8579  !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
8580  const int loop_index = BM_elem_index_get(l_curr);
8581  short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
8583  bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
8584  }
8585  else {
8586  BMVert *v_pivot = l_curr->v;
8587  UNUSED_VARS_NDEBUG(v_pivot);
8588  BMEdge *e_next;
8589  const BMEdge *e_org = l_curr->e;
8590  BMLoop *lfan_pivot, *lfan_pivot_next;
8591 
8592  lfan_pivot = l_curr;
8593  e_next = lfan_pivot->e;
8594  float avg_normal[3] = {0.0f};
8595 
8596  while (true) {
8597  lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
8598  if (lfan_pivot_next) {
8599  BLI_assert(lfan_pivot_next->v == v_pivot);
8600  }
8601  else {
8602  e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
8603  }
8604 
8605  BLI_SMALLSTACK_PUSH(loop_stack, lfan_pivot);
8606  add_v3_v3(avg_normal, lfan_pivot->f->no);
8607 
8608  if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
8609  break;
8610  }
8611  lfan_pivot = lfan_pivot_next;
8612  }
8613  if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
8614  /* If avg normal is nearly 0, set clnor to default value. */
8615  zero_v3(avg_normal);
8616  }
8617  while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
8618  const int l_index = BM_elem_index_get(l);
8619  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
8621  bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
8622  }
8623  }
8624  }
8625  } while ((l_curr = l_curr->next) != l_first);
8626  }
8627 }
8628 
8629 static int normals_split_merge(bContext *C, const bool do_merge)
8630 {
8631  ViewLayer *view_layer = CTX_data_view_layer(C);
8632  uint objects_len = 0;
8634  view_layer, CTX_wm_view3d(C), &objects_len);
8635 
8636  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
8637  Object *obedit = objects[ob_index];
8638  BMEditMesh *em = BKE_editmesh_from_object(obedit);
8639  BMesh *bm = em->bm;
8640  BMEdge *e;
8641  BMIter eiter;
8642 
8643  BKE_editmesh_ensure_autosmooth(em, obedit->data);
8644  BKE_editmesh_lnorspace_update(em, obedit->data);
8645 
8646  /* Note that we need temp lnor editing data for all loops of all affected vertices, since by
8647  * setting some faces/edges as smooth we are going to change clnors spaces... See also T65809.
8648  */
8649  BMLoopNorEditDataArray *lnors_ed_arr = do_merge ?
8651  NULL;
8652 
8653  mesh_set_smooth_faces(em, do_merge);
8654 
8655  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
8657  BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge);
8658  }
8659  }
8660 
8662  BKE_editmesh_lnorspace_update(em, obedit->data);
8663 
8664  if (do_merge) {
8665  normals_merge(bm, lnors_ed_arr);
8666  }
8667  else {
8668  normals_split(bm);
8669  }
8670 
8671  if (lnors_ed_arr) {
8672  BM_loop_normal_editdata_array_free(lnors_ed_arr);
8673  }
8674 
8675  EDBM_update_generic(obedit->data, true, false);
8676  }
8677 
8678  MEM_freeN(objects);
8679  return OPERATOR_FINISHED;
8680 }
8681 
8683 {
8684  return normals_split_merge(C, true);
8685 }
8686 
8688 {
8689  /* identifiers */
8690  ot->name = "Merge Normals";
8691  ot->description = "Merge custom normals of selected vertices";
8692  ot->idname = "MESH_OT_merge_normals";
8693 
8694  /* api callbacks */
8697 
8698  /* flags */
8700 }
8701 
8703 {
8704  return normals_split_merge(C, false);
8705 }
8706 
8708 {
8709  /* identifiers */
8710  ot->name = "Split Normals";
8711  ot->description = "Split custom normals of selected vertices";
8712  ot->idname = "MESH_OT_split_normals";
8713 
8714  /* api callbacks */
8717 
8718  /* flags */
8720 }
8721 
8724 /* -------------------------------------------------------------------- */
8728 enum {
8732 };
8733 
8736  "CUSTOM_NORMAL",
8737  0,
8738  "Custom Normal",
8739  "Take average of vertex normals"},
8741  "FACE_AREA",
8742  0,
8743  "Face Area",
8744  "Set all vertex normals by face area"},
8746  "CORNER_ANGLE",
8747  0,
8748  "Corner Angle",
8749  "Set all vertex normals by corner angle"},
8750  {0, NULL, 0, NULL, NULL},
8751 };
8752 
8754 {
8755  ViewLayer *view_layer = CTX_data_view_layer(C);
8756  uint objects_len = 0;
8758  view_layer, CTX_wm_view3d(C), &objects_len);
8759  const int average_type = RNA_enum_get(op->ptr, "average_type");
8760  const float absweight = (float)RNA_int_get(op->ptr, "weight");
8761  const float threshold = RNA_float_get(op->ptr, "threshold");
8762 
8763  HeapSimple *loop_weight = BLI_heapsimple_new();
8764  BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
8765 
8766  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
8767  BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
8768  BLI_assert(BLI_heapsimple_is_empty(loop_weight));
8769 
8770  Object *obedit = objects[ob_index];
8771  BMEditMesh *em = BKE_editmesh_from_object(obedit);
8772  BMesh *bm = em->bm;
8773  BMFace *f;
8774  BMLoop *l, *l_curr, *l_first;
8775  BMIter fiter;
8776 
8777  BKE_editmesh_ensure_autosmooth(em, obedit->data);
8779  BKE_editmesh_lnorspace_update(em, obedit->data);
8780 
8781  const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
8782 
8783  float weight = absweight / 50.0f;
8784  if (absweight == 100.0f) {
8785  weight = (float)SHRT_MAX;
8786  }
8787  else if (absweight == 1.0f) {
8788  weight = 1 / (float)SHRT_MAX;
8789  }
8790  else if ((weight - 1) * 25 > 1) {
8791  weight = (weight - 1) * 25;
8792  }
8793 
8795 
8796  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
8797  l_curr = l_first = BM_FACE_FIRST_LOOP(f);
8798  do {
8799  if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
8800  (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
8801  (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) &&
8802  BM_loop_check_cyclic_smooth_fan(l_curr)))) {
8803  if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
8804  !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
8805  const int loop_index = BM_elem_index_get(l_curr);
8806  short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
8808  bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
8809  }
8810  else {
8811  BMVert *v_pivot = l_curr->v;
8812  UNUSED_VARS_NDEBUG(v_pivot);
8813  BMEdge *e_next;
8814  const BMEdge *e_org = l_curr->e;
8815  BMLoop *lfan_pivot, *lfan_pivot_next;
8816 
8817  lfan_pivot = l_curr;
8818  e_next = lfan_pivot->e;
8819 
8820  while (true) {
8821  lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
8822  if (lfan_pivot_next) {
8823  BLI_assert(lfan_pivot_next->v == v_pivot);
8824  }
8825  else {
8826  e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
8827  }
8828 
8829  float val = 1.0f;
8830  if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) {
8831  val = 1.0f / BM_face_calc_area(lfan_pivot->f);
8832  }
8833  else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) {
8834  val = 1.0f / BM_loop_calc_face_angle(lfan_pivot);
8835  }
8836 
8837  BLI_heapsimple_insert(loop_weight, val, lfan_pivot);
8838 
8839  if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
8840  break;
8841  }
8842  lfan_pivot = lfan_pivot_next;
8843  }
8844 
8845  float wnor[3], avg_normal[3] = {0.0f}, count = 0;
8846  float val = BLI_heapsimple_top_value(loop_weight);
8847 
8848  while (!BLI_heapsimple_is_empty(loop_weight)) {
8849  const float cur_val = BLI_heapsimple_top_value(loop_weight);
8850  if (!compare_ff(val, cur_val, threshold)) {
8851  count++;
8852  val = cur_val;
8853  }
8854  l = BLI_heapsimple_pop_min(loop_weight);
8855  BLI_SMALLSTACK_PUSH(loop_stack, l);
8856 
8857  const float n_weight = pow(weight, count);
8858 
8859  if (average_type == EDBM_CLNOR_AVERAGE_LOOP) {
8860  const int l_index = BM_elem_index_get(l);
8861  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
8863  bm->lnor_spacearr->lspacearr[l_index], clnors, wnor);
8864  }
8865  else {
8866  copy_v3_v3(wnor, l->f->no);
8867  }
8868  mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight));
8869  add_v3_v3(avg_normal, wnor);
8870  }
8871 
8872  if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
8873  /* If avg normal is nearly 0, set clnor to default value. */
8874  zero_v3(avg_normal);
8875  }
8876  while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
8877  const int l_index = BM_elem_index_get(l);
8878  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
8880  bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
8881  }
8882  }
8883  }
8884  } while ((l_curr = l_curr->next) != l_first);
8885  }
8886 
8887  EDBM_update_generic(obedit->data, true, false);
8888  }
8889 
8890  BLI_heapsimple_free(loop_weight, NULL);
8891 
8892  MEM_freeN(objects);
8893  return OPERATOR_FINISHED;
8894 }
8895 
8897  PropertyRNA *prop,
8898  void *UNUSED(user_data))
8899 {
8900  const char *prop_id = RNA_property_identifier(prop);
8901  const int average_type = RNA_enum_get(ptr, "average_type");
8902 
8903  /* Only show weight/threshold options in loop average type. */
8904  if (STREQ(prop_id, "weight")) {
8905  return (average_type == EDBM_CLNOR_AVERAGE_LOOP);
8906  }
8907  if (STREQ(prop_id, "threshold")) {
8908  return (average_type == EDBM_CLNOR_AVERAGE_LOOP);
8909  }
8910 
8911  /* Else, show it! */
8912  return true;
8913 }
8914 
8916 {
8917  uiLayout *layout = op->layout;
8919  PointerRNA ptr;
8920 
8921  RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
8922 
8923  uiLayoutSetPropSep(layout, true);
8924 
8925  /* Main auto-draw call */
8926  uiDefAutoButsRNA(layout, &ptr, average_normals_draw_check_prop, NULL, NULL, '\0', false);
8927 }
8928 
8930 {
8931  /* identifiers */
8932  ot->name = "Average Normals";
8933  ot->description = "Average custom normals of selected vertices";
8934  ot->idname = "MESH_OT_average_normals";
8935 
8936  /* api callbacks */
8940 
8941  /* flags */
8943 
8944  ot->prop = RNA_def_enum(ot->srna,
8945  "average_type",
8948  "Type",
8949  "Averaging method");
8950 
8951  RNA_def_int(ot->srna, "weight", 50, 1, 100, "Weight", "Weight applied per face", 1, 100);
8952 
8954  "threshold",
8955  0.01f,
8956  0,
8957  10,
8958  "Threshold",
8959  "Threshold value for different weights to be considered equal",
8960  0,
8961  5);
8962 }
8963 
8966 /* -------------------------------------------------------------------- */
8970 enum {
8976 };
8977 
8979  {EDBM_CLNOR_TOOLS_COPY, "COPY", 0, "Copy Normal", "Copy normal to buffer"},
8980  {EDBM_CLNOR_TOOLS_PASTE, "PASTE", 0, "Paste Normal", "Paste normal from buffer"},
8981  {EDBM_CLNOR_TOOLS_ADD, "ADD", 0, "Add Normal", "Add normal vector with selection"},
8983  "MULTIPLY",
8984  0,
8985  "Multiply Normal",
8986  "Multiply normal vector with selection"},
8988  "RESET",
8989  0,
8990  "Reset Normal",
8991  "Reset buffer and/or normal of selected element"},
8992  {0, NULL, 0, NULL, NULL},
8993 };
8994 
8996 {
8998  ViewLayer *view_layer = CTX_data_view_layer(C);
8999  uint objects_len = 0;
9001  view_layer, CTX_wm_view3d(C), &objects_len);
9002  const int mode = RNA_enum_get(op->ptr, "mode");
9003  const bool absolute = RNA_boolean_get(op->ptr, "absolute");
9004  float *normal_vector = scene->toolsettings->normal_vector;
9005  bool done_copy = false;
9006 
9007  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
9008  Object *obedit = objects[ob_index];
9009  BMEditMesh *em = BKE_editmesh_from_object(obedit);
9010  BMesh *bm = em->bm;
9011 
9012  if (bm->totloop == 0) {
9013  continue;
9014  }
9015 
9016  BKE_editmesh_ensure_autosmooth(em, obedit->data);
9017  BKE_editmesh_lnorspace_update(em, obedit->data);
9019  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
9020 
9021  switch (mode) {
9022  case EDBM_CLNOR_TOOLS_COPY:
9023  if (bm->totfacesel == 0 && bm->totvertsel == 0) {
9024  BM_loop_normal_editdata_array_free(lnors_ed_arr);
9025  continue;
9026  }
9027 
9028  if (done_copy ||
9029  (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1)) {
9030  BKE_report(op->reports,
9031  RPT_ERROR,
9032  "Can only copy one custom normal, vertex normal or face normal");
9033  BM_loop_normal_editdata_array_free(lnors_ed_arr);
9034  continue;
9035  }
9036  if (lnors_ed_arr->totloop == 1) {
9038  }
9039  else if (bm->totfacesel == 1) {
9040  BMFace *f;
9041  BMIter fiter;
9042  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9045  }
9046  }
9047  }
9048  else {
9049  /* 'Vertex' normal, i.e. common set of loop normals on the same vertex,
9050  * only if they are all the same. */
9051  bool are_same_lnors = true;
9052  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9053  if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) {
9054  are_same_lnors = false;
9055  }
9056  }
9057  if (are_same_lnors) {
9059  }
9060  }
9061  done_copy = true;
9062  break;
9063 
9065  if (!absolute) {
9066  if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) {
9067  /* If normal is nearly 0, do nothing. */
9068  break;
9069  }
9070  }
9071  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9072  if (absolute) {
9073  float abs_normal[3];
9074  copy_v3_v3(abs_normal, lnor_ed->loc);
9075  negate_v3(abs_normal);
9076  add_v3_v3(abs_normal, normal_vector);
9077 
9078  if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) {
9079  /* If abs normal is nearly 0, set clnor to initial value. */
9080  copy_v3_v3(abs_normal, lnor_ed->niloc);
9081  }
9083  abs_normal,
9084  lnor_ed->clnors_data);
9085  }
9086  else {
9088  normal_vector,
9089  lnor_ed->clnors_data);
9090  }
9091  }
9092  break;
9093 
9095  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9096  mul_v3_v3(lnor_ed->nloc, normal_vector);
9097 
9098  if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
9099  /* If abs normal is nearly 0, set clnor to initial value. */
9100  copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
9101  }
9103  lnor_ed->nloc,
9104  lnor_ed->clnors_data);
9105  }
9106  break;
9107 
9108  case EDBM_CLNOR_TOOLS_ADD:
9109  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9110  add_v3_v3(lnor_ed->nloc, normal_vector);
9111 
9112  if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
9113  /* If abs normal is nearly 0, set clnor to initial value. */
9114  copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
9115  }
9117  lnor_ed->nloc,
9118  lnor_ed->clnors_data);
9119  }
9120  break;
9121 
9123  zero_v3(normal_vector);
9124  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9126  normal_vector,
9127  lnor_ed->clnors_data);
9128  }
9129  break;
9130 
9131  default:
9132  BLI_assert(0);
9133  break;
9134  }
9135 
9136  BM_loop_normal_editdata_array_free(lnors_ed_arr);
9137 
9138  EDBM_update_generic(obedit->data, true, false);
9139  }
9140 
9141  MEM_freeN(objects);
9142  return OPERATOR_FINISHED;
9143 }
9144 
9146  PropertyRNA *prop,
9147  void *UNUSED(user_data))
9148 {
9149  const char *prop_id = RNA_property_identifier(prop);
9150  const int mode = RNA_enum_get(ptr, "mode");
9151 
9152  /* Only show absolute option in paste mode. */
9153  if (STREQ(prop_id, "absolute")) {
9154  return (mode == EDBM_CLNOR_TOOLS_PASTE);
9155  }
9156 
9157  /* Else, show it! */
9158  return true;
9159 }
9160 
9162 {
9163  uiLayout *layout = op->layout;
9165  PointerRNA ptr;
9166 
9167  RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
9168 
9169  /* Main auto-draw call */
9170  uiDefAutoButsRNA(layout, &ptr, normals_tools_draw_check_prop, NULL, NULL, '\0', false);
9171 }
9172 
9174 {
9175  /* identifiers */
9176  ot->name = "Normals Vector Tools";
9177  ot->description = "Custom normals tools using Normal Vector of UI";
9178  ot->idname = "MESH_OT_normals_tools";
9179 
9180  /* api callbacks */
9184 
9185  /* flags */
9187 
9188  ot->prop = RNA_def_enum(ot->srna,
9189  "mode",
9192  "Mode",
9193  "Mode of tools taking input from interface");
9195 
9197  "absolute",
9198  false,
9199  "Absolute Coordinates",
9200  "Copy Absolute coordinates or Normal vector");
9201 }
9202 
9205 /* -------------------------------------------------------------------- */
9210 {
9211  ViewLayer *view_layer = CTX_data_view_layer(C);
9212  uint objects_len = 0;
9214  view_layer, CTX_wm_view3d(C), &objects_len);
9215 
9216  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
9217  Object *obedit = objects[ob_index];
9218  BMEditMesh *em = BKE_editmesh_from_object(obedit);
9219  BMesh *bm = em->bm;
9220  BMFace *f;
9221  BMVert *v;
9222  BMEdge *e;
9223  BMLoop *l;
9224  BMIter fiter, viter, eiter, liter;
9225 
9226  const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp");
9227 
9228  BKE_editmesh_ensure_autosmooth(em, obedit->data);
9229  BKE_editmesh_lnorspace_update(em, obedit->data);
9230 
9231  float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bm->totvert, __func__);
9232  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9234  BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
9235  const int v_index = BM_elem_index_get(v);
9236  add_v3_v3(vnors[v_index], f->no);
9237  }
9238  }
9239  }
9240  for (int i = 0; i < bm->totvert; i++) {
9241  if (!is_zero_v3(vnors[i]) && normalize_v3(vnors[i]) < CLNORS_VALID_VEC_LEN) {
9242  zero_v3(vnors[i]);
9243  }
9244  }
9245 
9246  BLI_bitmap *loop_set = BLI_BITMAP_NEW(bm->totloop, __func__);
9247  const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
9248 
9249  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9250  BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
9251  if (!keep_sharp ||
9253  BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
9254  l = BM_face_vert_share_loop(f, v);
9255  const int l_index = BM_elem_index_get(l);
9256  const int v_index = BM_elem_index_get(l->v);
9257 
9258  if (!is_zero_v3(vnors[v_index])) {
9259  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
9261  bm->lnor_spacearr->lspacearr[l_index], vnors[v_index], clnors);
9262 
9264  BLI_BITMAP_ENABLE(loop_set, l_index);
9265  }
9266  else {
9267  LinkNode *loops = bm->lnor_spacearr->lspacearr[l_index]->loops;
9268  for (; loops; loops = loops->next) {
9269  BLI_BITMAP_ENABLE(loop_set, BM_elem_index_get((BMLoop *)loops->link));
9270  }
9271  }
9272  }
9273  }
9274  }
9275  }
9276  }
9277 
9278  int v_index;
9279  BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, v_index) {
9280  BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
9281  if (BLI_BITMAP_TEST(loop_set, BM_elem_index_get(l))) {
9282  const int loop_index = BM_elem_index_get(l);
9283  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
9285  bm->lnor_spacearr->lspacearr[loop_index], vnors[v_index], clnors);
9286  }
9287  }
9288  }
9289 
9290  MEM_freeN(loop_set);
9291  MEM_freeN(vnors);
9292  EDBM_update_generic(obedit->data, true, false);
9293  }
9294 
9295  MEM_freeN(objects);
9296  return OPERATOR_FINISHED;
9297 }
9298 
9300 {
9301  /* identifiers */
9302  ot->name = "Set Normals from Faces";
9303  ot->description = "Set the custom normals from the selected faces ones";
9304  ot->idname = "MESH_OT_set_normals_from_faces";
9305 
9306  /* api callbacks */
9309 
9310  /* flags */
9312 
9313  RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face");
9314 }
9315 
9318 /* -------------------------------------------------------------------- */
9323 {
9324  ViewLayer *view_layer = CTX_data_view_layer(C);
9325  uint objects_len = 0;
9327  view_layer, CTX_wm_view3d(C), &objects_len);
9328 
9329  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
9330  Object *obedit = objects[ob_index];
9331  BMEditMesh *em = BKE_editmesh_from_object(obedit);
9332  BMesh *bm = em->bm;
9333  BMFace *f;
9334  BMLoop *l;
9335  BMIter fiter, liter;
9336 
9337  BKE_editmesh_ensure_autosmooth(em, obedit->data);
9338  BKE_editmesh_lnorspace_update(em, obedit->data);
9340 
9341  float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop,
9342  __func__);
9343 
9344  /* This is weird choice of operation, taking all loops of faces of current vertex.
9345  * Could lead to some rather far away loops weighting as much as very close ones
9346  * (topologically speaking), with complex polygons.
9347  * Using topological distance here (rather than geometrical one)
9348  * makes sense imho, but would rather go with a more consistent and flexible code,
9349  * we could even add max topological distance to take into account, * and a weighting curve.
9350  * Would do that later though, think for now we can live with that choice. --mont29. */
9351  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
9352  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9353  l = lnor_ed->loop;
9354  float loop_normal[3];
9355 
9356  BM_ITER_ELEM (f, &fiter, l->v, BM_FACES_OF_VERT) {
9357  BMLoop *l_other;
9358  BM_ITER_ELEM (l_other, &liter, f, BM_LOOPS_OF_FACE) {
9359  const int l_index_other = BM_elem_index_get(l_other);
9360  short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset);
9362  bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal);
9363  add_v3_v3(smooth_normal[i], loop_normal);
9364  }
9365  }
9366  }
9367 
9368  const float factor = RNA_float_get(op->ptr, "factor");
9369 
9370  lnor_ed = lnors_ed_arr->lnor_editdata;
9371  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9372  float current_normal[3];
9373 
9374  if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) {
9375  /* Skip in case the smooth normal is invalid. */
9376  continue;
9377  }
9378 
9380  bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal);
9381 
9382  /* Note: again, this is not true spherical interpolation that normals would need...
9383  * But it's probably good enough for now. */
9384  mul_v3_fl(current_normal, 1.0f - factor);
9385  mul_v3_fl(smooth_normal[i], factor);
9386  add_v3_v3(current_normal, smooth_normal[i]);
9387 
9388  if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) {
9389  /* Skip in case the smoothed normal is invalid. */
9390  continue;
9391  }
9392 
9394  bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data);
9395  }
9396 
9397  BM_loop_normal_editdata_array_free(lnors_ed_arr);
9398  MEM_freeN(smooth_normal);
9399 
9400  EDBM_update_generic(obedit->data, true, false);
9401  }
9402 
9403  MEM_freeN(objects);
9404  return OPERATOR_FINISHED;
9405 }
9406 
9408 {
9409  /* identifiers */
9410  ot->name = "Smooth Normals Vectors";
9411  ot->description = "Smooth custom normals based on adjacent vertex normals";
9412  ot->idname = "MESH_OT_smooth_normals";
9413 
9414  /* api callbacks */
9417 
9418  /* flags */
9420 
9422  "factor",
9423  0.5f,
9424  0.0f,
9425  1.0f,
9426  "Factor",
9427  "Specifies weight of smooth vs original normal",
9428  0.0f,
9429  1.0f);
9430 }
9431 
9434 /* -------------------------------------------------------------------- */
9439 {
9440  ViewLayer *view_layer = CTX_data_view_layer(C);
9441  uint objects_len = 0;
9443  view_layer, CTX_wm_view3d(C), &objects_len);
9444 
9445  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
9446  Object *obedit = objects[ob_index];
9447  BMEditMesh *em = BKE_editmesh_from_object(obedit);
9448  BMesh *bm = em->bm;
9449  BMFace *f;
9450  BMIter fiter;
9451  const int face_strength = RNA_enum_get(op->ptr, "face_strength");
9452  const bool set = RNA_boolean_get(op->ptr, "set");
9453 
9455 
9456  const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
9457  int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT32, layer_id);
9458  if (cd_prop_int_index == -1) {
9460  cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT32, layer_id);
9461  }
9462  cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT32);
9463  const int cd_prop_int_offset = CustomData_get_n_offset(
9464  &bm->pdata, CD_PROP_INT32, cd_prop_int_index);
9465 
9467 
9468  if (set) {
9469  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9471  int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
9472  *strength = face_strength;
9473  }
9474  }
9475  }
9476  else {
9477  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9478  int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
9479  if (*strength == face_strength) {
9480  BM_face_select_set(bm, f, true);
9482  }
9483  else {
9484  BM_face_select_set(bm, f, false);
9485  }
9486  }
9487  }
9488 
9489  EDBM_update_generic(obedit->data, false, false);
9490  }
9491 
9492  MEM_freeN(objects);
9493  return OPERATOR_FINISHED;
9494 }
9495 
9497  {FACE_STRENGTH_WEAK, "WEAK", 0, "Weak", ""},
9498  {FACE_STRENGTH_MEDIUM, "MEDIUM", 0, "Medium", ""},
9499  {FACE_STRENGTH_STRONG, "STRONG", 0, "Strong", ""},
9500  {0, NULL, 0, NULL, NULL},
9501 };
9502 
9504 {
9505  /* identifiers */
9506  ot->name = "Face Normals Strength";
9507  ot->description = "Set/Get strength of face (used in Weighted Normal modifier)";
9508  ot->idname = "MESH_OT_mod_weighted_strength";
9509 
9510  /* api callbacks */
9513 
9514  /* flags */
9516 
9517  ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set Value", "Set value of faces");
9518 
9519  ot->prop = RNA_def_enum(
9520  ot->srna,
9521  "face_strength",
9524  "Face Strength",
9525  "Strength to use for assigning or selecting face influence for weighted normal modifier");
9526 }
9527 
typedef float(TangentPoint)[2]
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:252
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
#define CTX_DATA_END
Definition: BKE_context.h:260
int CustomData_number_of_layers(const struct CustomData *data, int type)
bool CustomData_has_layer(const struct CustomData *data, int type)
int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name)
int CustomData_get_layer_index(const struct CustomData *data, int type)
void * CustomData_bmesh_get(const struct CustomData *data, void *block, int type)
int CustomData_get_n_offset(const struct CustomData *data, int type, int n)
int CustomData_get_offset(const struct CustomData *data, int type)
void * CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n)
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me)
Definition: editmesh.c:264
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me)
Definition: editmesh.c:286
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
struct KeyBlock * BKE_keyblock_find_name(struct Key *key, const char name[])
Definition: key.c:1944
#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:420
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:426
#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:430
void id_us_plus(struct ID *id)
Definition: lib_id.c:288
General operations, lookup, etc. for materials.
struct Material *** BKE_object_material_array_p(struct Object *ob)
Definition: material.c:323
void BKE_object_material_resize(struct Main *bmain, struct Object *ob, const short totcol, bool do_id_user)
Definition: material.c:727
struct Material *** BKE_id_material_array_p(struct ID *id)
Definition: material.c:390
short * BKE_id_material_len_p(struct ID *id)
Definition: material.c:416
void BKE_id_material_clear(struct Main *bmain, struct ID *id)
Definition: material.c:622
short * BKE_object_material_len_p(struct Object *ob)
Definition: material.c:356
void BKE_id_material_resize(struct Main *bmain, struct ID *id, short totcol, bool do_id_user)
Definition: material.c:529
void BKE_object_material_array_assign(struct Main *bmain, struct Object *ob, struct Material ***matar, int totcol, const bool to_object_only)
Definition: material.c:1032
@ MLNOR_SPACE_IS_SINGLE
Definition: BKE_mesh.h:365
@ MLNOR_SPACEARR_BMLOOP_PTR
Definition: BKE_mesh.h:384
void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3])
void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2])
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:63
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:78
#define BLI_BITMAP_NEW(_tot, _alloc_string)
Definition: BLI_bitmap.h:50
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:32
unsigned int BLI_ghashutil_strhash_p(const void *ptr)
A min-heap / priority queue ADT.
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1)
HeapSimple * BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT
float BLI_heapsimple_top_value(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1)
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1)
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1
int BLI_listbase_count_at_most(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findptr(const struct ListBase *listbase, const void *ptr, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE int compare_ff(float a, float b, const float max_diff)
MINLINE float min_ff(float a, float b)
MINLINE int mod_i(int i, int n)
#define M_PI
Definition: BLI_math_base.h:38
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition: math_geom.c:6184
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
#define DEG2RADF(_deg)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:1020
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v3(float r[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE void zero_v3(float r[3])
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:417
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE void copy_v2_fl(float r[2], float f)
Random number functions.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition: rand.cc:76
struct RNG * BLI_rng_new_srandom(unsigned int seed)
Definition: rand.cc:64
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: rand.cc:120
int BLI_sortutil_cmp_float_reverse(const void *a_, const void *b_)
Definition: sort_utils.c:54
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define UNPACK3(a)
#define ELEM(...)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_ID_CURVE
#define TIP_(msgid)
#define IFACE_(msgid)
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:426
@ CD_CUSTOMLOOPNORMAL
@ CD_MDEFORMVERT
@ CD_PROP_INT32
@ CD_FREESTYLE_EDGE
@ CD_SHAPEKEY
@ CD_FREESTYLE_FACE
#define MAXMAT
@ ME_SYMMETRY_X
@ ME_EDIT_MIRROR_TOPO
@ FREESTYLE_EDGE_MARK
@ FREESTYLE_FACE_MARK
@ MOD_TRIANGULATE_QUAD_BEAUTY
@ eModifierMode_Realtime
@ eModifierType_Mirror
@ MOD_TRIANGULATE_NGON_BEAUTY
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID
@ MOD_MIR_AXIS_Z
@ MOD_MIR_CLIPPING
@ MOD_MIR_AXIS_X
@ MOD_MIR_AXIS_Y
Object is a sort of wrapper for general info.
@ OB_MESH
#define SCE_SELECT_FACE
#define PROP_SMOOTH
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
eDupli_ID_Flags
@ USER_DUP_MESH
@ USER_DUP_ACT
@ V3D_AROUND_ACTIVE
@ V3D_AROUND_CENTER_BOUNDS
@ V3D_AROUND_CURSOR
@ V3D_AROUND_CENTER_MEDIAN
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ OP_IS_REPEAT_LAST
@ OP_IS_MODAL_GRAB_CURSOR
void EDBM_verts_mirror_apply(struct BMEditMesh *em, const int sel_from, const int sel_to)
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode)
void ED_mesh_geometry_clear(struct Mesh *mesh)
Definition: mesh_data.c:1322
bool EDBM_selectmode_disable_multi_ex(struct Scene *scene, struct Base **bases, const uint bases_len, const short selectmode_disable, const short selectmode_fallback)
bool EDBM_mesh_hide(struct BMEditMesh *em, bool swap)
void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist)
void EDBM_select_flush(struct BMEditMesh *em)
void EDBM_verts_mirror_cache_end(struct BMEditMesh *em)
void EDBM_update_generic(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, const int axis, const bool use_self, const bool use_select, const bool respecthide, const bool use_topology, float maxdist, int *r_index)
void EDBM_verts_mirror_cache_begin(struct BMEditMesh *em, const int axis, const bool use_self, const bool use_select, const bool respecthide, const bool use_topology)
bool EDBM_mesh_reveal(struct BMEditMesh *em, bool select)
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag)
bool EDBM_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
void EDBM_selectmode_flush(struct BMEditMesh *em)
void EDBM_mesh_normals_update(struct BMEditMesh *em)
void EDBM_mesh_stats_multi(struct Object **objects, const uint objects_len, int totelem[3], int totelem_sel[3])
Definition: meshtools.c:1523
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:98
struct Base * ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, const eDupli_ID_Flags dupflag)
Definition: object_add.c:3313
@ BA_SELECT
Definition: ED_object.h:147
bool ED_object_calc_active_center_for_editmode(struct Object *obedit, const bool select_only, float r_center[3])
Definition: object_utils.c:54
void ED_outliner_select_sync_from_object_tag(struct bContext *C)
Definition: outliner_sync.c:56
void ED_area_status_text(ScrArea *area, const char *str)
Definition: area.c:815
bool ED_operator_editmesh(struct bContext *C)
Definition: screen_ops.c:404
bool ED_operator_scene_editable(struct bContext *C)
Definition: screen_ops.c:192
@ TFM_TRANSLATION
Definition: ED_transform.h:46
void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, int objects_len)
void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:190
@ V3D_PROJ_TEST_CLIP_NEAR
Definition: ED_view3d.h:196
void ED_view3d_win_to_3d_int(const struct View3D *v3d, const struct ARegion *region, const float depth_pt[3], const int mval[2], float r_out[3])
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region, const float co[3], float r_co[2], const eV3DProjTest flag)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:176
@ V3D_CURSOR_ORIENT_NONE
Definition: ED_view3d.h:99
void ED_view3d_cursor3d_update(struct bContext *C, const int mval[2], const bool use_depth, enum eV3DCursorOrient orientation)
Definition: view3d_edit.c:5151
void view3d_operator_needs_opengl(const struct bContext *C)
struct RegionView3D * ED_view3d_context_rv3d(struct bContext *C)
Definition: space_view3d.c:89
NSNotificationCenter * center
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define RNA_BEGIN(sptr, itemptr, propname)
Definition: RNA_access.h:1248
#define RNA_END
Definition: RNA_access.h:1255
StructRNA RNA_OperatorMousePath
@ PROP_ENUM
Definition: RNA_types.h:77
@ PROP_NEVER_UNLINK
Definition: RNA_types.h:232
@ PROP_ENUM_NO_TRANSLATE
Definition: RNA_types.h:279
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
@ PROP_NONE
Definition: RNA_types.h:113
#define C
Definition: RandGen.cpp:39
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_ITEM_R_EXPAND
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout, struct PointerRNA *ptr, bool(*check_prop)(struct PointerRNA *ptr, struct PropertyRNA *prop, void *user_data), void *user_data, struct PropertyRNA *prop_activate_init, eButLabelAlign label_align, const bool compact)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:90
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
#define NC_GEOM
Definition: WM_types.h:294
#define ND_DRAW
Definition: WM_types.h:362
@ OPTYPE_INTERNAL
Definition: WM_types.h:175
@ OPTYPE_BLOCKING
Definition: WM_types.h:157
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define ND_SELECT
Definition: WM_types.h:407
#define NC_OBJECT
Definition: WM_types.h:280
#define BM_elem_cb_check_hflag_disabled_simple(type, hflag_n)
@ BM_SPACEARR_DIRTY_ALL
Definition: bmesh_class.h:416
#define BM_DISK_EDGE_NEXT(e, v)
Definition: bmesh_class.h:556
#define BM_ALL_NOLOOP
Definition: bmesh_class.h:411
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_ALL
Definition: bmesh_class.h:410
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize)
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst, BMesh *bm_src, const char htype, const BMAllocTemplate *allocsize)
void BM_vert_separate(BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select, BMVert ***r_vout, int *r_vout_len)
Definition: bmesh_core.c:2486
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:1002
void BM_face_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:881
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
Definition: bmesh_core.c:147
void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, float vweight_factor, const bool do_triangulate, const int symmetry_axis, const float symmetry_eps)
BM_mesh_decimate.
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type)
Definition: bmesh_delete.c:282
void BM_mesh_edgeloops_free(ListBase *eloops)
int BM_mesh_edgeloops_find(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data)
int BM_edgeloop_length_get(BMEdgeLoopStore *el_store)
bool BM_edgeloop_is_closed(BMEdgeLoopStore *el_store)
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr)
ListBase * BM_edgeloop_verts_get(BMEdgeLoopStore *el_store)
bool BMO_error_occurred(BMesh *bm)
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:125
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:27
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
Definition: bmesh_interp.c:894
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
Definition: bmesh_interp.c:912
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
Elem Iter Flag Count.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_EDGE
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_select_history_clear(BMesh *bm)
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
BMVert * BM_mesh_active_vert_get(BMesh *bm)
void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag, const bool respecthide, const bool overwrite, const char hflag_test)
#define BM_select_history_store_notest(bm, ele)
#define BM_select_history_store_head_notest(bm, ele)
#define BM_select_history_store(bm, ele)
#define BM_SELECT_HISTORY_BACKUP(bm)
#define BM_SELECT_HISTORY_RESTORE(bm)
const BMAllocTemplate bm_mesh_allocsize_default
Definition: bmesh_mesh.c:46
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
Definition: bmesh_mesh.c:2476
void BM_lnorspace_update(BMesh *bm)
Definition: bmesh_mesh.c:1565
void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges)
Definition: bmesh_mesh.c:1582
void BM_mesh_elem_toolflags_ensure(BMesh *bm)
Definition: bmesh_mesh.c:98
bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
Definition: bmesh_mesh.c:1903
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
Definition: bmesh_mesh.c:307
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
BMesh Make Mesh.
Definition: bmesh_mesh.c:157
void BM_mesh_normals_update(BMesh *bm)
BMesh Compute Normals.
Definition: bmesh_mesh.c:500
BMLoopNorEditDataArray * BM_loop_normal_editdata_array_init(BMesh *bm, const bool do_all_loops_of_vert)
Definition: bmesh_mesh.c:1844
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2276
void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
Definition: bmesh_mesh.c:1892
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
Definition: bmesh_mesh.c:636
void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges)
Definition: bmesh_mesh.c:1940
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:98
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
Mesh -> BMesh.
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
void BM_mesh_copy_arrays(BMesh *bm_src, BMesh *bm_dst, BMVert **verts_src, uint verts_src_len, BMEdge **edges_src, uint edges_src_len, BMFace **faces_src, uint faces_src_len)
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag, const bool do_flush)
BMO_FLAG_BUFFER.
@ BMO_SYMMETRIZE_NEGATIVE_X
void * BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i)
void * BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int len)
void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag, const bool do_flush)
BMO_FLAG_BUFFER.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt,...)
#define BMO_edge_flag_set(bm, e, oflag, val)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float f)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
@ DEL_ONLYTAGGED
@ DEL_FACES_KEEP_BOUNDARY
@ DEL_EDGESFACES
@ DEL_EDGES
@ DEL_FACES
@ DEL_ONLYFACES
@ DEL_VERTS
#define BMO_FLAG_DEFAULTS
void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i)
@ BMO_FLAG_RESPECT_HIDE
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag)
void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
BMESH OPSTACK INIT OP.
@ BMO_DELIM_NORMAL
bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt,...)
BLI_INLINE void BMO_slot_map_float_insert(BMOperator *op, BMOpSlot *slot, void *element, const float val)
void BM_mesh_esubdivide(BMesh *bm, const char edge_hflag, const float smooth, const short smooth_falloff, const bool use_smooth_even, const float fractal, const float along_normal, const int numcuts, const int seltype, const int cornertype, const short use_single_edge, const short use_grid_fill, const short use_only_quads, const int seed)
@ SUBD_FALLOFF_LIN
@ SUBD_CORNER_FAN
@ SUBD_CORNER_STRAIGHT_CUT
@ SUBD_CORNER_PATH
@ SUBD_CORNER_INNERVERT
@ SUBD_RING_INTERP_SURF
@ SUBD_RING_INTERP_PATH
@ SUBD_RING_INTERP_LINEAR
@ SUBDIV_SELECT_ORIG
@ BMOP_POKE_MEDIAN_WEIGHTED
@ BMOP_POKE_BOUNDS
@ BMOP_POKE_MEDIAN
@ FACE_STRENGTH_STRONG
@ FACE_STRENGTH_WEAK
@ FACE_STRENGTH_MEDIUM
void BM_vert_normal_update(BMVert *v)
float BM_face_calc_area(const BMFace *f)
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int(**r_groups)[3])
Definition: bmesh_query.c:2899
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1995
bool BM_vert_is_wire(const BMVert *v)
Definition: bmesh_query.c:919
BMFace * BM_edge_pair_share_face_by_len(BMEdge *e_a, BMEdge *e_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
Definition: bmesh_query.c:289
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
Definition: bmesh_query.c:732
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1426
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
Definition: bmesh_query.c:1314
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
BMESH EDGE/FACE ANGLE.
Definition: bmesh_query.c:1719
float BM_loop_calc_face_angle(const BMLoop *l)
Definition: bmesh_query.c:1531
BMLoop * BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
Definition: bmesh_query.c:637
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
Definition: bmesh_query.c:1403
bool BM_vert_pair_share_face_check_cb(BMVert *v_a, BMVert *v_b, bool(*test_fn)(BMFace *, void *user_data), void *user_data)
Definition: bmesh_query.c:209
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
unsigned int U
Definition: btGjkEpa3.h:78
btMatrix3x3 absolute() const
Return the matrix with all values non negative.
Definition: btMatrix3x3.h:1028
static unsigned long seed
Definition: btSoftBody.h:39
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
Scene scene
void * user_data
void MESH_OT_poke(wmOperatorType *ot)
static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op)
static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v))
static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
static int edbm_fill_exec(bContext *C, wmOperator *op)
void MESH_OT_wireframe(wmOperatorType *ot)
void MESH_OT_hide(wmOperatorType *ot)
void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
static void edbm_normals_tools_ui(bContext *C, wmOperator *op)
void MESH_OT_uvs_reverse(wmOperatorType *ot)
static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], float(*mouse_path)[2], int len, char mode, int *isected)
static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_min, const int cuts_default)
static bool flip_custom_normals(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot)
static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static int edbm_solidify_exec(bContext *C, wmOperator *op)
@ SRT_VIEW_XAXIS
@ SRT_SELECTED
@ SRT_RANDOMIZE
@ SRT_MATERIAL
@ SRT_CURSOR_DISTANCE
@ SRT_REVERSE
@ SRT_VIEW_ZAXIS
static EnumPropertyItem average_method_items[]
static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op)
static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
static Base * mesh_separate_tagged(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
static void edbm_blend_from_shape_ui(bContext *C, wmOperator *op)
static void mesh_operator_edgering_props_get(wmOperator *op, struct EdgeRingOpSubdProps *op_props)
static bool bm_vert_connect_pair(BMesh *bm, BMVert *v_a, BMVert *v_b)
static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
void MESH_OT_faces_shade_flat(wmOperatorType *ot)
static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
static bool normals_tools_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data))
static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
void MESH_OT_edge_rotate(wmOperatorType *ot)
static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const short mat_nr)
static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
@ EDBM_CLNOR_TOOLS_RESET
@ EDBM_CLNOR_TOOLS_COPY
@ EDBM_CLNOR_TOOLS_ADD
@ EDBM_CLNOR_TOOLS_MULTIPLY
@ EDBM_CLNOR_TOOLS_PASTE
static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
static int edbm_mark_sharp_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_mesh_cornervert_types[]
static bool average_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data))
static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
void MESH_OT_edge_split(wmOperatorType *ot)
static int edbm_duplicate_exec(bContext *C, wmOperator *op)
static bool bm_vert_connect_select_history(BMesh *bm)
static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use_uvmerge, wmOperator *wmop)
void MESH_OT_delete(wmOperatorType *ot)
static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
void MESH_OT_point_normals(struct wmOperatorType *ot)
static const EnumPropertyItem * merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
static int edbm_bridge_tag_boundary_edges(BMesh *bm)
wmKeyMap * point_normals_modal_keymap(wmKeyConfig *keyconf)
static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
@ EDBM_CLNOR_AVERAGE_LOOP
@ EDBM_CLNOR_AVERAGE_FACE_AREA
@ EDBM_CLNOR_AVERAGE_ANGLE
static void edbm_average_normals_ui(bContext *C, wmOperator *op)
void MESH_OT_beautify_fill(wmOperatorType *ot)
static bool mesh_separate_loose(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
static void bmesh_selected_verts_center_calc(BMesh *bm, float *r_center)
static bool edbm_decimate_check(bContext *UNUSED(C), wmOperator *UNUSED(op))
static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
#define ELE_EDGE_CUT
void MESH_OT_colors_rotate(wmOperatorType *ot)
void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
@ EDBM_CLNOR_POINTTO_MODE_MOUSE
@ EDBM_CLNOR_POINTTO_MODE_COORDINATES
static bool bm_face_is_loose(BMFace *f)
static int edbm_smooth_normals_exec(bContext *C, wmOperator *op)
void MESH_OT_vert_connect(wmOperatorType *ot)
static bool edbm_edge_split_selected_verts(wmOperator *op, Object *obedit, BMEditMesh *em)
static EnumPropertyItem clnors_pointto_mode_items[]
void MESH_OT_vertices_smooth(wmOperatorType *ot)
static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
static void edbm_decimate_ui(bContext *C, wmOperator *op)
#define KNIFE_EXACT
static int bmelemsort_comp(const void *v1, const void *v2)
static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag)
void MESH_OT_face_make_planar(wmOperatorType *ot)
static void point_normals_free(wmOperator *op)
static int edbm_dissolve_faces_exec(bContext *C, wmOperator *op)
void MESH_OT_dissolve_edges(wmOperatorType *ot)
void MESH_OT_uvs_rotate(wmOperatorType *ot)
static int edbm_add_edge_face_exec__vert_edge_lookup(BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len, bool(*func)(const BMEdge *))
static void point_normals_apply(bContext *C, wmOperator *op, float target[3], const bool do_reset)
void MESH_OT_delete_loose(wmOperatorType *ot)
static int edbm_split_normals_exec(bContext *C, wmOperator *UNUSED(op))
#define WM_MODALKEY(_id)
static void edbm_point_normals_ui(bContext *C, wmOperator *op)
void MESH_OT_fill(wmOperatorType *ot)
static void point_normals_cancel(bContext *C, wmOperator *op)
void MESH_OT_mark_seam(wmOperatorType *ot)
static bool bm_vert_connect_select_history_edge_to_vert_path(BMesh *bm, ListBase *r_selected)
static int edbm_average_normals_exec(bContext *C, wmOperator *op)
void MESH_OT_remove_doubles(wmOperatorType *ot)
#define KNIFE_MULTICUT
void MESH_OT_offset_edge_loops(wmOperatorType *ot)
static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
static BMLoopNorEditDataArray * flip_custom_normals_init_data(BMesh *bm)
static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
void MESH_OT_merge_normals(struct wmOperatorType *ot)
void MESH_OT_subdivide_edgering(wmOperatorType *ot)
static bool mesh_separate_selected(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
static int edbm_hide_exec(bContext *C, wmOperator *op)
void MESH_OT_separate(wmOperatorType *ot)
static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
void MESH_OT_dissolve_limited(wmOperatorType *ot)
void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
void MESH_OT_blend_from_shape(wmOperatorType *ot)
static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
void MESH_OT_fill_grid(wmOperatorType *ot)
void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot)
static bool merge_target(BMEditMesh *em, Scene *scene, Object *ob, const bool use_cursor, const bool use_uvmerge, wmOperator *wmop)
static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static int edbm_merge_normals_exec(bContext *C, wmOperator *UNUSED(op))
void MESH_OT_decimate(wmOperatorType *ot)
static int edbm_unsubdivide_exec(bContext *C, wmOperator *op)
static int edbm_delete_exec(bContext *C, wmOperator *op)
static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
#define KNIFE_MIDPOINT
static bool edbm_add_edge_face__smooth_get(BMesh *bm)
@ MESH_DELETE_EDGE_FACE
@ MESH_DELETE_EDGE
@ MESH_DELETE_FACE
@ MESH_DELETE_VERT
@ MESH_DELETE_ONLY_FACE
static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_desel, BMFace *f)
void MESH_OT_knife_cut(wmOperatorType *ot)
static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
struct BMElemSort BMElemSort
static int edbm_reveal_exec(bContext *C, wmOperator *op)
void MESH_OT_dissolve_mode(wmOperatorType *ot)
static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
static bool bm_vert_is_select_history_open(BMesh *bm)
void MESH_OT_subdivide(wmOperatorType *ot)
static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
void MESH_OT_unsubdivide(wmOperatorType *ot)
#define MAXSLOPE
static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
void MESH_OT_duplicate(wmOperatorType *ot)
@ MESH_SEPARATE_LOOSE
@ MESH_SEPARATE_MATERIAL
@ MESH_SEPARATE_SELECTED
static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
void MESH_OT_normals_make_consistent(wmOperatorType *ot)
void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
static const EnumPropertyItem prop_mesh_face_strength_types[]
@ EDBM_CLNOR_MODAL_POINTTO_RESET
@ EDBM_CLNOR_MODAL_CANCEL
@ EDBM_CLNOR_MODAL_POINTTO_INVERT
@ EDBM_CLNOR_MODAL_CONFIRM
@ EDBM_CLNOR_MODAL_POINTTO_ALIGN
@ EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT
@ EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR
@ EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE
@ EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED
@ EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT
@ EDBM_CLNOR_MODAL_POINTTO_SPHERIZE
void MESH_OT_flip_normals(wmOperatorType *ot)
static void edbm_report_delete_info(ReportList *reports, const int totelem_old[3], const int totelem_new[3])
static bool edbm_fill_grid_prepare(BMesh *bm, int offset, int *span_p, const bool span_calc)
static int edbm_dissolve_mode_exec(bContext *C, wmOperator *op)
static void join_triangle_props(wmOperatorType *ot)
static bool point_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data))
void MESH_OT_mark_sharp(wmOperatorType *ot)
static bool edbm_sort_elements_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop)
void MESH_OT_vert_connect_path(wmOperatorType *ot)
static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
static bool point_normals_ensure(bContext *C, wmOperator *op)
void MESH_OT_reveal(wmOperatorType *ot)
static int edbm_merge_exec(bContext *C, wmOperator *op)
void MESH_OT_delete_edgeloop(wmOperatorType *ot)
void MESH_OT_normals_tools(struct wmOperatorType *ot)
static void sort_bmelem_flag(bContext *C, Scene *scene, Object *ob, RegionView3D *rv3d, const int types, const int flag, const int action, const int reverse, const uint seed)
static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot)
void MESH_OT_merge(wmOperatorType *ot)
void MESH_OT_sort_elements(wmOperatorType *ot)
void MESH_OT_fill_holes(wmOperatorType *ot)
#define CLNORS_VALID_VEC_LEN
static int edbm_subdivide_exec(bContext *C, wmOperator *op)
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot)
void MESH_OT_solidify(wmOperatorType *ot)
static EnumPropertyItem normal_vector_tool_items[]
static bool edbm_connect_vert_pair(BMEditMesh *em, struct Mesh *me, wmOperator *op)
void MESH_OT_smooth_normals(struct wmOperatorType *ot)
static bool mesh_separate_material(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
void MESH_OT_vert_connect_concave(wmOperatorType *ot)
static void point_normals_update_header(bContext *C, wmOperator *op)
static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
static int edbm_bridge_edge_loops_for_single_editmesh(wmOperator *op, BMEditMesh *em, struct Mesh *me, const bool use_pairs, const bool use_cyclic, const bool use_merge, const float merge_factor, const int twist_offset)
static const EnumPropertyItem * shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
static int edbm_poke_face_exec(bContext *C, wmOperator *op)
static bool point_normals_init(bContext *C, wmOperator *op)
static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
void MESH_OT_symmetrize(struct wmOperatorType *ot)
static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op)
static Base * mesh_separate_arrays(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old, BMVert **verts, uint verts_len, BMEdge **edges, uint edges_len, BMFace **faces, uint faces_len)
static bool edbm_edge_split_selected_edges(wmOperator *op, Object *obedit, BMEditMesh *em)
@ MESH_MERGE_LAST
@ MESH_MERGE_CENTER
@ MESH_MERGE_CURSOR
@ MESH_MERGE_FIRST
@ MESH_MERGE_COLLAPSE
static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
static int normals_split_merge(bContext *C, const bool do_merge)
static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
@ MESH_BRIDGELOOP_PAIRS
@ MESH_BRIDGELOOP_SINGLE
@ MESH_BRIDGELOOP_CLOSED
void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
void MESH_OT_colors_reverse(wmOperatorType *ot)
void MESH_OT_split_normals(struct wmOperatorType *ot)
void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot)
static const EnumPropertyItem merge_type_items[]
static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op)
void MESH_OT_dissolve_faces(wmOperatorType *ot)
static void normals_split(BMesh *bm)
static int edbm_point_normals_exec(bContext *C, wmOperator *op)
static bool shape_propagate(BMEditMesh *em)
static BMElem * edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm)
static int edbm_wireframe_exec(bContext *C, wmOperator *op)
static int edbm_decimate_exec(bContext *C, wmOperator *op)
static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
void MESH_OT_edge_face_add(wmOperatorType *ot)
void MESH_OT_edge_collapse(wmOperatorType *ot)
void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
static int edbm_separate_exec(bContext *C, wmOperator *op)
static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
void MESH_OT_dissolve_verts(wmOperatorType *ot)
static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
static int edbm_split_exec(bContext *C, wmOperator *op)
static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem knife_items[]
static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
void MESH_OT_average_normals(struct wmOperatorType *ot)
void MESH_OT_split(wmOperatorType *ot)
static float edbm_fill_grid_vert_tag_angle(BMVert *v)
bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt,...)
bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt,...)
bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op, const char *select_slot_out, const bool select_extend, const char *fmt,...)
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
bool EDBM_view3d_poll(bContext *C)
static float verts[][3]
uint col
BLI_INLINE float fb(float length, float L)
int count
#define fabsf(x)
static char ** types
Definition: makesdna.c:164
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong * next
static char faces[256]
void MESH_OT_convex_hull(struct wmOperatorType *ot)
static void clear(Message *msg)
Definition: msgfmt.c:294
static unsigned a[3]
Definition: RandGen.cpp:92
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
Definition: rall1d.h:359
const btScalar eps
Definition: poly34.cpp:11
return ret
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2941
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:2627
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
Definition: rna_access.c:3033
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
int RNA_collection_length(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6634
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:122
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1145
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:6655
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2331
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2607
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
Definition: rna_access.c:2358
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
Definition: rna_access.c:3132
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3543
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6413
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_enum_flag(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3795
void RNA_def_property_float_default(PropertyRNA *prop, float value)
Definition: rna_define.c:2042
void RNA_def_property_enum_default(PropertyRNA *prop, int value)
Definition: rna_define.c:2127
PropertyRNA * RNA_def_float_distance(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:4041
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description)
Definition: rna_define.c:1676
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
Definition: rna_define.c:4210
void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item)
Definition: rna_define.c:1892
PropertyRNA * RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:4133
PropertyRNA * RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier, int type, int subtype)
Definition: rna_define.c:1279
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4470
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4416
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
Definition: rna_define.c:2870
PropertyRNA * RNA_def_float_vector_xyz(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3883
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3819
void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item, int value)
Definition: rna_define.c:4455
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
Definition: rna_define.c:1706
PropertyRNA * RNA_def_float_rotation(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:4005
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]
Definition: rna_mesh.c:49
const EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[]
Definition: rna_modifier.c:338
const EnumPropertyItem rna_enum_axis_xyz_items[]
Definition: rna_modifier.c:584
const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[]
Definition: rna_modifier.c:314
const EnumPropertyItem DummyRNA_NULL_items[]
Definition: rna_rna.c:40
const EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[]
Definition: rna_scene.c:132
const EnumPropertyItem rna_enum_symmetrize_direction_items[]
#define min(a, b)
Definition: sort.c:51
void * regiondata
BMHeader head
Definition: bmesh_class.h:123
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMLoop * l
Definition: bmesh_class.h:140
short selectmode
Definition: BKE_editmesh.h:72
struct BMesh * bm
Definition: BKE_editmesh.h:52
short mat_nr
Definition: BKE_editmesh.h:73
struct BMEditSelection * next
Definition: bmesh_marking.h:24
struct BMEditSelection * prev
Definition: bmesh_marking.h:24
BMHeader head
Definition: bmesh_class.h:255
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:279
BMHeader head
Definition: bmesh_class.h:267
float no[3]
Definition: bmesh_class.h:280
char htype
Definition: bmesh_class.h:76
void * data
Definition: bmesh_class.h:63
BMLoopNorEditData ** lidx_to_lnor_editdata
Definition: bmesh_class.h:404
BMLoopNorEditData * lnor_editdata
Definition: bmesh_class.h:399
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
BMHeader head
Definition: bmesh_class.h:97
int totvert
Definition: bmesh_class.h:297
int totfacesel
Definition: bmesh_class.h:298
struct MLoopNorSpaceArray * lnor_spacearr
Definition: bmesh_class.h:343
char elem_index_dirty
Definition: bmesh_class.h:305
CustomData vdata
Definition: bmesh_class.h:337
int totedge
Definition: bmesh_class.h:297
ListBase selected
Definition: bmesh_class.h:356
CustomData edata
Definition: bmesh_class.h:337
int totvertsel
Definition: bmesh_class.h:298
int totloop
Definition: bmesh_class.h:297
int totedgesel
Definition: bmesh_class.h:298
char spacearr_dirty
Definition: bmesh_class.h:344
CustomData pdata
Definition: bmesh_class.h:337
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
struct Object * object
CustomDataLayer * layers
const char * identifier
Definition: RNA_types.h:446
const char * name
Definition: RNA_types.h:450
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
char name[64]
Definition: DNA_key_types.h:68
short relative
Definition: DNA_key_types.h:57
ListBase block
void * data
Definition: DNA_listBase.h:42
struct LinkData * next
Definition: DNA_listBase.h:41
void * link
Definition: BLI_linklist.h:40
struct LinkNode * next
Definition: BLI_linklist.h:39
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
MLoopNorSpace ** lspacearr
Definition: BKE_mesh.h:372
struct LinkNode * loops
Definition: BKE_mesh.h:355
Definition: BKE_main.h:116
struct BMEditMesh * edit_mesh
char editflag
struct Key * key
ListBase modifiers
struct Material ** mat
float loc[3]
char * matbits
float imat[4][4]
unsigned short actdef
float obmat[4][4]
void * data
Definition: rand.cc:48
float viewmat[4][4]
struct ToolSettings * toolsettings
View3DCursor cursor
char transform_pivot_point
float normal_vector[3]
short val
Definition: WM_types.h:579
int mval[2]
Definition: WM_types.h:583
short type
Definition: WM_types.h:577
const void * modal_items
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
bool(* poll_property)(const struct bContext *C, struct wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:782
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
void(* ui)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:787
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:744
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
IDProperty * properties
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
float max
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
uint len
void WM_cursor_wait(bool val)
Definition: wm_cursors.c:226
@ WM_CURSOR_KNIFE
Definition: wm_cursors.h:47
@ WM_CURSOR_NUM
Definition: wm_cursors.h:78
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ EVT_MODAL_MAP
@ MOUSEMOVE
@ INBETWEEN_MOUSEMOVE
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156
int WM_gesture_lines_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_lines_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition: wm_keymap.c:914
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
Definition: wm_keymap.c:985
const char * WM_bool_as_string(bool test)
Definition: wm_keymap.c:2003
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition: wm_keymap.c:888
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
void WM_operator_type_modal_from_exec_for_object_edit_coords(wmOperatorType *ot)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_operators.c:982