Blender  V3.3
editmesh_tools.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2004 Blender Foundation. All rights reserved. */
3 
8 #include <stddef.h>
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "DNA_key_types.h"
13 #include "DNA_material_types.h"
14 #include "DNA_mesh_types.h"
15 #include "DNA_meshdata_types.h"
16 #include "DNA_modifier_types.h"
17 #include "DNA_object_types.h"
18 #include "DNA_scene_types.h"
19 
20 #include "BLI_bitmap.h"
21 #include "BLI_heap_simple.h"
22 #include "BLI_linklist.h"
23 #include "BLI_linklist_stack.h"
24 #include "BLI_listbase.h"
25 #include "BLI_math.h"
26 #include "BLI_rand.h"
27 #include "BLI_sort_utils.h"
28 #include "BLI_string.h"
29 
30 #include "BKE_attribute.h"
31 #include "BKE_context.h"
32 #include "BKE_customdata.h"
33 #include "BKE_deform.h"
34 #include "BKE_editmesh.h"
35 #include "BKE_key.h"
36 #include "BKE_layer.h"
37 #include "BKE_lib_id.h"
38 #include "BKE_main.h"
39 #include "BKE_material.h"
40 #include "BKE_mesh.h"
41 #include "BKE_object.h"
42 #include "BKE_report.h"
43 #include "BKE_texture.h"
44 
45 #include "DEG_depsgraph.h"
46 #include "DEG_depsgraph_build.h"
47 
48 #include "BLT_translation.h"
49 
50 #include "RNA_access.h"
51 #include "RNA_define.h"
52 #include "RNA_enum_types.h"
53 #include "RNA_prototypes.h"
54 
55 #include "WM_api.h"
56 #include "WM_types.h"
57 
58 #include "ED_mesh.h"
59 #include "ED_object.h"
60 #include "ED_outliner.h"
61 #include "ED_screen.h"
62 #include "ED_select_utils.h"
63 #include "ED_transform.h"
64 #include "ED_uvedit.h"
65 #include "ED_view3d.h"
66 
67 #include "RE_texture.h"
68 
69 #include "UI_interface.h"
70 #include "UI_resources.h"
71 
72 #include "mesh_intern.h" /* own include */
73 
74 #include "bmesh_tools.h"
75 
76 #define USE_FACE_CREATE_SEL_EXTEND
77 
78 /* -------------------------------------------------------------------- */
83 {
84  const int cuts = RNA_int_get(op->ptr, "number_cuts");
85  const float smooth = RNA_float_get(op->ptr, "smoothness");
86  const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
87  const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
88  const bool use_quad_tri = !RNA_boolean_get(op->ptr, "ngon");
89 
90  if (use_quad_tri && RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT) {
91  RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT);
92  }
93  const int quad_corner_type = RNA_enum_get(op->ptr, "quadcorner");
94  const int seed = RNA_int_get(op->ptr, "seed");
95 
96  ViewLayer *view_layer = CTX_data_view_layer(C);
97  uint objects_len = 0;
99  view_layer, CTX_wm_view3d(C), &objects_len);
100 
101  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
102  Object *obedit = objects[ob_index];
103  BMEditMesh *em = BKE_editmesh_from_object(obedit);
104 
105  if (!(em->bm->totedgesel || em->bm->totfacesel)) {
106  continue;
107  }
108 
111  smooth,
113  false,
114  fractal,
115  along_normal,
116  cuts,
118  quad_corner_type,
119  use_quad_tri,
120  true,
121  false,
122  seed);
123 
124  EDBM_update(obedit->data,
125  &(const struct EDBMUpdate_Params){
126  .calc_looptri = true,
127  .calc_normals = false,
128  .is_destructive = true,
129  });
130  }
131 
132  MEM_freeN(objects);
133 
134  return OPERATOR_FINISHED;
135 }
136 
137 /* NOTE: these values must match delete_mesh() event values. */
139  {SUBD_CORNER_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
140  {SUBD_CORNER_PATH, "PATH", 0, "Path", ""},
141  {SUBD_CORNER_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
142  {SUBD_CORNER_FAN, "FAN", 0, "Fan", ""},
143  {0, NULL, 0, NULL, NULL},
144 };
145 
147 {
148  PropertyRNA *prop;
149 
150  /* identifiers */
151  ot->name = "Subdivide";
152  ot->description = "Subdivide selected edges";
153  ot->idname = "MESH_OT_subdivide";
154 
155  /* api callbacks */
158 
159  /* flags */
161 
162  /* properties */
163  prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 100, "Number of Cuts", "", 1, 10);
164  /* avoid re-using last var because it can cause
165  * _very_ high poly meshes and annoy users (or worse crash) */
167 
169  ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
170 
172 
174  "ngon",
175  true,
176  "Create N-Gons",
177  "When disabled, newly created faces are limited to 3 and 4 sided faces");
178  RNA_def_enum(
179  ot->srna,
180  "quadcorner",
183  "Quad Corner Type",
184  "How to subdivide quad corners (anything other than Straight Cut will prevent n-gons)");
185 
187  "fractal",
188  0.0f,
189  0.0f,
190  1e6f,
191  "Fractal",
192  "Fractal randomness factor",
193  0.0f,
194  1000.0f);
196  "fractal_along_normal",
197  0.0f,
198  0.0f,
199  1.0f,
200  "Along Normal",
201  "Apply fractal displacement along normal only",
202  0.0f,
203  1.0f);
205  "seed",
206  0,
207  0,
208  INT_MAX,
209  "Random Seed",
210  "Seed for the random number generator",
211  0,
212  255);
213 }
214 
217 /* -------------------------------------------------------------------- */
226  int cuts;
227  float smooth;
228 
231 };
232 
234  const int cuts_min,
235  const int cuts_default)
236 {
237  /* NOTE: these values must match delete_mesh() event values. */
238  static const EnumPropertyItem prop_subd_edgering_types[] = {
239  {SUBD_RING_INTERP_LINEAR, "LINEAR", 0, "Linear", ""},
240  {SUBD_RING_INTERP_PATH, "PATH", 0, "Blend Path", ""},
241  {SUBD_RING_INTERP_SURF, "SURFACE", 0, "Blend Surface", ""},
242  {0, NULL, 0, NULL, NULL},
243  };
244 
245  PropertyRNA *prop;
246 
247  prop = RNA_def_int(
248  ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", cuts_min, 64);
250 
252  "interpolation",
253  prop_subd_edgering_types,
255  "Interpolation",
256  "Interpolation method");
257 
259  ot->srna, "smoothness", 1.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 2.0f);
260 
261  /* profile-shape */
263  "profile_shape_factor",
264  0.0f,
265  -1e3f,
266  1e3f,
267  "Profile Factor",
268  "How much intermediary new edges are shrunk/expanded",
269  -2.0f,
270  2.0f);
271 
272  prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE);
275  RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile");
277  BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */
278 }
279 
281 {
282  op_props->interp_mode = RNA_enum_get(op->ptr, "interpolation");
283  op_props->cuts = RNA_int_get(op->ptr, "number_cuts");
284  op_props->smooth = RNA_float_get(op->ptr, "smoothness");
285 
286  op_props->profile_shape = RNA_enum_get(op->ptr, "profile_shape");
287  op_props->profile_shape_factor = RNA_float_get(op->ptr, "profile_shape_factor");
288 }
289 
291 {
292 
293  ViewLayer *view_layer = CTX_data_view_layer(C);
294  uint objects_len = 0;
296  view_layer, CTX_wm_view3d(C), &objects_len);
297  struct EdgeRingOpSubdProps op_props;
298 
299  mesh_operator_edgering_props_get(op, &op_props);
300 
301  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
302  Object *obedit = objects[ob_index];
303  BMEditMesh *em = BKE_editmesh_from_object(obedit);
304 
305  if (em->bm->totedgesel == 0) {
306  continue;
307  }
308 
309  if (!EDBM_op_callf(em,
310  op,
311  "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
312  "profile_shape=%i profile_shape_factor=%f",
314  op_props.interp_mode,
315  op_props.cuts,
316  op_props.smooth,
317  op_props.profile_shape,
318  op_props.profile_shape_factor)) {
319  continue;
320  }
321 
322  EDBM_update(obedit->data,
323  &(const struct EDBMUpdate_Params){
324  .calc_looptri = true,
325  .calc_normals = false,
326  .is_destructive = true,
327  });
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(obedit->data,
388  &(const struct EDBMUpdate_Params){
389  .calc_looptri = true,
390  .calc_normals = false,
391  .is_destructive = true,
392  });
393  }
394  MEM_freeN(objects);
395 
396  return OPERATOR_FINISHED;
397 }
398 
400 {
401  /* identifiers */
402  ot->name = "Un-Subdivide";
403  ot->description = "Un-subdivide selected edges and faces";
404  ot->idname = "MESH_OT_unsubdivide";
405 
406  /* api callbacks */
409 
410  /* flags */
412 
413  /* props */
414  RNA_def_int(
415  ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to un-subdivide", 1, 100);
416 }
417 
420 /* -------------------------------------------------------------------- */
424 /* NOTE: these values must match delete_mesh() event values. */
425 enum {
431 };
432 
433 static void edbm_report_delete_info(ReportList *reports,
434  const int totelem_old[3],
435  const int totelem_new[3])
436 {
437  BKE_reportf(reports,
438  RPT_INFO,
439  "Removed: %d vertices, %d edges, %d faces",
440  totelem_old[0] - totelem_new[0],
441  totelem_old[1] - totelem_new[1],
442  totelem_old[2] - totelem_new[2]);
443 }
444 
446 {
447  ViewLayer *view_layer = CTX_data_view_layer(C);
448 
449  uint objects_len = 0;
451  view_layer, CTX_wm_view3d(C), &objects_len);
452  bool changed_multi = false;
453 
454  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
455  Object *obedit = objects[ob_index];
456  BMEditMesh *em = BKE_editmesh_from_object(obedit);
457  const int type = RNA_enum_get(op->ptr, "type");
458 
459  switch (type) {
460  case MESH_DELETE_VERT: /* Erase Vertices */
461  if (em->bm->totvertsel == 0) {
462  continue;
463  }
465  if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) {
466  continue;
467  }
468  break;
469  case MESH_DELETE_EDGE: /* Erase Edges */
470  if (em->bm->totedgesel == 0) {
471  continue;
472  }
474  if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) {
475  continue;
476  }
477  break;
478  case MESH_DELETE_FACE: /* Erase Faces */
479  if (em->bm->totfacesel == 0) {
480  continue;
481  }
483  if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) {
484  continue;
485  }
486  break;
487  case MESH_DELETE_EDGE_FACE: /* Edges and Faces */
488  if ((em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
489  continue;
490  }
492  if (!EDBM_op_callf(
493  em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)) {
494  continue;
495  }
496  break;
497  case MESH_DELETE_ONLY_FACE: /* Only faces. */
498  if (em->bm->totfacesel == 0) {
499  continue;
500  }
502  if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES)) {
503  continue;
504  }
505  break;
506  default:
507  BLI_assert(0);
508  break;
509  }
510 
511  changed_multi = true;
512 
514 
516 
517  EDBM_update(obedit->data,
518  &(const struct EDBMUpdate_Params){
519  .calc_looptri = true,
520  .calc_normals = false,
521  .is_destructive = true,
522  });
523 
526  }
527 
528  MEM_freeN(objects);
529 
530  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
531 }
532 
534 {
535  static const EnumPropertyItem prop_mesh_delete_types[] = {
536  {MESH_DELETE_VERT, "VERT", 0, "Vertices", ""},
537  {MESH_DELETE_EDGE, "EDGE", 0, "Edges", ""},
538  {MESH_DELETE_FACE, "FACE", 0, "Faces", ""},
539  {MESH_DELETE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""},
540  {MESH_DELETE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""},
541  {0, NULL, 0, NULL, NULL},
542  };
543 
544  /* identifiers */
545  ot->name = "Delete";
546  ot->description = "Delete selected vertices, edges or faces";
547  ot->idname = "MESH_OT_delete";
548 
549  /* api callbacks */
552 
554 
555  /* flags */
557 
558  /* props */
559  ot->prop = RNA_def_enum(ot->srna,
560  "type",
561  prop_mesh_delete_types,
563  "Type",
564  "Method used for deleting mesh data");
566 }
567 
570 /* -------------------------------------------------------------------- */
574 static bool bm_face_is_loose(BMFace *f)
575 {
576  BMLoop *l_iter, *l_first;
577 
578  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
579  do {
580  if (!BM_edge_is_boundary(l_iter->e)) {
581  return false;
582  }
583  } while ((l_iter = l_iter->next) != l_first);
584 
585  return true;
586 }
587 
589 {
590  ViewLayer *view_layer = CTX_data_view_layer(C);
591  int totelem_old_sel[3];
592  int totelem_old[3];
593 
594  uint objects_len = 0;
596  view_layer, CTX_wm_view3d(C), &objects_len);
597 
598  EDBM_mesh_stats_multi(objects, objects_len, totelem_old, totelem_old_sel);
599 
600  const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && totelem_old_sel[0]);
601  const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && totelem_old_sel[1]);
602  const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && totelem_old_sel[2]);
603 
604  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
605  Object *obedit = objects[ob_index];
606 
607  BMEditMesh *em = BKE_editmesh_from_object(obedit);
608  BMesh *bm = em->bm;
609  BMIter iter;
610 
612 
613  if (use_faces) {
614  BMFace *f;
615 
616  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
619  }
620  }
621 
623  }
624 
625  if (use_edges) {
626  BMEdge *e;
627 
628  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
631  }
632  }
633 
635  }
636 
637  if (use_verts) {
638  BMVert *v;
639 
640  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
643  }
644  }
645 
647  }
648 
650 
651  EDBM_update(obedit->data,
652  &(const struct EDBMUpdate_Params){
653  .calc_looptri = true,
654  .calc_normals = false,
655  .is_destructive = true,
656  });
657  }
658 
659  int totelem_new[3];
660  EDBM_mesh_stats_multi(objects, objects_len, totelem_new, NULL);
661 
662  edbm_report_delete_info(op->reports, totelem_old, totelem_new);
663 
664  MEM_freeN(objects);
665 
666  return OPERATOR_FINISHED;
667 }
668 
670 {
671  /* identifiers */
672  ot->name = "Delete Loose";
673  ot->description = "Delete loose vertices, edges or faces";
674  ot->idname = "MESH_OT_delete_loose";
675 
676  /* api callbacks */
678 
680 
681  /* flags */
683 
684  /* props */
685  RNA_def_boolean(ot->srna, "use_verts", true, "Vertices", "Remove loose vertices");
686  RNA_def_boolean(ot->srna, "use_edges", true, "Edges", "Remove loose edges");
687  RNA_def_boolean(ot->srna, "use_faces", false, "Faces", "Remove loose faces");
688 }
689 
692 /* -------------------------------------------------------------------- */
697 {
698  ViewLayer *view_layer = CTX_data_view_layer(C);
699  uint objects_len = 0;
701  view_layer, CTX_wm_view3d(C), &objects_len);
702  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
703  Object *obedit = objects[ob_index];
704  BMEditMesh *em = BKE_editmesh_from_object(obedit);
705 
706  if (em->bm->totedgesel == 0) {
707  continue;
708  }
709 
710  if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true)) {
711  continue;
712  }
713 
714  EDBM_update(obedit->data,
715  &(const struct EDBMUpdate_Params){
716  .calc_looptri = true,
717  .calc_normals = false,
718  .is_destructive = true,
719  });
720  }
721  MEM_freeN(objects);
722 
723  return OPERATOR_FINISHED;
724 }
725 
727 {
728  /* identifiers */
729  ot->name = "Collapse Edges & Faces";
730  ot->description =
731  "Collapse isolated edge and face regions, merging data such as UV's and color attributes. "
732  "This can collapse edge-rings as well as regions of connected faces into vertices";
733  ot->idname = "MESH_OT_edge_collapse";
734 
735  /* api callbacks */
738 
739  /* flags */
741 }
742 
745 /* -------------------------------------------------------------------- */
750 {
751  BMEdge *e;
752  BMIter iter;
753 
754  uint vote_on_smooth[2] = {0, 0};
755 
756  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
757  if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
758  vote_on_smooth[BM_elem_flag_test_bool(e->l->f, BM_ELEM_SMOOTH)]++;
759  }
760  }
761 
762  return (vote_on_smooth[0] < vote_on_smooth[1]);
763 }
764 
765 #ifdef USE_FACE_CREATE_SEL_EXTEND
771  BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len, bool (*func)(const BMEdge *))
772 {
773  BMIter iter;
774  BMEdge *e_iter;
775  int i = 0;
776  BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
777  if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) {
778  if ((e_used == NULL) || (e_used != e_iter)) {
779  if (func(e_iter)) {
780  e_arr[i++] = e_iter;
781  if (i >= e_arr_len) {
782  break;
783  }
784  }
785  }
786  }
787  }
788  return i;
789 }
790 
792 {
793  BMIter iter;
794  bool found = false;
795 
796  if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) {
797  /* first look for 2 boundary edges */
798  BMVert *v;
799 
800  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
802  found = true;
803  break;
804  }
805  }
806 
807  if (found) {
808  BMEdge *ed_pair[3];
810  2) &&
811  (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) ||
812 
814  2) &&
815  (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false))) {
816  BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v),
817  BM_edge_other_vert(ed_pair[1], v));
818  BM_edge_select_set(bm, ed_pair[0], true);
819  BM_edge_select_set(bm, ed_pair[1], true);
820  if (e_other) {
821  BM_edge_select_set(bm, e_other, true);
822  }
823  return (BMElem *)v;
824  }
825  }
826  }
827  else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) {
828  /* first look for 2 boundary edges */
829  BMEdge *e;
830 
831  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
833  found = true;
834  break;
835  }
836  }
837  if (found) {
838  BMEdge *ed_pair_v1[2];
839  BMEdge *ed_pair_v2[2];
840  if (((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) ==
841  1) &&
843  1) &&
844  (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
845  (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
846 
847 # if 1 /* better support mixed cases T37203. */
849  1) &&
851  e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) &&
852  (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
853  (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
854 
856  e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) &&
858  1) &&
859  (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
860  (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) ||
861 # endif
862 
864  e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) &&
866  e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) &&
867  (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) &&
868  (BM_edge_share_face_check(e, ed_pair_v2[0]) == false))) {
869  BMVert *v1_other = BM_edge_other_vert(ed_pair_v1[0], e->v1);
870  BMVert *v2_other = BM_edge_other_vert(ed_pair_v2[0], e->v2);
871  BMEdge *e_other = (v1_other != v2_other) ? BM_edge_exists(v1_other, v2_other) : NULL;
872  BM_edge_select_set(bm, ed_pair_v1[0], true);
873  BM_edge_select_set(bm, ed_pair_v2[0], true);
874  if (e_other) {
875  BM_edge_select_set(bm, e_other, true);
876  }
877  return (BMElem *)e;
878  }
879  }
880  }
881 
882  return NULL;
883 }
885 {
886  /* Now we need to find the edge that isn't connected to this element. */
888 
889  /* Notes on hidden geometry:
890  * - Un-hide the face since its possible hidden was copied when copying
891  * surrounding face attributes.
892  * - Un-hide before adding to select history
893  * since we may extend into an existing, hidden vert/edge.
894  */
895 
897  BM_face_select_set(bm, f, false);
898 
899  if (ele_desel->head.htype == BM_VERT) {
900  BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel);
901  BLI_assert(f->len == 3);
902  BM_vert_select_set(bm, (BMVert *)ele_desel, false);
903  BM_edge_select_set(bm, l->next->e, true);
905  }
906  else {
907  BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel);
908  BLI_assert(ELEM(f->len, 4, 3));
909 
910  BM_edge_select_set(bm, (BMEdge *)ele_desel, false);
911  if (f->len == 4) {
912  BMEdge *e_active = l->next->next->e;
914  BM_edge_select_set(bm, e_active, true);
915  BM_select_history_store(bm, e_active);
916  }
917  else {
918  BMVert *v_active = l->next->next->v;
920  BM_vert_select_set(bm, v_active, true);
921  BM_select_history_store(bm, v_active);
922  }
923  }
924 }
925 #endif /* USE_FACE_CREATE_SEL_EXTEND */
926 
928 {
929  /* When this is used to dissolve we could avoid this, but checking isn't too slow. */
930  bool changed_multi = false;
931  ViewLayer *view_layer = CTX_data_view_layer(C);
932  uint objects_len = 0;
934  view_layer, CTX_wm_view3d(C), &objects_len);
935  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
936  Object *obedit = objects[ob_index];
937  BMEditMesh *em = BKE_editmesh_from_object(obedit);
938 
939  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totvertsel == 0)) {
940  continue;
941  }
942 
943  bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
944  int totedge_orig = em->bm->totedge;
945  int totface_orig = em->bm->totface;
946 
947  BMOperator bmop;
948 #ifdef USE_FACE_CREATE_SEL_EXTEND
949  BMElem *ele_desel;
950  BMFace *ele_desel_face;
951 
952  /* be extra clever, figure out if a partial selection should be extended so we can create
953  * geometry with single vert or single edge selection. */
955 #endif
956  if (!EDBM_op_init(em,
957  &bmop,
958  op,
959  "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
961  em->mat_nr,
962  use_smooth)) {
963  continue;
964  }
965 
966  BMO_op_exec(em->bm, &bmop);
967 
968  /* cancel if nothing was done */
969  if ((totedge_orig == em->bm->totedge) && (totface_orig == em->bm->totface)) {
970  EDBM_op_finish(em, &bmop, op, true);
971  continue;
972  }
973 #ifdef USE_FACE_CREATE_SEL_EXTEND
974  /* normally we would want to leave the new geometry selected,
975  * but being able to press F many times to add geometry is too useful! */
976  if (ele_desel && (BMO_slot_buffer_len(bmop.slots_out, "faces.out") == 1) &&
977  (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out"))) {
978  edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face);
979  }
980  else
981 #endif
982  {
983  /* Newly created faces may include existing hidden edges,
984  * copying face data from surrounding, may have copied hidden face flag too.
985  *
986  * Important that faces use flushing since 'edges.out'
987  * won't include hidden edges that already existed.
988  */
990  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true);
992  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false);
993 
995  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
997  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
998  }
999 
1000  if (!EDBM_op_finish(em, &bmop, op, true)) {
1001  continue;
1002  }
1003 
1004  EDBM_update(obedit->data,
1005  &(const struct EDBMUpdate_Params){
1006  .calc_looptri = true,
1007  .calc_normals = false,
1008  .is_destructive = true,
1009  });
1010  changed_multi = true;
1011  }
1012  MEM_freeN(objects);
1013 
1014  if (!changed_multi) {
1015  return OPERATOR_CANCELLED;
1016  }
1017 
1018  return OPERATOR_FINISHED;
1019 }
1020 
1022 {
1023  /* identifiers */
1024  ot->name = "Make Edge/Face";
1025  ot->description = "Add an edge or face to selected";
1026  ot->idname = "MESH_OT_edge_face_add";
1027 
1028  /* api callbacks */
1031 
1032  /* flags */
1034 }
1035 
1038 /* -------------------------------------------------------------------- */
1043 {
1045  ViewLayer *view_layer = CTX_data_view_layer(C);
1046  BMEdge *eed;
1047  BMIter iter;
1048  const bool clear = RNA_boolean_get(op->ptr, "clear");
1049 
1050  uint objects_len = 0;
1052  view_layer, CTX_wm_view3d(C), &objects_len);
1053  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1054  Object *obedit = objects[ob_index];
1055  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1056  BMesh *bm = em->bm;
1057 
1058  if (bm->totedgesel == 0) {
1059  continue;
1060  }
1061 
1062  if (clear) {
1063  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
1065  continue;
1066  }
1067 
1069  }
1070  }
1071  else {
1072  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
1074  continue;
1075  }
1077  }
1078  }
1079  }
1080 
1081  ED_uvedit_live_unwrap(scene, objects, objects_len);
1082 
1083  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1084  Object *obedit = objects[ob_index];
1085  EDBM_update(obedit->data,
1086  &(const struct EDBMUpdate_Params){
1087  .calc_looptri = true,
1088  .calc_normals = false,
1089  .is_destructive = false,
1090  });
1091  }
1092 
1093  MEM_freeN(objects);
1094 
1095  return OPERATOR_FINISHED;
1096 }
1097 
1099 {
1100  PropertyRNA *prop;
1101 
1102  /* identifiers */
1103  ot->name = "Mark Seam";
1104  ot->idname = "MESH_OT_mark_seam";
1105  ot->description = "(Un)mark selected edges as a seam";
1106 
1107  /* api callbacks */
1110 
1111  /* flags */
1113 
1114  prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1116 
1118 }
1119 
1122 /* -------------------------------------------------------------------- */
1127 {
1128  BMEdge *eed;
1129  BMIter iter;
1130  const bool clear = RNA_boolean_get(op->ptr, "clear");
1131  const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
1132  ViewLayer *view_layer = CTX_data_view_layer(C);
1133 
1134  uint objects_len = 0;
1136  view_layer, CTX_wm_view3d(C), &objects_len);
1137  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1138  Object *obedit = objects[ob_index];
1139  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1140  BMesh *bm = em->bm;
1141 
1142  if ((use_verts && bm->totvertsel == 0) || (!use_verts && bm->totedgesel == 0)) {
1143  continue;
1144  }
1145 
1146  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
1147  if (use_verts) {
1148  if (!(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
1150  continue;
1151  }
1152  }
1153  else if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1154  continue;
1155  }
1156 
1158  }
1159 
1160  EDBM_update(obedit->data,
1161  &(const struct EDBMUpdate_Params){
1162  .calc_looptri = true,
1163  .calc_normals = false,
1164  .is_destructive = false,
1165  });
1166  }
1167  MEM_freeN(objects);
1168 
1169  return OPERATOR_FINISHED;
1170 }
1171 
1173 {
1174  PropertyRNA *prop;
1175 
1176  /* identifiers */
1177  ot->name = "Mark Sharp";
1178  ot->idname = "MESH_OT_mark_sharp";
1179  ot->description = "(Un)mark selected edges as sharp";
1180 
1181  /* api callbacks */
1184 
1185  /* flags */
1187 
1188  prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
1190  prop = RNA_def_boolean(
1191  ot->srna,
1192  "use_verts",
1193  false,
1194  "Vertices",
1195  "Consider vertices instead of edges to select which edges to (un)tag as sharp");
1197 }
1198 
1201 /* -------------------------------------------------------------------- */
1205 static bool edbm_connect_vert_pair(BMEditMesh *em, struct Mesh *me, wmOperator *op)
1206 {
1207  BMesh *bm = em->bm;
1208  BMOperator bmop;
1209  const int verts_len = bm->totvertsel;
1210  bool is_pair = (verts_len == 2);
1211  int len = 0;
1212  bool check_degenerate = true;
1213 
1214  bool checks_succeded = true;
1215 
1216  /* sanity check */
1217  if (verts_len < 2) {
1218  return false;
1219  }
1220 
1221  BMVert **verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__);
1222  {
1223  BMIter iter;
1224  BMVert *v;
1225  int i = 0;
1226 
1227  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
1229  verts[i++] = v;
1230  }
1231  }
1232 
1234  verts[0],
1235  verts[1],
1237  check_degenerate = false;
1238  is_pair = false;
1239  }
1240  }
1241 
1242  if (is_pair) {
1243  if (!EDBM_op_init(em,
1244  &bmop,
1245  op,
1246  "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
1247  verts,
1248  verts_len,
1250  BM_ELEM_HIDDEN)) {
1251  checks_succeded = false;
1252  }
1253  }
1254  else {
1255  if (!EDBM_op_init(em,
1256  &bmop,
1257  op,
1258  "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
1259  verts,
1260  verts_len,
1262  check_degenerate)) {
1263  checks_succeded = false;
1264  }
1265  }
1266  if (checks_succeded) {
1267  BMBackup em_backup = EDBM_redo_state_store(em);
1268 
1270 
1271  BMO_op_exec(bm, &bmop);
1272  const bool failure = BMO_error_occurred_at_level(bm, BMO_ERROR_FATAL);
1273  len = BMO_slot_get(bmop.slots_out, "edges.out")->len;
1274 
1275  if (len && is_pair) {
1276  /* new verts have been added, we have to select the edges, not just flush */
1278  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
1279  }
1280 
1281  bool em_backup_free = true;
1282  if (!EDBM_op_finish(em, &bmop, op, false)) {
1283  len = 0;
1284  }
1285  else if (failure) {
1286  len = 0;
1287  EDBM_redo_state_restore_and_free(&em_backup, em, true);
1288  em_backup_free = false;
1289  }
1290  else {
1291  /* so newly created edges get the selection state from the vertex */
1293 
1295 
1296  EDBM_update(me,
1297  &(const struct EDBMUpdate_Params){
1298  .calc_looptri = true,
1299  .calc_normals = false,
1300  .is_destructive = true,
1301  });
1302  }
1303 
1304  if (em_backup_free) {
1305  EDBM_redo_state_free(&em_backup);
1306  }
1307  }
1308  MEM_freeN(verts);
1309 
1310  return len;
1311 }
1312 
1314 {
1315  ViewLayer *view_layer = CTX_data_view_layer(C);
1316  uint objects_len = 0;
1317  uint failed_objects_len = 0;
1319  view_layer, CTX_wm_view3d(C), &objects_len);
1320 
1321  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1322  Object *obedit = objects[ob_index];
1323  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1324 
1325  if (!edbm_connect_vert_pair(em, obedit->data, op)) {
1326  failed_objects_len++;
1327  }
1328  }
1329  MEM_freeN(objects);
1330  return failed_objects_len == objects_len ? OPERATOR_CANCELLED : OPERATOR_FINISHED;
1331 }
1332 
1334 {
1335  /* identifiers */
1336  ot->name = "Vertex Connect";
1337  ot->idname = "MESH_OT_vert_connect";
1338  ot->description = "Connect selected vertices of faces, splitting the face";
1339 
1340  /* api callbacks */
1343 
1344  /* flags */
1346 }
1347 
1350 /* -------------------------------------------------------------------- */
1358 {
1359  BMEditSelection *ele_a = bm->selected.first;
1360  BMEditSelection *ele_b = bm->selected.last;
1361  if ((ele_a->htype == BM_VERT) && (ele_b->htype == BM_VERT)) {
1363  1) &&
1365  1)) {
1366  return true;
1367  }
1368  }
1369 
1370  return false;
1371 }
1372 
1373 static bool bm_vert_connect_pair(BMesh *bm, BMVert *v_a, BMVert *v_b)
1374 {
1375  BMOperator bmop;
1376  BMVert **verts;
1377  const int totedge_orig = bm->totedge;
1378 
1379  BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, "connect_vert_pair");
1380 
1381  verts = BMO_slot_buffer_alloc(&bmop, bmop.slots_in, "verts", 2);
1382  verts[0] = v_a;
1383  verts[1] = v_b;
1384 
1387 
1388  BMO_op_exec(bm, &bmop);
1389  BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
1390  BMO_op_finish(bm, &bmop);
1391  return (bm->totedge != totedge_orig);
1392 }
1393 
1395 {
1396  /* Logic is as follows:
1397  *
1398  * - If there are any isolated/wire verts - connect as edges.
1399  * - Otherwise connect faces.
1400  * - If all edges have been created already, closed the loop.
1401  */
1402  if (BLI_listbase_count_at_most(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) {
1403  BMEditSelection *ese;
1404  int tot = 0;
1405  bool changed = false;
1406  bool has_wire = false;
1407  // bool all_verts;
1408 
1409  /* ensure all verts have history */
1410  for (ese = bm->selected.first; ese; ese = ese->next, tot++) {
1411  BMVert *v;
1412  if (ese->htype != BM_VERT) {
1413  break;
1414  }
1415  v = (BMVert *)ese->ele;
1416  if ((has_wire == false) && ((v->e == NULL) || BM_vert_is_wire(v))) {
1417  has_wire = true;
1418  }
1419  }
1420  // all_verts = (ese == NULL);
1421 
1422  if (has_wire == false) {
1423  /* all verts have faces , connect verts via faces! */
1424  if (tot == bm->totvertsel) {
1425  BMEditSelection *ese_last;
1426  ese_last = bm->selected.first;
1427  ese = ese_last->next;
1428 
1429  do {
1430 
1431  if (BM_edge_exists((BMVert *)ese_last->ele, (BMVert *)ese->ele)) {
1432  /* pass, edge exists (and will be selected) */
1433  }
1434  else {
1435  changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele);
1436  }
1437  } while ((void)(ese_last = ese), (ese = ese->next));
1438 
1439  if (changed) {
1440  return true;
1441  }
1442  }
1443 
1444  if (changed == false) {
1445  /* existing loops: close the selection */
1447  changed |= bm_vert_connect_pair(bm,
1448  (BMVert *)((BMEditSelection *)bm->selected.first)->ele,
1449  (BMVert *)((BMEditSelection *)bm->selected.last)->ele);
1450 
1451  if (changed) {
1452  return true;
1453  }
1454  }
1455  }
1456  }
1457 
1458  else {
1459  /* no faces, simply connect the verts by edges */
1460  BMEditSelection *ese_prev;
1461  ese_prev = bm->selected.first;
1462  ese = ese_prev->next;
1463 
1464  do {
1465  if (BM_edge_exists((BMVert *)ese_prev->ele, (BMVert *)ese->ele)) {
1466  /* pass, edge exists (and will be selected) */
1467  }
1468  else {
1469  BMEdge *e;
1470  e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
1471  BM_edge_select_set(bm, e, true);
1472  changed = true;
1473  }
1474  } while ((void)(ese_prev = ese), (ese = ese->next));
1475 
1476  if (changed == false) {
1477  /* existing loops: close the selection */
1479  BMEdge *e;
1480  ese_prev = bm->selected.first;
1481  ese = bm->selected.last;
1482  e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
1483  BM_edge_select_set(bm, e, true);
1484  }
1485  }
1486 
1487  return true;
1488  }
1489  }
1490 
1491  return false;
1492 }
1493 
1499 {
1500  ListBase selected_orig = {NULL, NULL};
1501  BMEditSelection *ese;
1502  int edges_len = 0;
1503  bool side = false;
1504 
1505  /* first check all edges are OK */
1506  for (ese = bm->selected.first; ese; ese = ese->next) {
1507  if (ese->htype == BM_EDGE) {
1508  edges_len += 1;
1509  }
1510  else {
1511  return false;
1512  }
1513  }
1514  /* if this is a mixed selection, bail out! */
1515  if (bm->totedgesel != edges_len) {
1516  return false;
1517  }
1518 
1519  SWAP(ListBase, bm->selected, selected_orig);
1520 
1521  /* convert edge selection into 2 ordered loops (where the first edge ends up in the middle) */
1522  for (ese = selected_orig.first; ese; ese = ese->next) {
1523  BMEdge *e_curr = (BMEdge *)ese->ele;
1524  BMEdge *e_prev = ese->prev ? (BMEdge *)ese->prev->ele : NULL;
1525  BMLoop *l_curr;
1526  BMLoop *l_prev;
1527  BMVert *v;
1528 
1529  if (e_prev) {
1530  BMFace *f = BM_edge_pair_share_face_by_len(e_curr, e_prev, &l_curr, &l_prev, true);
1531  if (f) {
1532  if ((e_curr->v1 != l_curr->v) == (e_prev->v1 != l_prev->v)) {
1533  side = !side;
1534  }
1535  }
1536  else if (is_quad_flip_v3(e_curr->v1->co, e_curr->v2->co, e_prev->v2->co, e_prev->v1->co)) {
1537  side = !side;
1538  }
1539  }
1540 
1541  v = (&e_curr->v1)[side];
1542  if (!bm->selected.last || (BMVert *)((BMEditSelection *)bm->selected.last)->ele != v) {
1544  }
1545 
1546  v = (&e_curr->v1)[!side];
1547  if (!bm->selected.first || (BMVert *)((BMEditSelection *)bm->selected.first)->ele != v) {
1549  }
1550 
1551  e_prev = e_curr;
1552  }
1553 
1554  *r_selected = bm->selected;
1555  bm->selected = selected_orig;
1556 
1557  return true;
1558 }
1559 
1561 {
1562  ViewLayer *view_layer = CTX_data_view_layer(C);
1563  uint objects_len = 0;
1564  uint failed_selection_order_len = 0;
1565  uint failed_connect_len = 0;
1567  view_layer, CTX_wm_view3d(C), &objects_len);
1568 
1569  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1570  Object *obedit = objects[ob_index];
1571  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1572  BMesh *bm = em->bm;
1573  const bool is_pair = (em->bm->totvertsel == 2);
1574  ListBase selected_orig = {NULL, NULL};
1575 
1576  if (bm->totvertsel == 0) {
1577  continue;
1578  }
1579 
1580  /* when there is only 2 vertices, we can ignore selection order */
1581  if (is_pair) {
1582  if (!edbm_connect_vert_pair(em, obedit->data, op)) {
1583  failed_connect_len++;
1584  }
1585  continue;
1586  }
1587 
1588  if (bm->selected.first) {
1589  BMEditSelection *ese = bm->selected.first;
1590  if (ese->htype == BM_EDGE) {
1592  SWAP(ListBase, bm->selected, selected_orig);
1593  }
1594  }
1595  }
1596 
1598 
1601 
1603 
1604  EDBM_update(obedit->data,
1605  &(const struct EDBMUpdate_Params){
1606  .calc_looptri = true,
1607  .calc_normals = false,
1608  .is_destructive = true,
1609  });
1610  }
1611  else {
1612  failed_selection_order_len++;
1613  }
1614 
1615  if (!BLI_listbase_is_empty(&selected_orig)) {
1617  bm->selected = selected_orig;
1618  }
1619  }
1620 
1621  MEM_freeN(objects);
1622 
1623  if (failed_selection_order_len == objects_len) {
1624  BKE_report(op->reports, RPT_ERROR, "Invalid selection order");
1625  return OPERATOR_CANCELLED;
1626  }
1627  if (failed_connect_len == objects_len) {
1628  BKE_report(op->reports, RPT_ERROR, "Could not connect vertices");
1629  return OPERATOR_CANCELLED;
1630  }
1631 
1632  return OPERATOR_FINISHED;
1633 }
1634 
1636 {
1637  /* identifiers */
1638  ot->name = "Vertex Connect Path";
1639  ot->idname = "MESH_OT_vert_connect_path";
1640  ot->description = "Connect vertices by their selection order, creating edges, splitting faces";
1641 
1642  /* api callbacks */
1645 
1646  /* flags */
1648 }
1649 
1652 /* -------------------------------------------------------------------- */
1657 {
1658  ViewLayer *view_layer = CTX_data_view_layer(C);
1659  uint objects_len = 0;
1661  view_layer, CTX_wm_view3d(C), &objects_len);
1662  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1663  Object *obedit = objects[ob_index];
1664  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1665 
1666  if (em->bm->totfacesel == 0) {
1667  continue;
1668  }
1669 
1671  em, op, "faces.out", true, "connect_verts_concave faces=%hf", BM_ELEM_SELECT)) {
1672  continue;
1673  }
1674  EDBM_update(obedit->data,
1675  &(const struct EDBMUpdate_Params){
1676  .calc_looptri = true,
1677  .calc_normals = false,
1678  .is_destructive = true,
1679  });
1680  }
1681 
1682  MEM_freeN(objects);
1683  return OPERATOR_FINISHED;
1684 }
1685 
1687 {
1688  /* identifiers */
1689  ot->name = "Split Concave Faces";
1690  ot->idname = "MESH_OT_vert_connect_concave";
1691  ot->description = "Make all faces convex";
1692 
1693  /* api callbacks */
1696 
1697  /* flags */
1699 }
1700 
1703 /* -------------------------------------------------------------------- */
1708 {
1709  ViewLayer *view_layer = CTX_data_view_layer(C);
1710  const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
1711  uint objects_len = 0;
1713  view_layer, CTX_wm_view3d(C), &objects_len);
1714 
1715  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1716  Object *obedit = objects[ob_index];
1717  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1718 
1719  if (em->bm->totfacesel == 0) {
1720  continue;
1721  }
1722 
1723  if (!EDBM_op_call_and_selectf(em,
1724  op,
1725  "faces.out",
1726  true,
1727  "connect_verts_nonplanar faces=%hf angle_limit=%f",
1729  angle_limit)) {
1730  continue;
1731  }
1732 
1733  EDBM_update(obedit->data,
1734  &(const struct EDBMUpdate_Params){
1735  .calc_looptri = true,
1736  .calc_normals = false,
1737  .is_destructive = true,
1738  });
1739  }
1740  MEM_freeN(objects);
1741 
1742  return OPERATOR_FINISHED;
1743 }
1744 
1746 {
1747  PropertyRNA *prop;
1748 
1749  /* identifiers */
1750  ot->name = "Split Non-Planar Faces";
1751  ot->idname = "MESH_OT_vert_connect_nonplanar";
1752  ot->description = "Split non-planar faces that exceed the angle threshold";
1753 
1754  /* api callbacks */
1757 
1758  /* flags */
1760 
1761  /* props */
1762  prop = RNA_def_float_rotation(ot->srna,
1763  "angle_limit",
1764  0,
1765  NULL,
1766  0.0f,
1767  DEG2RADF(180.0f),
1768  "Max Angle",
1769  "Angle limit",
1770  0.0f,
1771  DEG2RADF(180.0f));
1773 }
1774 
1777 /* -------------------------------------------------------------------- */
1782 {
1783  ViewLayer *view_layer = CTX_data_view_layer(C);
1784  uint objects_len = 0;
1786  view_layer, CTX_wm_view3d(C), &objects_len);
1787 
1788  const int repeat = RNA_int_get(op->ptr, "repeat");
1789  const float fac = RNA_float_get(op->ptr, "factor");
1790 
1791  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1792  Object *obedit = objects[ob_index];
1793  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1794  if (em->bm->totfacesel == 0) {
1795  continue;
1796  }
1797 
1798  if (!EDBM_op_callf(em,
1799  op,
1800  "planar_faces faces=%hf iterations=%i factor=%f",
1802  repeat,
1803  fac)) {
1804  continue;
1805  }
1806 
1807  EDBM_update(obedit->data,
1808  &(const struct EDBMUpdate_Params){
1809  .calc_looptri = true,
1810  .calc_normals = true,
1811  .is_destructive = true,
1812  });
1813  }
1814  MEM_freeN(objects);
1815 
1816  return OPERATOR_FINISHED;
1817 }
1818 
1820 {
1821  /* identifiers */
1822  ot->name = "Make Planar Faces";
1823  ot->idname = "MESH_OT_face_make_planar";
1824  ot->description = "Flatten selected faces";
1825 
1826  /* api callbacks */
1829 
1830  /* flags */
1832 
1833  /* props */
1834  RNA_def_float(ot->srna, "factor", 1.0f, -10.0f, 10.0f, "Factor", "", 0.0f, 1.0f);
1835  RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
1836 }
1837 
1840 /* -------------------------------------------------------------------- */
1845 {
1846  BMesh *bm = em->bm;
1847  if (bm->totedgesel == 0) {
1848  return false;
1849  }
1850 
1852 
1854  em, op, "edges.out", false, "split_edges edges=%he", BM_ELEM_SELECT)) {
1855  return false;
1856  }
1857 
1859 
1860  EDBM_select_flush(em);
1861  EDBM_update(obedit->data,
1862  &(const struct EDBMUpdate_Params){
1863  .calc_looptri = true,
1864  .calc_normals = false,
1865  .is_destructive = true,
1866  });
1867 
1868  return true;
1869 }
1870 
1872 {
1873  BMesh *bm = em->bm;
1874 
1875  /* Note that tracking vertices through the 'split_edges' operator is complicated.
1876  * Instead, tag loops for selection. */
1877  if (bm->totvertsel == 0) {
1878  return false;
1879  }
1880 
1882 
1883  /* Flush from vertices to edges. */
1884  BMIter iter;
1885  BMEdge *eed;
1886  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
1888  if (eed->l != NULL) {
1889  if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
1893  }
1894  /* Store selection in loop tags. */
1895  BMLoop *l_iter = eed->l;
1896  do {
1898  } while ((l_iter = l_iter->radial_next) != eed->l);
1899  }
1900  }
1901 
1902  if (!EDBM_op_callf(em,
1903  op,
1904  "split_edges edges=%he verts=%hv use_verts=%b",
1905  BM_ELEM_TAG,
1907  true)) {
1908  return false;
1909  }
1910 
1911  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1912  if (eed->l != NULL) {
1913  BMLoop *l_iter = eed->l;
1914  do {
1915  if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
1916  BM_vert_select_set(em->bm, l_iter->v, true);
1917  }
1918  } while ((l_iter = l_iter->radial_next) != eed->l);
1919  }
1920  else {
1921  /* Split out wire. */
1922  for (int i = 0; i < 2; i++) {
1923  BMVert *v = *(&eed->v1 + i);
1925  if (eed != BM_DISK_EDGE_NEXT(eed, v)) {
1926  BM_vert_separate(bm, v, &eed, 1, true, NULL, NULL);
1927  }
1928  }
1929  }
1930  }
1931  }
1932 
1934 
1935  EDBM_select_flush(em);
1936  EDBM_update(obedit->data,
1937  &(const struct EDBMUpdate_Params){
1938  .calc_looptri = true,
1939  .calc_normals = false,
1940  .is_destructive = true,
1941  });
1942 
1943  return true;
1944 }
1945 
1947 {
1948  const int type = RNA_enum_get(op->ptr, "type");
1949 
1950  ViewLayer *view_layer = CTX_data_view_layer(C);
1951  uint objects_len = 0;
1953  view_layer, CTX_wm_view3d(C), &objects_len);
1954  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1955  Object *obedit = objects[ob_index];
1956  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1957 
1958  switch (type) {
1959  case BM_VERT:
1960  if (!edbm_edge_split_selected_verts(op, obedit, em)) {
1961  continue;
1962  }
1963  break;
1964  case BM_EDGE:
1965  if (!edbm_edge_split_selected_edges(op, obedit, em)) {
1966  continue;
1967  }
1968  break;
1969  default:
1970  BLI_assert(0);
1971  }
1972  }
1973  MEM_freeN(objects);
1974 
1975  return OPERATOR_FINISHED;
1976 }
1977 
1979 {
1980  /* identifiers */
1981  ot->name = "Edge Split";
1982  ot->idname = "MESH_OT_edge_split";
1983  ot->description = "Split selected edges so that each neighbor face gets its own copy";
1984 
1985  /* api callbacks */
1988 
1989  /* flags */
1991 
1992  /* properties */
1993  static const EnumPropertyItem merge_type_items[] = {
1994  {BM_EDGE, "EDGE", 0, "Faces by Edges", "Split faces along selected edges"},
1995  {BM_VERT,
1996  "VERT",
1997  0,
1998  "Faces & Edges by Vertices",
1999  "Split faces and edges connected to selected vertices"},
2000  {0, NULL, 0, NULL, NULL},
2001  };
2002 
2003  ot->prop = RNA_def_enum(
2004  ot->srna, "type", merge_type_items, BM_EDGE, "Type", "Method to use for splitting");
2005 }
2006 
2009 /* -------------------------------------------------------------------- */
2014 {
2015  ViewLayer *view_layer = CTX_data_view_layer(C);
2016  uint objects_len = 0;
2018  view_layer, CTX_wm_view3d(C), &objects_len);
2019  bool changed = false;
2020 
2021  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2022  Object *obedit = objects[ob_index];
2023  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2024  if (em->bm->totvertsel == 0) {
2025  continue;
2026  }
2027 
2028  BMOperator bmop;
2029  BMesh *bm = em->bm;
2030  changed = true;
2031 
2032  EDBM_op_init(em,
2033  &bmop,
2034  op,
2035  "duplicate geom=%hvef use_select_history=%b use_edge_flip_from_face=%b",
2037  true,
2038  true);
2039 
2040  BMO_op_exec(bm, &bmop);
2041 
2042  /* de-select all would clear otherwise */
2044 
2046 
2048  bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
2049 
2050  /* rebuild editselection */
2052 
2053  if (!EDBM_op_finish(em, &bmop, op, true)) {
2054  continue;
2055  }
2056  EDBM_update(obedit->data,
2057  &(const struct EDBMUpdate_Params){
2058  .calc_looptri = true,
2059  .calc_normals = false,
2060  .is_destructive = true,
2061  });
2062  }
2063  MEM_freeN(objects);
2064 
2065  return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2066 }
2067 
2068 static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2069 {
2070  WM_cursor_wait(true);
2071  const int retval = edbm_duplicate_exec(C, op);
2072  WM_cursor_wait(false);
2073 
2074  return retval;
2075 }
2076 
2078 {
2079  /* identifiers */
2080  ot->name = "Duplicate";
2081  ot->description = "Duplicate selected vertices, edges or faces";
2082  ot->idname = "MESH_OT_duplicate";
2083 
2084  /* api callbacks */
2087 
2089 
2090  /* to give to transform */
2091  RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
2092 }
2093 
2095 {
2096  BMLoopNorEditDataArray *lnors_ed_arr = NULL;
2098  /* The mesh has custom normal data, update these too.
2099  * Otherwise they will be left in a mangled state.
2100  */
2102  lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, true);
2103  }
2104 
2105  return lnors_ed_arr;
2106 }
2107 
2109 {
2110  if (!lnors_ed_arr) {
2111  return false;
2112  }
2113 
2114  if (lnors_ed_arr->totloop == 0) {
2115  /* No loops normals to flip, exit early! */
2116  return false;
2117  }
2118 
2121 
2122  /* We need to recreate the custom normal array because the clnors_data will
2123  * be mangled because we swapped the loops around when we flipped the faces. */
2124  BMLoopNorEditDataArray *lnors_ed_arr_new_full = BM_loop_normal_editdata_array_init(bm, true);
2125 
2126  {
2127  /* We need to recalculate all loop normals in the affected area. Even the ones that are not
2128  * going to be flipped because the clnors data is mangled. */
2129 
2130  BMLoopNorEditData *lnor_ed_new_full = lnors_ed_arr_new_full->lnor_editdata;
2131  for (int i = 0; i < lnors_ed_arr_new_full->totloop; i++, lnor_ed_new_full++) {
2132 
2133  BMLoopNorEditData *lnor_ed =
2134  lnors_ed_arr->lidx_to_lnor_editdata[lnor_ed_new_full->loop_index];
2135 
2136  BLI_assert(lnor_ed != NULL);
2137 
2139  bm->lnor_spacearr->lspacearr[lnor_ed_new_full->loop_index],
2140  lnor_ed->nloc,
2141  lnor_ed_new_full->clnors_data);
2142  }
2143  }
2144 
2145  BMFace *f;
2146  BMLoop *l, *l_start;
2147  BMIter iter_f;
2148  BM_ITER_MESH (f, &iter_f, bm, BM_FACES_OF_MESH) {
2149  /* Flip all the custom loop normals on the selected faces. */
2150  if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
2151  continue;
2152  }
2153 
2154  /* Because the winding has changed, we need to go the reverse way around the face to get the
2155  * correct placement of the normals. However we need to derive the old loop index to get the
2156  * correct data. Note that the first loop index is the same though. So the loop starts and ends
2157  * in the same place as before the flip.
2158  */
2159 
2160  l_start = l = BM_FACE_FIRST_LOOP(f);
2161  int old_index = BM_elem_index_get(l);
2162  do {
2163  int loop_index = BM_elem_index_get(l);
2164 
2165  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lidx_to_lnor_editdata[old_index];
2166  BMLoopNorEditData *lnor_ed_new = lnors_ed_arr_new_full->lidx_to_lnor_editdata[loop_index];
2167  BLI_assert(lnor_ed != NULL && lnor_ed_new != NULL);
2168 
2169  negate_v3(lnor_ed->nloc);
2170 
2172  bm->lnor_spacearr->lspacearr[loop_index], lnor_ed->nloc, lnor_ed_new->clnors_data);
2173 
2174  old_index++;
2175  l = l->prev;
2176  } while (l != l_start);
2177  }
2178  BM_loop_normal_editdata_array_free(lnors_ed_arr_new_full);
2179  return true;
2180 }
2181 
2184 /* -------------------------------------------------------------------- */
2189 {
2191  return;
2192  }
2193 
2194  /* The mesh has custom normal data, flip them. */
2195  BMesh *bm = em->bm;
2196 
2199  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
2200 
2201  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
2202  negate_v3(lnor_ed->nloc);
2203 
2205  bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
2206  }
2207  BM_loop_normal_editdata_array_free(lnors_ed_arr);
2208  EDBM_update(obedit->data,
2209  &(const struct EDBMUpdate_Params){
2210  .calc_looptri = true,
2211  .calc_normals = false,
2212  .is_destructive = false,
2213  });
2214 }
2215 
2217 {
2218 
2219  bool has_flipped_faces = false;
2220 
2221  /* See if we have any custom normals to flip. */
2223 
2224  if (EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) {
2225  has_flipped_faces = true;
2226  }
2227 
2228  if (flip_custom_normals(em->bm, lnors_ed_arr) || has_flipped_faces) {
2229  EDBM_update(obedit->data,
2230  &(const struct EDBMUpdate_Params){
2231  .calc_looptri = true,
2232  .calc_normals = false,
2233  .is_destructive = false,
2234  });
2235  }
2236 
2237  if (lnors_ed_arr != NULL) {
2238  BM_loop_normal_editdata_array_free(lnors_ed_arr);
2239  }
2240 }
2241 
2243 {
2244  const bool only_clnors = RNA_boolean_get(op->ptr, "only_clnors");
2245 
2246  ViewLayer *view_layer = CTX_data_view_layer(C);
2247  uint objects_len = 0;
2249  view_layer, CTX_wm_view3d(C), &objects_len);
2250 
2251  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2252  Object *obedit = objects[ob_index];
2253  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2254 
2255  if (only_clnors) {
2256  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
2257  continue;
2258  }
2260  }
2261  else {
2262  if (em->bm->totfacesel == 0) {
2263  continue;
2264  }
2265  edbm_flip_normals_face_winding(op, obedit, em);
2266  }
2267  }
2268 
2269  MEM_freeN(objects);
2270  return OPERATOR_FINISHED;
2271 }
2272 
2274 {
2275  /* identifiers */
2276  ot->name = "Flip Normals";
2277  ot->description = "Flip the direction of selected faces' normals (and of their vertices)";
2278  ot->idname = "MESH_OT_flip_normals";
2279 
2280  /* api callbacks */
2283 
2284  /* flags */
2286 
2288  "only_clnors",
2289  false,
2290  "Custom Normals Only",
2291  "Only flip the custom loop normals of the selected elements");
2292 }
2293 
2296 /* -------------------------------------------------------------------- */
2304 {
2305  BMEdge *eed;
2306  BMIter iter;
2307  const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
2308 
2309  int tot_failed_all = 0;
2310  bool no_selected_edges = true, invalid_selected_edges = true;
2311 
2312  ViewLayer *view_layer = CTX_data_view_layer(C);
2313  uint objects_len = 0;
2315  view_layer, CTX_wm_view3d(C), &objects_len);
2316  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2317  Object *obedit = objects[ob_index];
2318  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2319  int tot = 0;
2320 
2321  if (em->bm->totedgesel == 0) {
2322  continue;
2323  }
2324  no_selected_edges = false;
2325 
2326  /* first see if we have two adjacent faces */
2327  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2329  if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2330  BMFace *fa, *fb;
2331  if (BM_edge_face_pair(eed, &fa, &fb)) {
2332  /* if both faces are selected we rotate between them,
2333  * otherwise - rotate between 2 unselected - but not mixed */
2336  tot++;
2337  }
2338  }
2339  }
2340  }
2341 
2342  /* OK, we don't have two adjacent faces, but we do have two selected ones.
2343  * that's an error condition. */
2344  if (tot == 0) {
2345  continue;
2346  }
2347  invalid_selected_edges = false;
2348 
2349  BMOperator bmop;
2350  EDBM_op_init(em, &bmop, op, "rotate_edges edges=%he use_ccw=%b", BM_ELEM_TAG, use_ccw);
2351 
2352  /* avoids leaving old verts selected which can be a problem running multiple times,
2353  * since this means the edges become selected around the face
2354  * which then attempt to rotate */
2355  BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "edges", BM_EDGE, BM_ELEM_SELECT, true);
2356 
2357  BMO_op_exec(em->bm, &bmop);
2358  /* edges may rotate into hidden vertices, if this does _not_ run we get an illogical state */
2360  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true);
2362  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
2363 
2364  const int tot_rotate = BMO_slot_buffer_len(bmop.slots_out, "edges.out");
2365  const int tot_failed = tot - tot_rotate;
2366 
2367  tot_failed_all += tot_failed;
2368 
2369  if (tot_failed != 0) {
2370  /* If some edges fail to rotate, we need to re-select them,
2371  * otherwise we can end up with invalid selection
2372  * (unselected edge between 2 selected faces). */
2374  }
2375 
2377 
2378  if (!EDBM_op_finish(em, &bmop, op, true)) {
2379  continue;
2380  }
2381 
2382  EDBM_update(obedit->data,
2383  &(const struct EDBMUpdate_Params){
2384  .calc_looptri = true,
2385  .calc_normals = false,
2386  .is_destructive = true,
2387  });
2388  }
2389  MEM_freeN(objects);
2390 
2391  if (no_selected_edges) {
2392  BKE_report(
2393  op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about");
2394  return OPERATOR_CANCELLED;
2395  }
2396 
2397  /* Ok, we don't have two adjacent faces, but we do have two selected ones.
2398  * that's an error condition. */
2399  if (invalid_selected_edges) {
2400  BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated");
2401  return OPERATOR_CANCELLED;
2402  }
2403 
2404  if (tot_failed_all != 0) {
2405  BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all);
2406  }
2407 
2408  return OPERATOR_FINISHED;
2409 }
2410 
2412 {
2413  /* identifiers */
2414  ot->name = "Rotate Selected Edge";
2415  ot->description = "Rotate selected edge or adjoining faces";
2416  ot->idname = "MESH_OT_edge_rotate";
2417 
2418  /* api callbacks */
2421 
2422  /* flags */
2424 
2425  /* props */
2426  RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
2427 }
2428 
2431 /* -------------------------------------------------------------------- */
2436 {
2437  const bool unselected = RNA_boolean_get(op->ptr, "unselected");
2438  ViewLayer *view_layer = CTX_data_view_layer(C);
2439  bool changed = false;
2440 
2441  uint objects_len = 0;
2443  view_layer, CTX_wm_view3d(C), &objects_len);
2444  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2445  Object *obedit = objects[ob_index];
2446  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2447  BMesh *bm = em->bm;
2448 
2449  if (unselected) {
2450  if (em->selectmode & SCE_SELECT_VERTEX) {
2451  if (bm->totvertsel == bm->totvert) {
2452  continue;
2453  }
2454  }
2455  else if (em->selectmode & SCE_SELECT_EDGE) {
2456  if (bm->totedgesel == bm->totedge) {
2457  continue;
2458  }
2459  }
2460  else if (em->selectmode & SCE_SELECT_FACE) {
2461  if (bm->totfacesel == bm->totface) {
2462  continue;
2463  }
2464  }
2465  }
2466  else {
2467  if (bm->totvertsel == 0) {
2468  continue;
2469  }
2470  }
2471 
2472  if (EDBM_mesh_hide(em, unselected)) {
2473  EDBM_update(obedit->data,
2474  &(const struct EDBMUpdate_Params){
2475  .calc_looptri = true,
2476  .calc_normals = false,
2477  .is_destructive = false,
2478  });
2479  changed = true;
2480  }
2481  }
2482  MEM_freeN(objects);
2483 
2484  if (!changed) {
2485  return OPERATOR_CANCELLED;
2486  }
2487 
2488  return OPERATOR_FINISHED;
2489 }
2490 
2492 {
2493  /* identifiers */
2494  ot->name = "Hide Selected";
2495  ot->idname = "MESH_OT_hide";
2496  ot->description = "Hide (un)selected vertices, edges or faces";
2497 
2498  /* api callbacks */
2499  ot->exec = edbm_hide_exec;
2501 
2502  /* flags */
2504 
2505  /* props */
2507  ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
2508 }
2509 
2512 /* -------------------------------------------------------------------- */
2517 {
2518  const bool select = RNA_boolean_get(op->ptr, "select");
2519  ViewLayer *view_layer = CTX_data_view_layer(C);
2520 
2521  uint objects_len = 0;
2523  view_layer, CTX_wm_view3d(C), &objects_len);
2524  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2525  Object *obedit = objects[ob_index];
2526  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2527 
2528  if (EDBM_mesh_reveal(em, select)) {
2529  EDBM_update(obedit->data,
2530  &(const struct EDBMUpdate_Params){
2531  .calc_looptri = true,
2532  .calc_normals = false,
2533  .is_destructive = false,
2534  });
2535  }
2536  }
2537  MEM_freeN(objects);
2538 
2539  return OPERATOR_FINISHED;
2540 }
2541 
2543 {
2544  /* identifiers */
2545  ot->name = "Reveal Hidden";
2546  ot->idname = "MESH_OT_reveal";
2547  ot->description = "Reveal all hidden vertices, edges and faces";
2548 
2549  /* api callbacks */
2552 
2553  /* flags */
2555 
2556  RNA_def_boolean(ot->srna, "select", true, "Select", "");
2557 }
2558 
2561 /* -------------------------------------------------------------------- */
2566 {
2567  ViewLayer *view_layer = CTX_data_view_layer(C);
2568  const bool inside = RNA_boolean_get(op->ptr, "inside");
2569 
2570  uint objects_len = 0;
2572  view_layer, CTX_wm_view3d(C), &objects_len);
2573  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2574  Object *obedit = objects[ob_index];
2575  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2576 
2577  if (em->bm->totfacesel == 0) {
2578  continue;
2579  }
2580 
2581  BMLoopNorEditDataArray *lnors_ed_arr = NULL;
2582 
2583  if (inside) {
2584  /* Save custom normal data for later so we can flip them correctly. */
2585  lnors_ed_arr = flip_custom_normals_init_data(em->bm);
2586  }
2587 
2588  if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) {
2589  continue;
2590  }
2591 
2592  if (inside) {
2593  EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
2594  flip_custom_normals(em->bm, lnors_ed_arr);
2595  if (lnors_ed_arr != NULL) {
2596  BM_loop_normal_editdata_array_free(lnors_ed_arr);
2597  }
2598  }
2599 
2600  EDBM_update(obedit->data,
2601  &(const struct EDBMUpdate_Params){
2602  .calc_looptri = true,
2603  .calc_normals = false,
2604  .is_destructive = false,
2605  });
2606  }
2607  MEM_freeN(objects);
2608 
2609  return OPERATOR_FINISHED;
2610 }
2611 
2613 {
2614  /* identifiers */
2615  ot->name = "Recalculate Normals";
2616  ot->description = "Make face and vertex normals point either outside or inside the mesh";
2617  ot->idname = "MESH_OT_normals_make_consistent";
2618 
2619  /* api callbacks */
2622 
2623  /* flags */
2625 
2626  RNA_def_boolean(ot->srna, "inside", false, "Inside", "");
2627 }
2628 
2631 /* -------------------------------------------------------------------- */
2636 {
2637  const float fac = RNA_float_get(op->ptr, "factor");
2638 
2639  const bool xaxis = RNA_boolean_get(op->ptr, "xaxis");
2640  const bool yaxis = RNA_boolean_get(op->ptr, "yaxis");
2641  const bool zaxis = RNA_boolean_get(op->ptr, "zaxis");
2642  int repeat = RNA_int_get(op->ptr, "repeat");
2643 
2644  if (!repeat) {
2645  repeat = 1;
2646  }
2647 
2648  ViewLayer *view_layer = CTX_data_view_layer(C);
2649  uint objects_len = 0;
2651  view_layer, CTX_wm_view3d(C), &objects_len);
2652  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2653  Object *obedit = objects[ob_index];
2654  Mesh *me = obedit->data;
2655  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2656  bool mirrx = false, mirry = false, mirrz = false;
2657  float clip_dist = 0.0f;
2658  const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
2659 
2660  if (em->bm->totvertsel == 0) {
2661  continue;
2662  }
2663 
2664  /* mirror before smooth */
2665  if (((Mesh *)obedit->data)->symmetry & ME_SYMMETRY_X) {
2666  EDBM_verts_mirror_cache_begin(em, 0, false, true, false, use_topology);
2667  }
2668 
2669  /* if there is a mirror modifier with clipping, flag the verts that
2670  * are within tolerance of the plane(s) of reflection
2671  */
2672  LISTBASE_FOREACH (ModifierData *, md, &obedit->modifiers) {
2673  if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
2675 
2676  if (mmd->flag & MOD_MIR_CLIPPING) {
2677  if (mmd->flag & MOD_MIR_AXIS_X) {
2678  mirrx = true;
2679  }
2680  if (mmd->flag & MOD_MIR_AXIS_Y) {
2681  mirry = true;
2682  }
2683  if (mmd->flag & MOD_MIR_AXIS_Z) {
2684  mirrz = true;
2685  }
2686 
2687  clip_dist = mmd->tolerance;
2688  }
2689  }
2690  }
2691 
2692  for (int i = 0; i < repeat; i++) {
2693  if (!EDBM_op_callf(
2694  em,
2695  op,
2696  "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
2697  "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
2699  fac,
2700  mirrx,
2701  mirry,
2702  mirrz,
2703  clip_dist,
2704  xaxis,
2705  yaxis,
2706  zaxis)) {
2707  continue;
2708  }
2709  }
2710 
2711  /* apply mirror */
2712  if (((Mesh *)obedit->data)->symmetry & ME_SYMMETRY_X) {
2715  }
2716 
2717  EDBM_update(obedit->data,
2718  &(const struct EDBMUpdate_Params){
2719  .calc_looptri = true,
2720  .calc_normals = false,
2721  .is_destructive = false,
2722  });
2723  }
2724  MEM_freeN(objects);
2725 
2726  return OPERATOR_FINISHED;
2727 }
2728 
2730 {
2731  /* identifiers */
2732  ot->name = "Smooth Vertices";
2733  ot->description = "Flatten angles of selected vertices";
2734  ot->idname = "MESH_OT_vertices_smooth";
2735 
2736  /* api callbacks */
2739 
2740  /* flags */
2742 
2744  ot->srna, "factor", 0.0f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
2745  RNA_def_int(
2746  ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100);
2747 
2749 
2750  RNA_def_boolean(ot->srna, "xaxis", true, "X-Axis", "Smooth along the X axis");
2751  RNA_def_boolean(ot->srna, "yaxis", true, "Y-Axis", "Smooth along the Y axis");
2752  RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis");
2753 
2754  /* Set generic modal callbacks. */
2756 }
2757 
2760 /* -------------------------------------------------------------------- */
2765 {
2766  int tot_unselected = 0;
2767  ViewLayer *view_layer = CTX_data_view_layer(C);
2768 
2769  const float lambda_factor = RNA_float_get(op->ptr, "lambda_factor");
2770  const float lambda_border = RNA_float_get(op->ptr, "lambda_border");
2771  const bool usex = RNA_boolean_get(op->ptr, "use_x");
2772  const bool usey = RNA_boolean_get(op->ptr, "use_y");
2773  const bool usez = RNA_boolean_get(op->ptr, "use_z");
2774  const bool preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume");
2775  int repeat = RNA_int_get(op->ptr, "repeat");
2776 
2777  if (!repeat) {
2778  repeat = 1;
2779  }
2780 
2781  uint objects_len = 0;
2783  view_layer, CTX_wm_view3d(C), &objects_len);
2784  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2785  Object *obedit = objects[ob_index];
2786  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2787  Mesh *me = obedit->data;
2788  bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
2789 
2790  if (em->bm->totvertsel == 0) {
2791  tot_unselected++;
2792  continue;
2793  }
2794 
2795  /* Mirror before smooth. */
2796  if (((Mesh *)obedit->data)->symmetry & ME_SYMMETRY_X) {
2797  EDBM_verts_mirror_cache_begin(em, 0, false, true, false, use_topology);
2798  }
2799 
2800  bool failed_repeat_loop = false;
2801  for (int i = 0; i < repeat; i++) {
2802  if (!EDBM_op_callf(em,
2803  op,
2804  "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f "
2805  "use_x=%b use_y=%b use_z=%b preserve_volume=%b",
2807  lambda_factor,
2808  lambda_border,
2809  usex,
2810  usey,
2811  usez,
2812  preserve_volume)) {
2813  failed_repeat_loop = true;
2814  break;
2815  }
2816  }
2817  if (failed_repeat_loop) {
2818  continue;
2819  }
2820 
2821  /* Apply mirror. */
2822  if (((Mesh *)obedit->data)->symmetry & ME_SYMMETRY_X) {
2825  }
2826 
2827  EDBM_update(obedit->data,
2828  &(const struct EDBMUpdate_Params){
2829  .calc_looptri = true,
2830  .calc_normals = false,
2831  .is_destructive = false,
2832  });
2833  }
2834  MEM_freeN(objects);
2835 
2836  if (tot_unselected == objects_len) {
2837  BKE_report(op->reports, RPT_WARNING, "No selected vertex");
2838  return OPERATOR_CANCELLED;
2839  }
2840 
2841  return OPERATOR_FINISHED;
2842 }
2843 
2845 {
2846  /* identifiers */
2847  ot->name = "Laplacian Smooth Vertices";
2848  ot->description = "Laplacian smooth of selected vertices";
2849  ot->idname = "MESH_OT_vertices_smooth_laplacian";
2850 
2851  /* api callbacks */
2854 
2855  /* flags */
2857 
2858  RNA_def_int(
2859  ot->srna, "repeat", 1, 1, 1000, "Number of iterations to smooth the mesh", "", 1, 200);
2860  RNA_def_float(
2861  ot->srna, "lambda_factor", 1.0f, 1e-7f, 1000.0f, "Lambda factor", "", 1e-7f, 1000.0f);
2863  "lambda_border",
2864  5e-5f,
2865  1e-7f,
2866  1000.0f,
2867  "Lambda factor in border",
2868  "",
2869  1e-7f,
2870  1000.0f);
2871 
2873 
2874  RNA_def_boolean(ot->srna, "use_x", true, "Smooth X Axis", "Smooth object along X axis");
2875  RNA_def_boolean(ot->srna, "use_y", true, "Smooth Y Axis", "Smooth object along Y axis");
2876  RNA_def_boolean(ot->srna, "use_z", true, "Smooth Z Axis", "Smooth object along Z axis");
2878  "preserve_volume",
2879  true,
2880  "Preserve Volume",
2881  "Apply volume preservation after smooth");
2882 }
2883 
2886 /* -------------------------------------------------------------------- */
2890 static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
2891 {
2892  BMIter iter;
2893  BMFace *efa;
2894 
2895  if (em == NULL) {
2896  return;
2897  }
2898 
2899  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2900  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2902  }
2903  }
2904 }
2905 
2907 {
2908  ViewLayer *view_layer = CTX_data_view_layer(C);
2909  uint objects_len = 0;
2911  view_layer, CTX_wm_view3d(C), &objects_len);
2912  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2913  Object *obedit = objects[ob_index];
2914  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2915 
2916  if (em->bm->totfacesel == 0) {
2917  continue;
2918  }
2919 
2920  mesh_set_smooth_faces(em, 1);
2921  EDBM_update(obedit->data,
2922  &(const struct EDBMUpdate_Params){
2923  .calc_looptri = false,
2924  .calc_normals = false,
2925  .is_destructive = false,
2926  });
2927  }
2928  MEM_freeN(objects);
2929 
2930  return OPERATOR_FINISHED;
2931 }
2932 
2934 {
2935  /* identifiers */
2936  ot->name = "Shade Smooth";
2937  ot->description = "Display faces smooth (using vertex normals)";
2938  ot->idname = "MESH_OT_faces_shade_smooth";
2939 
2940  /* api callbacks */
2943 
2944  /* flags */
2946 }
2947 
2950 /* -------------------------------------------------------------------- */
2955 {
2956  ViewLayer *view_layer = CTX_data_view_layer(C);
2957  uint objects_len = 0;
2959  view_layer, CTX_wm_view3d(C), &objects_len);
2960  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2961  Object *obedit = objects[ob_index];
2962  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2963 
2964  if (em->bm->totfacesel == 0) {
2965  continue;
2966  }
2967 
2968  mesh_set_smooth_faces(em, 0);
2969  EDBM_update(obedit->data,
2970  &(const struct EDBMUpdate_Params){
2971  .calc_looptri = false,
2972  .calc_normals = false,
2973  .is_destructive = false,
2974  });
2975  }
2976  MEM_freeN(objects);
2977 
2978  return OPERATOR_FINISHED;
2979 }
2980 
2982 {
2983  /* identifiers */
2984  ot->name = "Shade Flat";
2985  ot->description = "Display faces flat";
2986  ot->idname = "MESH_OT_faces_shade_flat";
2987 
2988  /* api callbacks */
2991 
2992  /* flags */
2994 }
2995 
2998 /* -------------------------------------------------------------------- */
3003 {
3004  /* get the direction from RNA */
3005  const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
3006 
3007  ViewLayer *view_layer = CTX_data_view_layer(C);
3008  uint objects_len = 0;
3010  view_layer, CTX_wm_view3d(C), &objects_len);
3011  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3012  Object *obedit = objects[ob_index];
3013  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3014 
3015  if (em->bm->totfacesel == 0) {
3016  continue;
3017  }
3018 
3019  BMOperator bmop;
3020 
3021  EDBM_op_init(em, &bmop, op, "rotate_uvs faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
3022 
3023  BMO_op_exec(em->bm, &bmop);
3024 
3025  if (!EDBM_op_finish(em, &bmop, op, true)) {
3026  continue;
3027  }
3028 
3029  EDBM_update(obedit->data,
3030  &(const struct EDBMUpdate_Params){
3031  .calc_looptri = false,
3032  .calc_normals = false,
3033  .is_destructive = false,
3034  });
3035  }
3036 
3037  MEM_freeN(objects);
3038  return OPERATOR_FINISHED;
3039 }
3040 
3042 {
3043  ViewLayer *view_layer = CTX_data_view_layer(C);
3044  uint objects_len = 0;
3046  view_layer, CTX_wm_view3d(C), &objects_len);
3047  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3048  Object *obedit = objects[ob_index];
3049  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3050 
3051  if (em->bm->totfacesel == 0) {
3052  continue;
3053  }
3054 
3055  BMOperator bmop;
3056 
3057  EDBM_op_init(em, &bmop, op, "reverse_uvs faces=%hf", BM_ELEM_SELECT);
3058 
3059  BMO_op_exec(em->bm, &bmop);
3060 
3061  if (!EDBM_op_finish(em, &bmop, op, true)) {
3062  continue;
3063  }
3064  EDBM_update(obedit->data,
3065  &(const struct EDBMUpdate_Params){
3066  .calc_looptri = false,
3067  .calc_normals = false,
3068  .is_destructive = false,
3069  });
3070  }
3071 
3072  MEM_freeN(objects);
3073  return OPERATOR_FINISHED;
3074 }
3075 
3077 {
3078  /* get the direction from RNA */
3079  const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
3080 
3081  ViewLayer *view_layer = CTX_data_view_layer(C);
3082  uint objects_len = 0;
3084  view_layer, CTX_wm_view3d(C), &objects_len);
3085 
3086  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3087  Object *ob = objects[ob_index];
3089  if (em->bm->totfacesel == 0) {
3090  continue;
3091  }
3092 
3093  BMOperator bmop;
3094 
3095  const Mesh *me = BKE_object_get_original_mesh(ob);
3097 
3098  if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
3099  continue;
3100  }
3101 
3102  int color_index = BKE_id_attribute_to_index(
3104  EDBM_op_init(em,
3105  &bmop,
3106  op,
3107  "rotate_colors faces=%hf use_ccw=%b color_index=%i",
3109  use_ccw,
3110  color_index);
3111 
3112  BMO_op_exec(em->bm, &bmop);
3113 
3114  if (!EDBM_op_finish(em, &bmop, op, true)) {
3115  continue;
3116  }
3117 
3118  /* dependencies graph and notification stuff */
3119  EDBM_update(ob->data,
3120  &(const struct EDBMUpdate_Params){
3121  .calc_looptri = false,
3122  .calc_normals = false,
3123  .is_destructive = false,
3124  });
3125  }
3126 
3127  MEM_freeN(objects);
3128 
3129  return OPERATOR_FINISHED;
3130 }
3131 
3133 {
3134  ViewLayer *view_layer = CTX_data_view_layer(C);
3135  uint objects_len = 0;
3137  view_layer, CTX_wm_view3d(C), &objects_len);
3138 
3139  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3140  Object *obedit = objects[ob_index];
3141  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3142 
3143  if (em->bm->totfacesel == 0) {
3144  continue;
3145  }
3146 
3147  const Mesh *me = BKE_object_get_original_mesh(obedit);
3149 
3150  if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
3151  continue;
3152  }
3153 
3154  BMOperator bmop;
3155 
3156  int color_index = BKE_id_attribute_to_index(
3158  EDBM_op_init(
3159  em, &bmop, op, "reverse_colors faces=%hf color_index=%i", BM_ELEM_SELECT, color_index);
3160 
3161  BMO_op_exec(em->bm, &bmop);
3162 
3163  if (!EDBM_op_finish(em, &bmop, op, true)) {
3164  continue;
3165  }
3166 
3167  EDBM_update(obedit->data,
3168  &(const struct EDBMUpdate_Params){
3169  .calc_looptri = false,
3170  .calc_normals = false,
3171  .is_destructive = false,
3172  });
3173  }
3174  MEM_freeN(objects);
3175 
3176  return OPERATOR_FINISHED;
3177 }
3178 
3180 {
3181  /* identifiers */
3182  ot->name = "Rotate UVs";
3183  ot->idname = "MESH_OT_uvs_rotate";
3184  ot->description = "Rotate UV coordinates inside faces";
3185 
3186  /* api callbacks */
3189 
3190  /* flags */
3192 
3193  /* props */
3194  RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
3195 }
3196 
3198 {
3199  /* identifiers */
3200  ot->name = "Reverse UVs";
3201  ot->idname = "MESH_OT_uvs_reverse";
3202  ot->description = "Flip direction of UV coordinates inside faces";
3203 
3204  /* api callbacks */
3207 
3208  /* flags */
3210 
3211  /* props */
3212  // RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around");
3213 }
3214 
3216 {
3217  /* identifiers */
3218  ot->name = "Rotate Colors";
3219  ot->idname = "MESH_OT_colors_rotate";
3220  ot->description = "Rotate color attributes inside faces";
3221 
3222  /* api callbacks */
3225 
3226  /* flags */
3228 
3229  /* props */
3230  RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
3231 }
3232 
3234 {
3235  /* identifiers */
3236  ot->name = "Reverse Colors";
3237  ot->idname = "MESH_OT_colors_reverse";
3238  ot->description = "Flip direction of vertex colors inside faces";
3239 
3240  /* api callbacks */
3243 
3244  /* flags */
3246 
3247  /* props */
3248 #if 0
3249  RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around");
3250 #endif
3251 }
3252 
3255 /* -------------------------------------------------------------------- */
3259 enum {
3265 };
3266 
3267 static bool merge_firstlast(BMEditMesh *em,
3268  const bool use_first,
3269  const bool use_uvmerge,
3270  wmOperator *wmop)
3271 {
3272  BMVert *mergevert;
3273  BMEditSelection *ese;
3274 
3275  /* operator could be called directly from shortcut or python,
3276  * so do extra check for data here
3277  */
3278 
3279  /* While #merge_type_itemf does a sanity check, this operation runs on all edit-mode objects.
3280  * Some of them may not have the expected selection state. */
3281  if (use_first == false) {
3282  if (!em->bm->selected.last || ((BMEditSelection *)em->bm->selected.last)->htype != BM_VERT) {
3283  return false;
3284  }
3285 
3286  ese = em->bm->selected.last;
3287  mergevert = (BMVert *)ese->ele;
3288  }
3289  else {
3290  if (!em->bm->selected.first || ((BMEditSelection *)em->bm->selected.first)->htype != BM_VERT) {
3291  return false;
3292  }
3293 
3294  ese = em->bm->selected.first;
3295  mergevert = (BMVert *)ese->ele;
3296  }
3297 
3298  if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT)) {
3299  return false;
3300  }
3301 
3302  if (use_uvmerge) {
3303  if (!EDBM_op_callf(
3304  em, wmop, "pointmerge_facedata verts=%hv vert_snap=%e", BM_ELEM_SELECT, mergevert)) {
3305  return false;
3306  }
3307  }
3308 
3309  if (!EDBM_op_callf(
3310  em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, mergevert->co)) {
3311  return false;
3312  }
3313 
3314  return true;
3315 }
3316 
3317 static bool merge_target(BMEditMesh *em,
3318  Scene *scene,
3319  Object *ob,
3320  const bool use_cursor,
3321  const bool use_uvmerge,
3322  wmOperator *wmop)
3323 {
3324  BMIter iter;
3325  BMVert *v;
3326  float co[3], cent[3] = {0.0f, 0.0f, 0.0f};
3327  const float *vco = NULL;
3328 
3329  if (use_cursor) {
3330  vco = scene->cursor.location;
3331  copy_v3_v3(co, vco);
3332  invert_m4_m4(ob->imat, ob->obmat);
3333  mul_m4_v3(ob->imat, co);
3334  }
3335  else {
3336  float fac;
3337  int i = 0;
3338  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
3340  continue;
3341  }
3342  add_v3_v3(cent, v->co);
3343  i++;
3344  }
3345 
3346  if (!i) {
3347  return false;
3348  }
3349 
3350  fac = 1.0f / (float)i;
3351  mul_v3_fl(cent, fac);
3352  copy_v3_v3(co, cent);
3353  vco = co;
3354  }
3355 
3356  if (!vco) {
3357  return false;
3358  }
3359 
3360  if (use_uvmerge) {
3361  if (!EDBM_op_callf(em, wmop, "average_vert_facedata verts=%hv", BM_ELEM_SELECT)) {
3362  return false;
3363  }
3364  }
3365 
3366  if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv merge_co=%v", BM_ELEM_SELECT, co)) {
3367  return false;
3368  }
3369 
3370  return true;
3371 }
3372 
3374 {
3376  ViewLayer *view_layer = CTX_data_view_layer(C);
3377  uint objects_len = 0;
3379  view_layer, CTX_wm_view3d(C), &objects_len);
3380  const int type = RNA_enum_get(op->ptr, "type");
3381  const bool uvs = RNA_boolean_get(op->ptr, "uvs");
3382 
3383  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3384  Object *obedit = objects[ob_index];
3385  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3386 
3387  if (em->bm->totvertsel == 0) {
3388  continue;
3389  }
3390 
3392 
3393  bool ok = false;
3394  switch (type) {
3395  case MESH_MERGE_CENTER:
3396  ok = merge_target(em, scene, obedit, false, uvs, op);
3397  break;
3398  case MESH_MERGE_CURSOR:
3399  ok = merge_target(em, scene, obedit, true, uvs, op);
3400  break;
3401  case MESH_MERGE_LAST:
3402  ok = merge_firstlast(em, false, uvs, op);
3403  break;
3404  case MESH_MERGE_FIRST:
3405  ok = merge_firstlast(em, true, uvs, op);
3406  break;
3407  case MESH_MERGE_COLLAPSE:
3408  ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs);
3409  break;
3410  default:
3411  BLI_assert(0);
3412  break;
3413  }
3414 
3415  if (!ok) {
3416  continue;
3417  }
3418 
3420 
3421  EDBM_update(obedit->data,
3422  &(const struct EDBMUpdate_Params){
3423  .calc_looptri = true,
3424  .calc_normals = false,
3425  .is_destructive = true,
3426  });
3427 
3428  /* once collapsed, we can't have edge/face selection */
3429  if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
3431  }
3432  /* Only active object supported, see comment below. */
3434  break;
3435  }
3436  }
3437 
3438  MEM_freeN(objects);
3439 
3440  return OPERATOR_FINISHED;
3441 }
3442 
3444  {MESH_MERGE_CENTER, "CENTER", 0, "At Center", ""},
3445  {MESH_MERGE_CURSOR, "CURSOR", 0, "At Cursor", ""},
3446  {MESH_MERGE_COLLAPSE, "COLLAPSE", 0, "Collapse", ""},
3447  {MESH_MERGE_FIRST, "FIRST", 0, "At First", ""},
3448  {MESH_MERGE_LAST, "LAST", 0, "At Last", ""},
3449  {0, NULL, 0, NULL, NULL},
3450 };
3451 
3453  PointerRNA *UNUSED(ptr),
3454  PropertyRNA *UNUSED(prop),
3455  bool *r_free)
3456 {
3457  if (!C) { /* needed for docs */
3458  return merge_type_items;
3459  }
3460 
3461  Object *obedit = CTX_data_edit_object(C);
3462  if (obedit && obedit->type == OB_MESH) {
3463  EnumPropertyItem *item = NULL;
3464  int totitem = 0;
3465  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3466 
3467  /* Keep these first so that their automatic shortcuts don't change. */
3471 
3472  /* Only active object supported:
3473  * In practice it doesn't make sense to run this operation on non-active meshes
3474  * since selecting will activate - we could have own code-path for these but it's a hassle
3475  * for now just apply to the active (first) object. */
3476  if (em->selectmode & SCE_SELECT_VERTEX) {
3477  if (em->bm->selected.first && em->bm->selected.last &&
3478  ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT &&
3479  ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
3482  }
3483  else if (em->bm->selected.first &&
3484  ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) {
3486  }
3487  else if (em->bm->selected.last &&
3488  ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
3490  }
3491  }
3492 
3493  RNA_enum_item_end(&item, &totitem);
3494 
3495  *r_free = true;
3496 
3497  return item;
3498  }
3499 
3500  /* Get all items e.g. when creating keymap item. */
3501  return merge_type_items;
3502 }
3503 
3505 {
3506  /* identifiers */
3507  ot->name = "Merge";
3508  ot->description = "Merge selected vertices";
3509  ot->idname = "MESH_OT_merge";
3510 
3511  /* api callbacks */
3512  ot->exec = edbm_merge_exec;
3515 
3516  /* flags */
3518 
3519  /* properties */
3520  ot->prop = RNA_def_enum(
3521  ot->srna, "type", merge_type_items, MESH_MERGE_CENTER, "Type", "Merge method to use");
3523 
3525 
3526  RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge");
3527 }
3528 
3531 /* -------------------------------------------------------------------- */
3536 {
3537  const float threshold = RNA_float_get(op->ptr, "threshold");
3538  const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected");
3539  const bool use_sharp_edge_from_normals = RNA_boolean_get(op->ptr, "use_sharp_edge_from_normals");
3540 
3541  int count_multi = 0;
3542 
3543  ViewLayer *view_layer = CTX_data_view_layer(C);
3544  uint objects_len = 0;
3546  view_layer, CTX_wm_view3d(C), &objects_len);
3547 
3548  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3549  Object *obedit = objects[ob_index];
3550  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3551 
3552  /* Selection used as target with 'use_unselected'. */
3553  if (em->bm->totvertsel == 0) {
3554  continue;
3555  }
3556 
3557  BMOperator bmop;
3558  const int totvert_orig = em->bm->totvert;
3559 
3560  /* avoid losing selection state (select -> tags) */
3561  char htype_select;
3562  if (em->selectmode & SCE_SELECT_VERTEX) {
3563  htype_select = BM_VERT;
3564  }
3565  else if (em->selectmode & SCE_SELECT_EDGE) {
3566  htype_select = BM_EDGE;
3567  }
3568  else {
3569  htype_select = BM_FACE;
3570  }
3571 
3573 
3574  /* store selection as tags */
3575  BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT);
3576 
3577  if (use_unselected) {
3578  EDBM_automerge(obedit, false, BM_ELEM_SELECT, threshold);
3579  }
3580  else {
3581  EDBM_op_init(em, &bmop, op, "find_doubles verts=%hv dist=%f", BM_ELEM_SELECT, threshold);
3582 
3583  BMO_op_exec(em->bm, &bmop);
3584 
3585  if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) {
3586  BMO_op_finish(em->bm, &bmop);
3587  continue;
3588  }
3589 
3590  if (!EDBM_op_finish(em, &bmop, op, true)) {
3591  continue;
3592  }
3593  }
3594 
3595  const int count = (totvert_orig - em->bm->totvert);
3596 
3597  /* restore selection from tags */
3598  BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_SELECT, true, true, BM_ELEM_TAG);
3600 
3601  BM_custom_loop_normals_from_vector_layer(em->bm, use_sharp_edge_from_normals);
3602 
3603  if (count) {
3604  count_multi += count;
3605  EDBM_update(obedit->data,
3606  &(const struct EDBMUpdate_Params){
3607  .calc_looptri = true,
3608  .calc_normals = false,
3609  .is_destructive = true,
3610  });
3611  }
3612  }
3613  MEM_freeN(objects);
3614 
3615  BKE_reportf(op->reports, RPT_INFO, "Removed %d vertice(s)", count_multi);
3616 
3617  return OPERATOR_FINISHED;
3618 }
3619 
3621 {
3622  /* identifiers */
3623  ot->name = "Merge by Distance";
3624  ot->description = "Merge vertices based on their proximity";
3625  ot->idname = "MESH_OT_remove_doubles";
3626 
3627  /* api callbacks */
3630 
3631  /* flags */
3633 
3635  "threshold",
3636  1e-4f,
3637  1e-6f,
3638  50.0f,
3639  "Merge Distance",
3640  "Maximum distance between elements to merge",
3641  1e-5f,
3642  10.0f);
3644  "use_unselected",
3645  false,
3646  "Unselected",
3647  "Merge selected to other unselected vertices");
3648 
3650  "use_sharp_edge_from_normals",
3651  false,
3652  "Sharp Edges",
3653  "Calculate sharp edges using custom normal data (when available)");
3654 }
3655 
3658 /* -------------------------------------------------------------------- */
3662 /* BMESH_TODO this should be properly encapsulated in a bmop. but later. */
3663 static bool shape_propagate(BMEditMesh *em)
3664 {
3665  BMIter iter;
3666  BMVert *eve = NULL;
3667  float *co;
3668  int totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
3669 
3670  if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
3671  return false;
3672  }
3673 
3674  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
3676  continue;
3677  }
3678 
3679  for (int i = 0; i < totshape; i++) {
3680  co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
3681  copy_v3_v3(co, eve->co);
3682  }
3683  }
3684  return true;
3685 }
3686 
3688 {
3689  ViewLayer *view_layer = CTX_data_view_layer(C);
3690  int tot_shapekeys = 0;
3691  int tot_selected_verts_objects = 0;
3692 
3693  uint objects_len = 0;
3695  view_layer, CTX_wm_view3d(C), &objects_len);
3696  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3697  Object *obedit = objects[ob_index];
3698  Mesh *me = obedit->data;
3699  BMEditMesh *em = me->edit_mesh;
3700 
3701  if (em->bm->totvertsel == 0) {
3702  continue;
3703  }
3704  tot_selected_verts_objects++;
3705 
3706  if (shape_propagate(em)) {
3707  tot_shapekeys++;
3708  }
3709 
3710  EDBM_update(me,
3711  &(const struct EDBMUpdate_Params){
3712  .calc_looptri = false,
3713  .calc_normals = false,
3714  .is_destructive = false,
3715  });
3716  }
3717  MEM_freeN(objects);
3718 
3719  if (tot_selected_verts_objects == 0) {
3720  BKE_report(op->reports, RPT_ERROR, "No selected vertex");
3721  return OPERATOR_CANCELLED;
3722  }
3723  if (tot_shapekeys == 0) {
3724  BKE_report(op->reports, RPT_ERROR, "Mesh(es) do not have shape keys");
3725  return OPERATOR_CANCELLED;
3726  }
3727 
3728  return OPERATOR_FINISHED;
3729 }
3730 
3732 {
3733  /* identifiers */
3734  ot->name = "Shape Propagate";
3735  ot->description = "Apply selected vertex locations to all other shape keys";
3736  ot->idname = "MESH_OT_shape_propagate_to_all";
3737 
3738  /* api callbacks */
3741 
3742  /* flags */
3744 }
3745 
3748 /* -------------------------------------------------------------------- */
3752 /* BMESH_TODO this should be properly encapsulated in a bmop. but later. */
3754 {
3755  Object *obedit_ref = CTX_data_edit_object(C);
3756  Mesh *me_ref = obedit_ref->data;
3757  Key *key_ref = me_ref->key;
3758  KeyBlock *kb_ref = NULL;
3759  BMEditMesh *em_ref = me_ref->edit_mesh;
3760  BMVert *eve;
3761  BMIter iter;
3762  ViewLayer *view_layer = CTX_data_view_layer(C);
3763  float co[3], *sco;
3764  int totshape_ref = 0;
3765 
3766  const float blend = RNA_float_get(op->ptr, "blend");
3767  int shape_ref = RNA_enum_get(op->ptr, "shape");
3768  const bool use_add = RNA_boolean_get(op->ptr, "add");
3769 
3770  /* Sanity check. */
3771  totshape_ref = CustomData_number_of_layers(&em_ref->bm->vdata, CD_SHAPEKEY);
3772 
3773  if (totshape_ref == 0 || shape_ref < 0) {
3774  BKE_report(op->reports, RPT_ERROR, "Active mesh does not have shape keys");
3775  return OPERATOR_CANCELLED;
3776  }
3777  if (shape_ref >= totshape_ref) {
3778  /* This case occurs if operator was used before on object with more keys than current one. */
3779  shape_ref = 0; /* default to basis */
3780  }
3781 
3782  /* Get shape key - needed for finding reference shape (for add mode only). */
3783  if (key_ref) {
3784  kb_ref = BLI_findlink(&key_ref->block, shape_ref);
3785  }
3786 
3787  int tot_selected_verts_objects = 0;
3788  uint objects_len = 0;
3790  view_layer, CTX_wm_view3d(C), &objects_len);
3791  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3792  Object *obedit = objects[ob_index];
3793  Mesh *me = obedit->data;
3794  Key *key = me->key;
3795  KeyBlock *kb = NULL;
3796  BMEditMesh *em = me->edit_mesh;
3797  int shape;
3798 
3799  if (em->bm->totvertsel == 0) {
3800  continue;
3801  }
3802  tot_selected_verts_objects++;
3803 
3804  if (!key) {
3805  continue;
3806  }
3807  kb = BKE_keyblock_find_name(key, kb_ref->name);
3808  shape = BLI_findindex(&key->block, kb);
3809 
3810  if (kb) {
3811  /* Perform blending on selected vertices. */
3812  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
3814  continue;
3815  }
3816 
3817  /* Get coordinates of shapekey we're blending from. */
3818  sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
3819  copy_v3_v3(co, sco);
3820 
3821  if (use_add) {
3822  /* In add mode, we add relative shape key offset. */
3823  const float *rco = CustomData_bmesh_get_n(
3824  &em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative);
3825  sub_v3_v3v3(co, co, rco);
3826 
3827  madd_v3_v3fl(eve->co, co, blend);
3828  }
3829  else {
3830  /* In blend mode, we interpolate to the shape key. */
3831  interp_v3_v3v3(eve->co, eve->co, co, blend);
3832  }
3833  }
3834  EDBM_update(me,
3835  &(const struct EDBMUpdate_Params){
3836  .calc_looptri = true,
3837  .calc_normals = true,
3838  .is_destructive = false,
3839  });
3840  }
3841  }
3842  MEM_freeN(objects);
3843 
3844  if (tot_selected_verts_objects == 0) {
3845  BKE_report(op->reports, RPT_ERROR, "No selected vertex");
3846  return OPERATOR_CANCELLED;
3847  }
3848 
3849  return OPERATOR_FINISHED;
3850 }
3851 
3853  PointerRNA *UNUSED(ptr),
3854  PropertyRNA *UNUSED(prop),
3855  bool *r_free)
3856 {
3857  Object *obedit = CTX_data_edit_object(C);
3858  BMEditMesh *em;
3859  EnumPropertyItem *item = NULL;
3860  int totitem = 0;
3861 
3862  if ((obedit && obedit->type == OB_MESH) && (em = BKE_editmesh_from_object(obedit)) &&
3864  EnumPropertyItem tmp = {0, "", 0, "", ""};
3865  int a;
3866 
3867  for (a = 0; a < em->bm->vdata.totlayer; a++) {
3868  if (em->bm->vdata.layers[a].type != CD_SHAPEKEY) {
3869  continue;
3870  }
3871 
3872  tmp.value = totitem;
3873  tmp.identifier = em->bm->vdata.layers[a].name;
3874  tmp.name = em->bm->vdata.layers[a].name;
3875  /* RNA_enum_item_add sets totitem itself! */
3876  RNA_enum_item_add(&item, &totitem, &tmp);
3877  }
3878  }
3879 
3880  RNA_enum_item_end(&item, &totitem);
3881  *r_free = true;
3882 
3883  return item;
3884 }
3885 
3887 {
3888  uiLayout *layout = op->layout;
3889  Object *obedit = CTX_data_edit_object(C);
3890  Mesh *me = obedit->data;
3891  PointerRNA ptr_key;
3892 
3893  RNA_id_pointer_create((ID *)me->key, &ptr_key);
3894 
3895  uiLayoutSetPropSep(layout, true);
3896  uiLayoutSetPropDecorate(layout, false);
3897 
3898  uiItemPointerR(layout, op->ptr, "shape", &ptr_key, "key_blocks", NULL, ICON_SHAPEKEY_DATA);
3899  uiItemR(layout, op->ptr, "blend", 0, NULL, ICON_NONE);
3900  uiItemR(layout, op->ptr, "add", 0, NULL, ICON_NONE);
3901 }
3902 
3904 {
3905  PropertyRNA *prop;
3906 
3907  /* identifiers */
3908  ot->name = "Blend from Shape";
3909  ot->description = "Blend in shape from a shape key";
3910  ot->idname = "MESH_OT_blend_from_shape";
3911 
3912  /* api callbacks */
3914  /* disable because search popup closes too easily */
3915  // ot->invoke = WM_operator_props_popup_call;
3918 
3919  /* flags */
3921 
3922  /* properties */
3923  prop = RNA_def_enum(
3924  ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending");
3927  RNA_def_float(ot->srna, "blend", 1.0f, -1e3f, 1e3f, "Blend", "Blending factor", -2.0f, 2.0f);
3928  RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes");
3929 }
3930 
3933 /* -------------------------------------------------------------------- */
3938 {
3939  const float thickness = RNA_float_get(op->ptr, "thickness");
3940 
3941  ViewLayer *view_layer = CTX_data_view_layer(C);
3942  uint objects_len = 0;
3944  view_layer, CTX_wm_view3d(C), &objects_len);
3945  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3946  Object *obedit = objects[ob_index];
3947  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3948  BMesh *bm = em->bm;
3949 
3950  if (em->bm->totfacesel == 0) {
3951  continue;
3952  }
3953 
3954  BMOperator bmop;
3955 
3956  if (!EDBM_op_init(
3957  em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) {
3958  continue;
3959  }
3960 
3961  /* deselect only the faces in the region to be solidified (leave wire
3962  * edges and loose verts selected, as there will be no corresponding
3963  * geometry selected below) */
3965 
3966  /* run the solidify operator */
3967  BMO_op_exec(bm, &bmop);
3968 
3969  /* select the newly generated faces */
3970  BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
3971 
3972  if (!EDBM_op_finish(em, &bmop, op, true)) {
3973  continue;
3974  }
3975 
3976  EDBM_update(obedit->data,
3977  &(const struct EDBMUpdate_Params){
3978  .calc_looptri = true,
3979  .calc_normals = false,
3980  .is_destructive = true,
3981  });
3982  }
3983 
3984  MEM_freeN(objects);
3985  return OPERATOR_FINISHED;
3986 }
3987 
3989 {
3990  PropertyRNA *prop;
3991  /* identifiers */
3992  ot->name = "Solidify";
3993  ot->description = "Create a solid skin by extruding, compensating for sharp angles";
3994  ot->idname = "MESH_OT_solidify";
3995 
3996  /* api callbacks */
3999 
4000  /* flags */
4002 
4003  prop = RNA_def_float_distance(
4004  ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f);
4005  RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4);
4006 }
4007 
4010 /* -------------------------------------------------------------------- */
4014 #define KNIFE_EXACT 1
4015 #define KNIFE_MIDPOINT 2
4016 #define KNIFE_MULTICUT 3
4017 
4018 static const EnumPropertyItem knife_items[] = {
4019  {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
4020  {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
4021  {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
4022  {0, NULL, 0, NULL, NULL},
4023 };
4024 
4025 /* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */
4026 
4027 static float bm_edge_seg_isect(const float sco_a[2],
4028  const float sco_b[2],
4029  float (*mouse_path)[2],
4030  int len,
4031  char mode,
4032  int *isected)
4033 {
4034 #define MAXSLOPE 100000
4035  float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max;
4036  float y2min, dist, lastdist = 0, xdiff2, xdiff1;
4037  float m1, b1, m2, b2, x21, x22, y21, y22, xi;
4038  float yi, x1min, x1max, y1max, y1min, perc = 0;
4039  float threshold = 0.0;
4040  int i;
4041 
4042  // threshold = 0.000001; /* tolerance for vertex intersection */
4043  // XXX threshold = scene->toolsettings->select_thresh / 100;
4044 
4045  /* Get screen coords of verts */
4046  x21 = sco_a[0];
4047  y21 = sco_a[1];
4048 
4049  x22 = sco_b[0];
4050  y22 = sco_b[1];
4051 
4052  xdiff2 = (x22 - x21);
4053  if (xdiff2) {
4054  m2 = (y22 - y21) / xdiff2;
4055  b2 = ((x22 * y21) - (x21 * y22)) / xdiff2;
4056  }
4057  else {
4058  m2 = MAXSLOPE; /* Vertical slope. */
4059  b2 = x22;
4060  }
4061 
4062  *isected = 0;
4063 
4064  /* check for _exact_ vertex intersection first */
4065  if (mode != KNIFE_MULTICUT) {
4066  for (i = 0; i < len; i++) {
4067  if (i > 0) {
4068  x11 = x12;
4069  y11 = y12;
4070  }
4071  else {
4072  x11 = mouse_path[i][0];
4073  y11 = mouse_path[i][1];
4074  }
4075  x12 = mouse_path[i][0];
4076  y12 = mouse_path[i][1];
4077 
4078  /* test e->v1 */
4079  if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) {
4080  perc = 0;
4081  *isected = 1;
4082  return perc;
4083  }
4084  /* test e->v2 */
4085  if ((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)) {
4086  perc = 0;
4087  *isected = 2;
4088  return perc;
4089  }
4090  }
4091  }
4092 
4093  /* now check for edge intersect (may produce vertex intersection as well) */
4094  for (i = 0; i < len; i++) {
4095  if (i > 0) {
4096  x11 = x12;
4097  y11 = y12;
4098  }
4099  else {
4100  x11 = mouse_path[i][0];
4101  y11 = mouse_path[i][1];
4102  }
4103  x12 = mouse_path[i][0];
4104  y12 = mouse_path[i][1];
4105 
4106  /* Calculate the distance from point to line. */
4107  if (m2 != MAXSLOPE) {
4108  /* `sqrt(m2 * m2 + 1);` Only looking for change in sign. Skip extra math. */
4109  dist = (y12 - m2 * x12 - b2);
4110  }
4111  else {
4112  dist = x22 - x12;
4113  }
4114 
4115  if (i == 0) {
4116  lastdist = dist;
4117  }
4118 
4119  /* if dist changes sign, and intersect point in edge's Bound Box */
4120  if ((lastdist * dist) <= 0) {
4121  xdiff1 = (x12 - x11); /* Equation of line between last 2 points */
4122  if (xdiff1) {
4123  m1 = (y12 - y11) / xdiff1;
4124  b1 = ((x12 * y11) - (x11 * y12)) / xdiff1;
4125  }
4126  else {
4127  m1 = MAXSLOPE;
4128  b1 = x12;
4129  }
4130  x2max = max_ff(x21, x22) + 0.001f; /* Prevent missed edges. */
4131  x2min = min_ff(x21, x22) - 0.001f; /* Due to round off error. */
4132  y2max = max_ff(y21, y22) + 0.001f;
4133  y2min = min_ff(y21, y22) - 0.001f;
4134 
4135  /* Found an intersect, calc intersect point */
4136  if (m1 == m2) { /* co-incident lines */
4137  /* cut at 50% of overlap area */
4138  x1max = max_ff(x11, x12);
4139  x1min = min_ff(x11, x12);
4140  xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f;
4141 
4142  y1max = max_ff(y11, y12);
4143  y1min = min_ff(y11, y12);
4144  yi = (min_ff(y2max, y1max) + max_ff(y2min, y1min)) / 2.0f;
4145  }
4146  else if (m2 == MAXSLOPE) {
4147  xi = x22;
4148  yi = m1 * x22 + b1;
4149  }
4150  else if (m1 == MAXSLOPE) {
4151  xi = x12;
4152  yi = m2 * x12 + b2;
4153  }
4154  else {
4155  xi = (b1 - b2) / (m2 - m1);
4156  yi = (b1 * m2 - m1 * b2) / (m2 - m1);
4157  }
4158 
4159  /* Intersect inside bounding box of edge? */
4160  if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) {
4161  /* Test for vertex intersect that may be 'close enough'. */
4162  if (mode != KNIFE_MULTICUT) {
4163  if (xi <= (x21 + threshold) && xi >= (x21 - threshold)) {
4164  if (yi <= (y21 + threshold) && yi >= (y21 - threshold)) {
4165  *isected = 1;
4166  perc = 0;
4167  break;
4168  }
4169  }
4170  if (xi <= (x22 + threshold) && xi >= (x22 - threshold)) {
4171  if (yi <= (y22 + threshold) && yi >= (y22 - threshold)) {
4172  *isected = 2;
4173  perc = 0;
4174  break;
4175  }
4176  }
4177  }
4178  if ((m2 <= 1.0f) && (m2 >= -1.0f)) {
4179  perc = (xi - x21) / (x22 - x21);
4180  }
4181  else {
4182  perc = (yi - y21) / (y22 - y21); /* lower slope more accurate */
4183  }
4184  // isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */
4185 
4186  break;
4187  }
4188  }
4189  lastdist = dist;
4190  }
4191  return perc;
4192 }
4193 
4194 #define ELE_EDGE_CUT 1
4195 
4197 {
4198  Object *obedit = CTX_data_edit_object(C);
4199  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4200  BMesh *bm = em->bm;
4201  ARegion *region = CTX_wm_region(C);
4202  BMVert *bv;
4203  BMIter iter;
4204  BMEdge *be;
4205  BMOperator bmop;
4206  float isect = 0.0f;
4207  int isected, i;
4208  short numcuts = 1;
4209  const short mode = RNA_int_get(op->ptr, "type");
4210 
4211  /* Allocated variables. */
4212  float(*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2];
4213 
4214  /* edit-object needed for matrix, and region->regiondata for projections to work */
4215  if (ELEM(NULL, obedit, region, region->regiondata)) {
4216  return OPERATOR_CANCELLED;
4217  }
4218 
4219  if (bm->totvertsel < 2) {
4220  BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on");
4221  return OPERATOR_CANCELLED;
4222  }
4223 
4224  const int len = RNA_collection_length(op->ptr, "path");
4225 
4226  if (len < 2) {
4227  BKE_report(op->reports, RPT_ERROR, "Mouse path too short");
4228  return OPERATOR_CANCELLED;
4229  }
4230 
4231  mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__);
4232 
4233  /* get the cut curve */
4234  RNA_BEGIN (op->ptr, itemptr, "path") {
4235  RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]);
4236  }
4237  RNA_END;
4238 
4239  /* for ED_view3d_project_float_object */
4240  ED_view3d_init_mats_rv3d(obedit, region->regiondata);
4241 
4242  /* TODO: investigate using index lookup for #screen_vert_coords() rather than a hash table. */
4243 
4244  /* the floating point coordinates of verts in screen space will be
4245  * stored in a hash table according to the vertices pointer */
4246  screen_vert_coords = sco = MEM_mallocN(sizeof(float[2]) * bm->totvert, __func__);
4247 
4248  BM_ITER_MESH_INDEX (bv, &iter, bm, BM_VERTS_OF_MESH, i) {
4249  if (ED_view3d_project_float_object(region, bv->co, *sco, V3D_PROJ_TEST_CLIP_NEAR) !=
4250  V3D_PROJ_RET_OK) {
4251  copy_v2_fl(*sco, FLT_MAX); /* set error value */
4252  }
4253  BM_elem_index_set(bv, i); /* set_inline */
4254  sco++;
4255  }
4256  bm->elem_index_dirty &= ~BM_VERT; /* clear dirty flag */
4257 
4258  if (!EDBM_op_init(em, &bmop, op, "subdivide_edges")) {
4259  MEM_freeN(mouse_path);
4260  MEM_freeN(screen_vert_coords);
4261  return OPERATOR_CANCELLED;
4262  }
4263 
4264  /* Store percentage of edge cut for KNIFE_EXACT here. */
4265  BMOpSlot *slot_edge_percents = BMO_slot_get(bmop.slots_in, "edge_percents");
4266  BM_ITER_MESH (be, &iter, bm, BM_EDGES_OF_MESH) {
4267  bool is_cut = false;
4268  if (BM_elem_flag_test(be, BM_ELEM_SELECT)) {
4269  const float *sco_a = screen_vert_coords[BM_elem_index_get(be->v1)];
4270  const float *sco_b = screen_vert_coords[BM_elem_index_get(be->v2)];
4271 
4272  /* check for error value (vert can't be projected) */
4273  if ((sco_a[0] != FLT_MAX) && (sco_b[0] != FLT_MAX)) {
4274  isect = bm_edge_seg_isect(sco_a, sco_b, mouse_path, len, mode, &isected);
4275 
4276  if (isect != 0.0f) {
4277  if (!ELEM(mode, KNIFE_MULTICUT, KNIFE_MIDPOINT)) {
4278  BMO_slot_map_float_insert(&bmop, slot_edge_percents, be, isect);
4279  }
4280  }
4281  }
4282  }
4283 
4284  BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
4285  }
4286 
4287  /* free all allocs */
4288  MEM_freeN(screen_vert_coords);
4289  MEM_freeN(mouse_path);
4290 
4292 
4294 
4295  if (mode == KNIFE_MIDPOINT) {
4296  numcuts = 1;
4297  }
4298  BMO_slot_int_set(bmop.slots_in, "cuts", numcuts);
4299 
4300  BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_CORNER_STRAIGHT_CUT);
4301  BMO_slot_bool_set(bmop.slots_in, "use_single_edge", false);
4302  BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false);
4303 
4304  BMO_slot_float_set(bmop.slots_in, "radius", 0);
4305 
4306  BMO_op_exec(bm, &bmop);
4307  if (!EDBM_op_finish(em, &bmop, op, true)) {
4308  return OPERATOR_CANCELLED;
4309  }
4310 
4312 
4313  EDBM_update(obedit->data,
4314  &(const struct EDBMUpdate_Params){
4315  .calc_looptri = true,
4316  .calc_normals = false,
4317  .is_destructive = true,
4318  });
4319 
4320  return OPERATOR_FINISHED;
4321 }
4322 
4323 #undef ELE_EDGE_CUT
4324 
4326 {
4327  ot->name = "Knife Cut";
4328  ot->description = "Cut selected edges and faces into parts";
4329  ot->idname = "MESH_OT_knife_cut";
4330 
4334 
4336 
4337  /* flags */
4339 
4340  /* properties */
4341  PropertyRNA *prop;
4342  prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
4344 
4345  RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
4346 
4347  /* internal */
4348  RNA_def_int(
4349  ot->srna, "cursor", WM_CURSOR_KNIFE, 0, WM_CURSOR_NUM, "Cursor", "", 0, WM_CURSOR_NUM);
4350 }
4351 
4354 /* -------------------------------------------------------------------- */
4358 enum {
4362 };
4363 
4366  Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
4367 {
4368  Object *obedit = base_old->object;
4370  &((struct BMeshCreateParams){
4371  .use_toolflags = true,
4372  }));
4373  BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */
4374 
4376 
4377  /* Take into account user preferences for duplicating actions. */
4378  const eDupli_ID_Flags dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT);
4379  Base *base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, dupflag);
4380 
4381  /* normally would call directly after but in this case delay recalc */
4382  // DAG_relations_tag_update(bmain);
4383 
4384  /* new in 2.5 */
4386  base_new->object,
4388  *BKE_object_material_len_p(obedit),
4389  false);
4390 
4391  ED_object_base_select(base_new, BA_SELECT);
4392 
4393  BMO_op_callf(bm_old,
4395  "duplicate geom=%hvef dest=%p",
4396  BM_ELEM_TAG,
4397  bm_new);
4398  BMO_op_callf(bm_old,
4400  "delete geom=%hvef context=%i",
4401  BM_ELEM_TAG,
4402  DEL_FACES);
4403 
4404  /* deselect loose data - this used to get deleted,
4405  * we could de-select edges and verts only, but this turns out to be less complicated
4406  * since de-selecting all skips selection flushing logic */
4408 
4409  BM_mesh_normals_update(bm_new);
4410 
4411  BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
4412 
4413  BM_mesh_free(bm_new);
4414  ((Mesh *)base_new->object->data)->edit_mesh = NULL;
4415 
4416  return base_new;
4417 }
4418 
4420  Scene *scene,
4421  ViewLayer *view_layer,
4422  Base *base_old,
4423  BMesh *bm_old,
4424  BMVert **verts,
4425  uint verts_len,
4426  BMEdge **edges,
4427  uint edges_len,
4428  BMFace **faces,
4429  uint faces_len)
4430 {
4431  const BMAllocTemplate bm_new_allocsize = {
4432  .totvert = verts_len,
4433  .totedge = edges_len,
4434  .totloop = faces_len * 3,
4435  .totface = faces_len,
4436  };
4437  const bool use_custom_normals = (bm_old->lnor_spacearr != NULL);
4438 
4439  Object *obedit = base_old->object;
4440 
4441  BMesh *bm_new = BM_mesh_create(&bm_new_allocsize, &((struct BMeshCreateParams){0}));
4442 
4443  if (use_custom_normals) {
4444  /* Needed so the temporary normal layer is copied too. */
4445  BM_mesh_copy_init_customdata_all_layers(bm_new, bm_old, BM_ALL, &bm_new_allocsize);
4446  }
4447  else {
4448  BM_mesh_copy_init_customdata(bm_new, bm_old, &bm_new_allocsize);
4449  }
4450 
4451  /* Take into account user preferences for duplicating actions. */
4452  const eDupli_ID_Flags dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT);
4453  Base *base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, dupflag);
4454 
4455  /* normally would call directly after but in this case delay recalc */
4456  // DAG_relations_tag_update(bmain);
4457 
4458  /* new in 2.5 */
4460  base_new->object,
4462  *BKE_object_material_len_p(obedit),
4463  false);
4464 
4465  ED_object_base_select(base_new, BA_SELECT);
4466 
4467  BM_mesh_copy_arrays(bm_old, bm_new, verts, verts_len, edges, edges_len, faces, faces_len);
4468 
4469  if (use_custom_normals) {
4471  }
4472 
4473  for (uint i = 0; i < verts_len; i++) {
4474  BM_vert_kill(bm_old, verts[i]);
4475  }
4476 
4477  BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
4478 
4479  BM_mesh_free(bm_new);
4480  ((Mesh *)base_new->object->data)->edit_mesh = NULL;
4481 
4482  return base_new;
4483 }
4484 
4486  Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
4487 {
4488  /* we may have tags from previous operators */
4490 
4491  /* sel -> tag */
4493  bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, false, BM_ELEM_SELECT);
4494 
4495  return (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL);
4496 }
4497 
4504 static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const short mat_nr)
4505 {
4506  ID *obdata = ob->data;
4507 
4508  const short *totcolp = BKE_id_material_len_p(obdata);
4509  Material ***matarar = BKE_id_material_array_p(obdata);
4510 
4511  if ((totcolp && matarar) == 0) {
4512  BLI_assert(0);
4513  return;
4514  }
4515 
4516  if (*totcolp) {
4517  Material *ma_ob;
4518  Material *ma_obdata;
4519  char matbit;
4520 
4521  if (mat_nr < ob->totcol) {
4522  ma_ob = ob->mat[mat_nr];
4523  matbit = ob->matbits[mat_nr];
4524  }
4525  else {
4526  ma_ob = NULL;
4527  matbit = 0;
4528  }
4529 
4530  if (mat_nr < *totcolp) {
4531  ma_obdata = (*matarar)[mat_nr];
4532  }
4533  else {
4534  ma_obdata = NULL;
4535  }
4536 
4537  BKE_id_material_clear(bmain, obdata);
4538  BKE_object_material_resize(bmain, ob, 1, true);
4539  BKE_id_material_resize(bmain, obdata, 1, true);
4540 
4541  ob->mat[0] = ma_ob;
4542  id_us_plus((ID *)ma_ob);
4543  ob->matbits[0] = matbit;
4544  (*matarar)[0] = ma_obdata;
4545  id_us_plus((ID *)ma_obdata);
4546  }
4547  else {
4548  BKE_id_material_clear(bmain, obdata);
4549  BKE_object_material_resize(bmain, ob, 0, true);
4550  BKE_id_material_resize(bmain, obdata, 0, true);
4551  }
4552 }
4553 
4555  Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
4556 {
4557  BMFace *f_cmp, *f;
4558  BMIter iter;
4559  bool result = false;
4560 
4561  while ((f_cmp = BM_iter_at_index(bm_old, BM_FACES_OF_MESH, NULL, 0))) {
4562  Base *base_new;
4563  const short mat_nr = f_cmp->mat_nr;
4564  int tot = 0;
4565 
4567 
4568  BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) {
4569  if (f->mat_nr == mat_nr) {
4570  BMLoop *l_iter;
4571  BMLoop *l_first;
4572 
4574  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
4575  do {
4576  BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
4577  BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
4578  } while ((l_iter = l_iter->next) != l_first);
4579 
4580  tot++;
4581  }
4582  }
4583 
4584  /* leave the current object with some materials */
4585  if (tot == bm_old->totface) {
4586  mesh_separate_material_assign_mat_nr(bmain, base_old->object, mat_nr);
4587 
4588  /* since we're in editmode, must set faces here */
4589  BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) {
4590  f->mat_nr = 0;
4591  }
4592  break;
4593  }
4594 
4595  /* Move selection into a separate object */
4596  base_new = mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old);
4597  if (base_new) {
4598  mesh_separate_material_assign_mat_nr(bmain, base_new->object, mat_nr);
4599  }
4600 
4601  result |= (base_new != NULL);
4602  }
4603 
4604  return result;
4605 }
4606 
4608  Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
4609 {
4610  /* Without this, we duplicate the object mode mesh for each loose part.
4611  * This can get very slow especially for large meshes with many parts
4612  * which would duplicate the mesh on entering edit-mode. */
4613  const bool clear_object_data = true;
4614 
4615  bool result = false;
4616 
4617  BMVert **vert_groups = MEM_mallocN(sizeof(*vert_groups) * bm_old->totvert, __func__);
4618  BMEdge **edge_groups = MEM_mallocN(sizeof(*edge_groups) * bm_old->totedge, __func__);
4619  BMFace **face_groups = MEM_mallocN(sizeof(*face_groups) * bm_old->totface, __func__);
4620 
4621  int(*groups)[3] = NULL;
4622  int groups_len = BM_mesh_calc_edge_groups_as_arrays(
4623  bm_old, vert_groups, edge_groups, face_groups, &groups);
4624  if (groups_len <= 1) {
4625  goto finally;
4626  }
4627 
4628  if (clear_object_data) {
4629  ED_mesh_geometry_clear(base_old->object->data);
4630  }
4631 
4633 
4634  /* Separate out all groups except the first. */
4635  uint group_ofs[3] = {UNPACK3(groups[0])};
4636  for (int i = 1; i < groups_len; i++) {
4637  Base *base_new = mesh_separate_arrays(bmain,
4638  scene,
4639  view_layer,
4640  base_old,
4641  bm_old,
4642  vert_groups + group_ofs[0],
4643  groups[i][0],
4644  edge_groups + group_ofs[1],
4645  groups[i][1],
4646  face_groups + group_ofs[2],
4647  groups[i][2]);
4648  result |= (base_new != NULL);
4649 
4650  group_ofs[0] += groups[i][0];
4651  group_ofs[1] += groups[i][1];
4652  group_ofs[2] += groups[i][2];
4653  }
4654 
4655  Mesh *me_old = base_old->object->data;
4657 
4658  if (clear_object_data) {
4660  bm_old,
4661  me_old,
4662  (&(struct BMeshToMeshParams){
4663  .update_shapekey_indices = true,
4664  }));
4665  }
4666 
4667 finally:
4668  MEM_freeN(vert_groups);
4669  MEM_freeN(edge_groups);
4670  MEM_freeN(face_groups);
4671 
4672  MEM_freeN(groups);
4673 
4674  return result;
4675 }
4676 
4678 {
4679  Main *bmain = CTX_data_main(C);
4681  ViewLayer *view_layer = CTX_data_view_layer(C);
4682  const int type = RNA_enum_get(op->ptr, "type");
4683  bool changed_multi = false;
4684 
4685  if (ED_operator_editmesh(C)) {
4686  uint bases_len = 0;
4687  uint empty_selection_len = 0;
4689  view_layer, CTX_wm_view3d(C), &bases_len);
4690  for (uint bs_index = 0; bs_index < bases_len; bs_index++) {
4691  Base *base = bases[bs_index];
4693  bool changed = false;
4694 
4695  if (type == 0) {
4696  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
4697  /* when all objects has no selection */
4698  if (++empty_selection_len == bases_len) {
4699  BKE_report(op->reports, RPT_ERROR, "Nothing selected");
4700  }
4701  continue;
4702  }
4703  }
4704 
4705  /* editmode separate */
4706  switch (type) {
4708  changed = mesh_separate_selected(bmain, scene, view_layer, base, em->bm);
4709  break;
4711  changed = mesh_separate_material(bmain, scene, view_layer, base, em->bm);
4712  break;
4713  case MESH_SEPARATE_LOOSE:
4714  changed = mesh_separate_loose(bmain, scene, view_layer, base, em->bm);
4715  break;
4716  default:
4717  BLI_assert(0);
4718  break;
4719  }
4720 
4721  if (changed) {
4722  EDBM_update(base->object->data,
4723  &(const struct EDBMUpdate_Params){
4724  .calc_looptri = true,
4725  .calc_normals = false,
4726  .is_destructive = true,
4727  });
4728  }
4729  changed_multi |= changed;
4730  }
4731  MEM_freeN(bases);
4732  }
4733  else {
4734  if (type == MESH_SEPARATE_SELECTED) {
4735  BKE_report(op->reports, RPT_ERROR, "Selection not supported in object mode");
4736  return OPERATOR_CANCELLED;
4737  }
4738 
4739  /* object mode separate */
4740  CTX_DATA_BEGIN (C, Base *, base_iter, selected_editable_bases) {
4741  Object *ob = base_iter->object;
4742  if (ob->type == OB_MESH) {
4743  Mesh *me = ob->data;
4744  if (BKE_id_is_editable(bmain, &me->id)) {
4745  BMesh *bm_old = NULL;
4746  bool changed = false;
4747 
4749  &((struct BMeshCreateParams){
4750  .use_toolflags = true,
4751  }));
4752 
4753  BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0}));
4754 
4755  switch (type) {
4757  changed = mesh_separate_material(bmain, scene, view_layer, base_iter, bm_old);
4758  break;
4759  case MESH_SEPARATE_LOOSE:
4760  changed = mesh_separate_loose(bmain, scene, view_layer, base_iter, bm_old);
4761  break;
4762  default:
4763  BLI_assert(0);
4764  break;
4765  }
4766 
4767  if (changed) {
4768  BM_mesh_bm_to_me(bmain,
4769  bm_old,
4770  me,
4771  (&(struct BMeshToMeshParams){
4772  .calc_object_remap = true,
4773  }));
4774 
4777  }
4778 
4779  BM_mesh_free(bm_old);
4780 
4781  changed_multi |= changed;
4782  }
4783  }
4784  }
4785  CTX_DATA_END;
4786  }
4787 
4788  if (changed_multi) {
4789  /* delay depsgraph recalc until all objects are duplicated */
4790  DEG_relations_tag_update(bmain);
4793 
4794  return OPERATOR_FINISHED;
4795  }
4796 
4797  return OPERATOR_CANCELLED;
4798 }
4799 
4801 {
4802  static const EnumPropertyItem prop_separate_types[] = {
4803  {MESH_SEPARATE_SELECTED, "SELECTED", 0, "Selection", ""},
4804  {MESH_SEPARATE_MATERIAL, "MATERIAL", 0, "By Material", ""},
4805  {MESH_SEPARATE_LOOSE, "LOOSE", 0, "By Loose Parts", ""},
4806  {0, NULL, 0, NULL, NULL},
4807  };
4808 
4809  /* identifiers */
4810  ot->name = "Separate";
4811  ot->description = "Separate selected geometry into a new mesh";
4812  ot->idname = "MESH_OT_separate";
4813 
4814  /* api callbacks */
4817  ot->poll = ED_operator_scene_editable; /* object and editmode */
4818 
4819  /* flags */
4820  ot->flag = OPTYPE_UNDO;
4821 
4822  ot->prop = RNA_def_enum(
4823  ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", "");
4824 }
4825 
4828 /* -------------------------------------------------------------------- */
4833 {
4834  const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty");
4835 
4836  bool has_selected_edges = false, has_faces_filled = false;
4837 
4838  ViewLayer *view_layer = CTX_data_view_layer(C);
4839  uint objects_len = 0;
4841  view_layer, CTX_wm_view3d(C), &objects_len);
4842  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4843  Object *obedit = objects[ob_index];
4844  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4845 
4846  const int totface_orig = em->bm->totface;
4847 
4848  if (em->bm->totedgesel == 0) {
4849  continue;
4850  }
4851  has_selected_edges = true;
4852 
4853  BMOperator bmop;
4854  if (!EDBM_op_init(
4855  em, &bmop, op, "triangle_fill edges=%he use_beauty=%b", BM_ELEM_SELECT, use_beauty)) {
4856  continue;
4857  }
4858 
4859  BMO_op_exec(em->bm, &bmop);
4860 
4861  /* cancel if nothing was done */
4862  if (totface_orig == em->bm->totface) {
4863  EDBM_op_finish(em, &bmop, op, true);
4864  continue;
4865  }
4866  has_faces_filled = true;
4867 
4868  /* select new geometry */
4870  em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
4871 
4872  if (!EDBM_op_finish(em, &bmop, op, true)) {
4873  continue;
4874  }
4875 
4876  EDBM_update(obedit->data,
4877  &(const struct EDBMUpdate_Params){
4878  .calc_looptri = true,
4879  .calc_normals = false,
4880  .is_destructive = true,
4881  });
4882  }
4883  MEM_freeN(objects);
4884 
4885  if (!has_selected_edges) {
4886  BKE_report(op->reports, RPT_ERROR, "No edges selected");
4887  return OPERATOR_CANCELLED;
4888  }
4889 
4890  if (!has_faces_filled) {
4891  BKE_report(op->reports, RPT_WARNING, "No faces filled");
4892  return OPERATOR_CANCELLED;
4893  }
4894 
4895  return OPERATOR_FINISHED;
4896 }
4897 
4899 {
4900  /* identifiers */
4901  ot->name = "Fill";
4902  ot->idname = "MESH_OT_fill";
4903  ot->description = "Fill a selected edge loop with faces";
4904 
4905  /* api callbacks */
4906  ot->exec = edbm_fill_exec;
4908 
4909  /* flags */
4911 
4912  RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division");
4913 }
4914 
4917 /* -------------------------------------------------------------------- */
4921 static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v))
4922 {
4924 }
4925 
4927 {
4928  BMIter iter;
4929  BMEdge *e_iter;
4930  BMVert *v_pair[2];
4931  int i = 0;
4932  BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
4933  if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) {
4934  v_pair[i++] = BM_edge_other_vert(e_iter, v);
4935  }
4936  }
4937  BLI_assert(i == 2);
4938 
4939  return fabsf((float)M_PI - angle_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co));
4940 }
4941 
4945 static bool edbm_fill_grid_prepare(BMesh *bm, int offset, int *span_p, const bool span_calc)
4946 {
4947  /* angle differences below this value are considered 'even'
4948  * in that they shouldn't be used to calculate corners used for the 'span' */
4949  const float eps_even = 1e-3f;
4950  BMEdge *e;
4951  BMIter iter;
4952  int count;
4953  int span = *span_p;
4954 
4955  ListBase eloops = {NULL};
4956  struct BMEdgeLoopStore *el_store;
4957  // LinkData *el_store;
4958 
4960  el_store = eloops.first;
4961 
4962  if (count != 1) {
4963  /* Let the operator use the selection flags,
4964  * most likely failing with an error in this case. */
4965  BM_mesh_edgeloops_free(&eloops);
4966  return false;
4967  }
4968 
4969  /* Only tag edges that are part of a loop. */
4970  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
4972  }
4973  const int verts_len = BM_edgeloop_length_get(el_store);
4974  const int edges_len = verts_len - (BM_edgeloop_is_closed(el_store) ? 0 : 1);
4975  BMEdge **edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
4976  BM_edgeloop_edges_get(el_store, edges);
4977  for (int i = 0; i < edges_len; i++) {
4978  BM_elem_flag_enable(edges[i], BM_ELEM_TAG);
4979  }
4980 
4981  if (span_calc) {
4982  span = verts_len / 4;
4983  }
4984  else {
4985  span = min_ii(span, (verts_len / 2) - 1);
4986  }
4987  offset = mod_i(offset, verts_len);
4988 
4989  if ((count == 1) && ((verts_len & 1) == 0) && (verts_len == edges_len)) {
4990 
4991  /* be clever! detect 2 edge loops from one closed edge loop */
4992  ListBase *verts = BM_edgeloop_verts_get(el_store);
4993  BMVert *v_act = BM_mesh_active_vert_get(bm);
4994  LinkData *v_act_link;
4995  int i;
4996 
4997  if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) {
4998  /* pass */
4999  }
5000  else {
5001  /* find the vertex with the best angle (a corner vertex) */
5002  LinkData *v_link, *v_link_best = NULL;
5003  float angle_best = -1.0f;
5004  for (v_link = verts->first; v_link; v_link = v_link->next) {
5005  const float angle = edbm_fill_grid_vert_tag_angle(v_link->data);
5006  if ((angle > angle_best) || (v_link_best == NULL)) {
5007  angle_best = angle;
5008  v_link_best = v_link;
5009  }
5010  }
5011 
5012  v_act_link = v_link_best;
5013  v_act = v_act_link->data;
5014  }
5015 
5016  /* set this vertex first */
5017  BLI_listbase_rotate_first(verts, v_act_link);
5018 
5019  if (offset != 0) {
5020  v_act_link = BLI_findlink(verts, offset);
5021  v_act = v_act_link->data;
5022  BLI_listbase_rotate_first(verts, v_act_link);
5023  }
5024 
5025  /* Run again to update the edge order from the rotated vertex list. */
5026  BM_edgeloop_edges_get(el_store, edges);
5027 
5028  if (span_calc) {
5029  /* calculate the span by finding the next corner in 'verts'
5030  * we don't know what defines a corner exactly so find the 4 verts
5031  * in the loop with the greatest angle.
5032  * Tag them and use the first tagged vertex to calculate the span.
5033  *
5034  * NOTE: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each
5035  * vert, but advantage of de-duplicating is minimal. */
5036  struct SortPtrByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__);
5037  LinkData *v_link;
5038  for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) {
5039  BMVert *v = v_link->data;
5040  const float angle = edbm_fill_grid_vert_tag_angle(v);
5041  ele_sort[i].sort_value = angle;
5042  ele_sort[i].data = v;
5043 
5045  }
5046 
5047  qsort(ele_sort, verts_len, sizeof(*ele_sort), BLI_sortutil_cmp_float_reverse);
5048 
5049  /* check that we have at least 3 corners,
5050  * if the angle on the 3rd angle is roughly the same as the last,
5051  * then we can't calculate 3+ corners - fallback to the even span. */
5052  if ((ele_sort[2].sort_value - ele_sort[verts_len - 1].sort_value) > eps_even) {
5053  for (i = 0; i < 4; i++) {
5054  BMVert *v = ele_sort[i].data;
5056  }
5057 
5058  /* now find the first... */
5059  for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) {
5060  BMVert *v = v_link->data;
5062  if (v != v_act) {
5063  span = i;
5064  break;
5065  }
5066  }
5067  }
5068  }
5069  MEM_freeN(ele_sort);
5070  }
5071  /* end span calc */
5072 
5073  /* un-flag 'rails' */
5074  for (i = 0; i < span; i++) {
5075  BM_elem_flag_disable(edges[i], BM_ELEM_TAG);
5076  BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG);
5077  }
5078  }
5079  /* else let the bmesh-operator handle it */
5080 
5081  BM_mesh_edgeloops_free(&eloops);
5082  MEM_freeN(edges);
5083 
5084  *span_p = span;
5085 
5086  return true;
5087 }
5088 
5090 {
5091  const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple");
5092 
5093  ViewLayer *view_layer = CTX_data_view_layer(C);
5094  uint objects_len = 0;
5096  view_layer, CTX_wm_view3d(C), &objects_len);
5097  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5098 
5099  Object *obedit = objects[ob_index];
5100  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5101 
5102  bool use_prepare = true;
5103  const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
5104  const int totedge_orig = em->bm->totedge;
5105  const int totface_orig = em->bm->totface;
5106 
5107  if (em->bm->totedgesel == 0) {
5108  continue;
5109  }
5110 
5111  if (use_prepare) {
5112  /* use when we have a single loop selected */
5113  PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span");
5114  PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset");
5115  bool calc_span;
5116 
5117  int span;
5118  int offset;
5119 
5120  /* Only reuse on redo because these settings need to match the current selection.
5121  * We never want to use them on other geometry, repeat last for eg, see: T60777. */
5122  if (((op->flag & OP_IS_INVOKE) || (op->flag & OP_IS_REPEAT_LAST) == 0) &&
5123  RNA_property_is_set(op->ptr, prop_span)) {
5124  span = RNA_property_int_get(op->ptr, prop_span);
5125  calc_span = false;
5126  }
5127  else {
5128  /* Will be overwritten if possible. */
5129  span = 0;
5130  calc_span = true;
5131  }
5132 
5133  offset = RNA_property_int_get(op->ptr, prop_offset);
5134 
5135  /* in simple cases, move selection for tags, but also support more advanced cases */
5136  use_prepare = edbm_fill_grid_prepare(em->bm, offset, &span, calc_span);
5137 
5138  RNA_property_int_set(op->ptr, prop_span, span);
5139  }
5140  /* end tricky prepare code */
5141 
5142  BMOperator bmop;
5143  if (!EDBM_op_init(em,
5144  &bmop,
5145  op,
5146  "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
5147  use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT,
5148  em->mat_nr,
5149  use_smooth,
5150  use_interp_simple)) {
5151  continue;
5152  }
5153 
5154  BMO_op_exec(em->bm, &bmop);
5155 
5156  /* NOTE: EDBM_op_finish() will change bmesh pointer inside of edit mesh,
5157  * so need to tell evaluated objects to sync new bmesh pointer to their
5158  * edit mesh structures.
5159  */
5160  DEG_id_tag_update(&obedit->id, 0);
5161 
5162  /* cancel if nothing was done */
5163  if ((totedge_orig == em->bm->totedge) && (totface_orig == em->bm->totface)) {
5164  EDBM_op_finish(em, &bmop, op, true);
5165  continue;
5166  }
5167 
5169  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
5170 
5171  if (!EDBM_op_finish(em, &bmop, op, true)) {
5172  continue;
5173  }
5174 
5175  EDBM_update(obedit->data,
5176  &(const struct EDBMUpdate_Params){
5177  .calc_looptri = true,
5178  .calc_normals = false,
5179  .is_destructive = true,
5180  });
5181  }
5182 
5183  MEM_freeN(objects);
5184 
5185  return OPERATOR_FINISHED;
5186 }
5187 
5189 {
5190  PropertyRNA *prop;
5191 
5192  /* identifiers */
5193  ot->name = "Grid Fill";
5194  ot->description = "Fill grid from two loops";
5195  ot->idname = "MESH_OT_fill_grid";
5196 
5197  /* api callbacks */
5200 
5201  /* flags */
5203 
5204  /* properties */
5205  prop = RNA_def_int(ot->srna, "span", 1, 1, 1000, "Span", "Number of grid columns", 1, 100);
5207  prop = RNA_def_int(ot->srna,
5208  "offset",
5209  0,
5210  -1000,
5211  1000,
5212  "Offset",
5213  "Vertex that is the corner of the grid",
5214  -100,
5215  100);
5218  "use_interp_simple",
5219  false,
5220  "Simple Blending",
5221  "Use simple interpolation of grid vertices");
5222 }
5223 
5226 /* -------------------------------------------------------------------- */
5231 {
5232  const int sides = RNA_int_get(op->ptr, "sides");
5233 
5234  ViewLayer *view_layer = CTX_data_view_layer(C);
5235  uint objects_len = 0;
5237  view_layer, CTX_wm_view3d(C), &objects_len);
5238 
5239  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5240  Object *obedit = objects[ob_index];
5241  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5242 
5243  if (em->bm->totedgesel == 0) {
5244  continue;
5245  }
5246 
5248  em, op, "faces.out", true, "holes_fill edges=%he sides=%i", BM_ELEM_SELECT, sides)) {
5249  continue;
5250  }
5251 
5252  EDBM_update(obedit->data,
5253  &(const struct EDBMUpdate_Params){
5254  .calc_looptri = true,
5255  .calc_normals = false,
5256  .is_destructive = true,
5257  });
5258  }
5259  MEM_freeN(objects);
5260 
5261  return OPERATOR_FINISHED;
5262 }
5263 
5265 {
5266  /* identifiers */
5267  ot->name = "Fill Holes";
5268  ot->idname = "MESH_OT_fill_holes";
5269  ot->description = "Fill in holes (boundary edge loops)";
5270 
5271  /* api callbacks */
5274 
5275  /* flags */
5277 
5278  RNA_def_int(ot->srna,
5279  "sides",
5280  4,
5281  0,
5282  1000,
5283  "Sides",
5284  "Number of sides in hole required to fill (zero fills all holes)",
5285  0,
5286  100);
5287 }
5288 
5291 /* -------------------------------------------------------------------- */
5296 {
5297  ViewLayer *view_layer = CTX_data_view_layer(C);
5298  uint objects_len = 0;
5300  view_layer, CTX_wm_view3d(C), &objects_len);
5301 
5302  const float angle_max = M_PI;
5303  const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
5304  char hflag;
5305 
5306  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5307  Object *obedit = objects[ob_index];
5308  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5309 
5310  if (em->bm->totfacesel == 0) {
5311  continue;
5312  }
5313 
5314  if (angle_limit >= angle_max) {
5315  hflag = BM_ELEM_SELECT;
5316  }
5317  else {
5318  BMIter iter;
5319  BMEdge *e;
5320 
5321  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
5323  BM_ELEM_TAG,
5325  BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit));
5326  }
5327  hflag = BM_ELEM_TAG;
5328  }
5329 
5330  if (!EDBM_op_call_and_selectf(em,
5331  op,
5332  "geom.out",
5333  true,
5334  "beautify_fill faces=%hf edges=%he",
5336  hflag)) {
5337  continue;
5338  }
5339 
5340  EDBM_update(obedit->data,
5341  &(const struct EDBMUpdate_Params){
5342  .calc_looptri = true,
5343  .calc_normals = false,
5344  .is_destructive = true,
5345  });
5346  }
5347 
5348  MEM_freeN(objects);
5349 
5350  return OPERATOR_FINISHED;
5351 }
5352 
5354 {
5355  PropertyRNA *prop;
5356 
5357  /* identifiers */
5358  ot->name = "Beautify Faces";
5359  ot->idname = "MESH_OT_beautify_fill";
5360  ot->description = "Rearrange some faces to try to get less degenerated geometry";
5361 
5362  /* api callbacks */
5365 
5366  /* flags */
5368 
5369  /* props */
5370  prop = RNA_def_float_rotation(ot->srna,
5371  "angle_limit",
5372  0,
5373  NULL,
5374  0.0f,
5375  DEG2RADF(180.0f),
5376  "Max Angle",
5377  "Angle limit",
5378  0.0f,
5379  DEG2RADF(180.0f));
5381 }
5382 
5385 /* -------------------------------------------------------------------- */
5390 {
5391  const float offset = RNA_float_get(op->ptr, "offset");
5392  const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset");
5393  const int center_mode = RNA_enum_get(op->ptr, "center_mode");
5394 
5395  ViewLayer *view_layer = CTX_data_view_layer(C);
5396  uint objects_len = 0;
5398  view_layer, CTX_wm_view3d(C), &objects_len);
5399  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5400  Object *obedit = objects[ob_index];
5401  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5402 
5403  if (em->bm->totfacesel == 0) {
5404  continue;
5405  }
5406 
5407  BMOperator bmop;
5408  EDBM_op_init(em,
5409  &bmop,
5410  op,
5411  "poke faces=%hf offset=%f use_relative_offset=%b center_mode=%i",
5413  offset,
5414  use_relative_offset,
5415  center_mode);
5416  BMO_op_exec(em->bm, &bmop);
5417 
5419 
5421  em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true);
5423  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
5424 
5425  if (!EDBM_op_finish(em, &bmop, op, true)) {
5426  continue;
5427  }
5428 
5429  EDBM_update(obedit->data,
5430  &(const struct EDBMUpdate_Params){
5431  .calc_looptri = true,
5432  .calc_normals = true,
5433  .is_destructive = true,
5434  });
5435  }
5436  MEM_freeN(objects);
5437 
5438  return OPERATOR_FINISHED;
5439 }
5440 
5442 {
5443  static const EnumPropertyItem poke_center_modes[] = {
5445  "MEDIAN_WEIGHTED",
5446  0,
5447  "Weighted Median",
5448  "Weighted median face center"},
5449  {BMOP_POKE_MEDIAN, "MEDIAN", 0, "Median", "Median face center"},
5450  {BMOP_POKE_BOUNDS, "BOUNDS", 0, "Bounds", "Face bounds center"},
5451  {0, NULL, 0, NULL, NULL},
5452  };
5453 
5454  /* identifiers */
5455  ot->name = "Poke Faces";
5456  ot->idname = "MESH_OT_poke";
5457  ot->description = "Split a face into a fan";
5458 
5459  /* api callbacks */
5462 
5463  /* flags */
5465 
5467  ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
5469  "use_relative_offset",
5470  false,
5471  "Offset Relative",
5472  "Scale the offset by surrounding geometry");
5473  RNA_def_enum(ot->srna,
5474  "center_mode",
5475  poke_center_modes,
5477  "Poke Center",
5478  "Poke face center calculation");
5479 }
5480 
5483 /* -------------------------------------------------------------------- */
5488 {
5489  const int quad_method = RNA_enum_get(op->ptr, "quad_method");
5490  const int ngon_method = RNA_enum_get(op->ptr, "ngon_method");
5491  ViewLayer *view_layer = CTX_data_view_layer(C);
5492 
5493  uint objects_len = 0;
5495  view_layer, CTX_wm_view3d(C), &objects_len);
5496  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5497  Object *obedit = objects[ob_index];
5498  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5499 
5500  if (em->bm->totfacesel == 0) {
5501  continue;
5502  }
5503 
5504  BMOperator bmop;
5505  BMOIter oiter;
5506  BMFace *f;
5507 
5509 
5510  EDBM_op_init(em,
5511  &bmop,
5512  op,
5513  "triangulate faces=%hf quad_method=%i ngon_method=%i",
5515  quad_method,
5516  ngon_method);
5517  BMO_op_exec(em->bm, &bmop);
5518 
5519  /* select the output */
5521  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
5522 
5523  /* remove the doubles */
5524  BMO_ITER (f, &oiter, bmop.slots_out, "face_map_double.out", BM_FACE) {
5525  BM_face_kill(em->bm, f);
5526  }
5527 
5529 
5530  if (!EDBM_op_finish(em, &bmop, op, true)) {
5531  continue;
5532  }
5533 
5535 
5536  EDBM_update(obedit->data,
5537  &(const struct EDBMUpdate_Params){
5538  .calc_looptri = true,
5539  .calc_normals = false,
5540  .is_destructive = true,
5541  });
5542  }
5543 
5544  MEM_freeN(objects);
5545 
5546  return OPERATOR_FINISHED;
5547 }
5548 
5550 {
5551  /* identifiers */
5552  ot->name = "Triangulate Faces";
5553  ot->idname = "MESH_OT_quads_convert_to_tris";
5554  ot->description = "Triangulate selected faces";
5555 
5556  /* api callbacks */
5559 
5560  /* flags */
5562 
5563  RNA_def_enum(ot->srna,
5564  "quad_method",
5567  "Quad Method",
5568  "Method for splitting the quads into triangles");
5569  RNA_def_enum(ot->srna,
5570  "ngon_method",
5573  "N-gon Method",
5574  "Method for splitting the n-gons into triangles");
5575 }
5576 
5579 /* -------------------------------------------------------------------- */
5584 {
5585  ViewLayer *view_layer = CTX_data_view_layer(C);
5586 
5587  uint objects_len = 0;
5589  view_layer, CTX_wm_view3d(C), &objects_len);
5590 
5591  const bool do_seam = RNA_boolean_get(op->ptr, "seam");
5592  const bool do_sharp = RNA_boolean_get(op->ptr, "sharp");
5593  const bool do_uvs = RNA_boolean_get(op->ptr, "uvs");
5594  const bool do_vcols = RNA_boolean_get(op->ptr, "vcols");
5595  const bool do_materials = RNA_boolean_get(op->ptr, "materials");
5596 
5597  float angle_face_threshold, angle_shape_threshold;
5598  bool is_face_pair;
5599  {
5600  int totelem_sel[3];
5601  EDBM_mesh_stats_multi(objects, objects_len, NULL, totelem_sel);
5602  is_face_pair = (totelem_sel[2] == 2);
5603  }
5604 
5605  /* When joining exactly 2 faces, no limit.
5606  * this is useful for one off joins while editing. */
5607  {
5608  PropertyRNA *prop;
5609  prop = RNA_struct_find_property(op->ptr, "face_threshold");
5610  if (is_face_pair && (RNA_property_is_set(op->ptr, prop) == false)) {
5611  angle_face_threshold = DEG2RADF(180.0f);
5612  }
5613  else {
5614  angle_face_threshold = RNA_property_float_get(op->ptr, prop);
5615  }
5616 
5617  prop = RNA_struct_find_property(op->ptr, "shape_threshold");
5618  if (is_face_pair && (RNA_property_is_set(op->ptr, prop) == false)) {
5619  angle_shape_threshold = DEG2RADF(180.0f);
5620  }
5621  else {
5622  angle_shape_threshold = RNA_property_float_get(op->ptr, prop);
5623  }
5624  }
5625 
5626  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5627  Object *obedit = objects[ob_index];
5628  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5629 
5630  if (em->bm->totfacesel == 0) {
5631  continue;
5632  }
5633 
5635 
5637  em,
5638  op,
5639  "faces.out",
5640  true,
5641  "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f "
5642  "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
5644  angle_face_threshold,
5645  angle_shape_threshold,
5646  do_seam,
5647  do_sharp,
5648  do_uvs,
5649  do_vcols,
5650  do_materials)) {
5651  continue;
5652  }
5653 
5655 
5656  EDBM_update(obedit->data,
5657  &(const struct EDBMUpdate_Params){
5658  .calc_looptri = true,
5659  .calc_normals = false,
5660  .is_destructive = true,
5661  });
5662  }
5663  MEM_freeN(objects);
5664 
5665  return OPERATOR_FINISHED;
5666 }
5667 
5669 {
5670  PropertyRNA *prop;
5671 
5672  prop = RNA_def_float_rotation(ot->srna,
5673  "face_threshold",
5674  0,
5675  NULL,
5676  0.0f,
5677  DEG2RADF(180.0f),
5678  "Max Face Angle",
5679  "Face angle limit",
5680  0.0f,
5681  DEG2RADF(180.0f));
5683 
5684  prop = RNA_def_float_rotation(ot->srna,
5685  "shape_threshold",
5686  0,
5687  NULL,
5688  0.0f,
5689  DEG2RADF(180.0f),
5690  "Max Shape Angle",
5691  "Shape angle limit",
5692  0.0f,
5693  DEG2RADF(180.0f));
5695 
5696  RNA_def_boolean(ot->srna, "uvs", false, "Compare UVs", "");
5697  RNA_def_boolean(ot->srna, "vcols", false, "Compare VCols", "");
5698  RNA_def_boolean(ot->srna, "seam", false, "Compare Seam", "");
5699  RNA_def_boolean(ot->srna, "sharp", false, "Compare Sharp", "");
5700  RNA_def_boolean(ot->srna, "materials", false, "Compare Materials", "");
5701 }
5702 
5704 {
5705  /* identifiers */
5706  ot->name = "Tris to Quads";
5707  ot->idname = "MESH_OT_tris_convert_to_quads";
5708  ot->description = "Join triangles into quads";
5709 
5710  /* api callbacks */
5713 
5714  /* flags */
5716 
5718 }
5719 
5722 /* -------------------------------------------------------------------- */
5732 {
5733  const float ratio = RNA_float_get(op->ptr, "ratio");
5734  bool use_vertex_group = RNA_boolean_get(op->ptr, "use_vertex_group");
5735  const float vertex_group_factor = RNA_float_get(op->ptr, "vertex_group_factor");
5736  const bool invert_vertex_group = RNA_boolean_get(op->ptr, "invert_vertex_group");
5737  const bool use_symmetry = RNA_boolean_get(op->ptr, "use_symmetry");
5738  const float symmetry_eps = 0.00002f;
5739  const int symmetry_axis = use_symmetry ? RNA_enum_get(op->ptr, "symmetry_axis") : -1;
5740 
5741  /* nop */
5742  if (ratio == 1.0f) {
5743  return OPERATOR_FINISHED;
5744  }
5745 
5746  ViewLayer *view_layer = CTX_data_view_layer(C);
5747  uint objects_len = 0;
5749  view_layer, CTX_wm_view3d(C), &objects_len);
5750 
5751  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5752  Object *obedit = objects[ob_index];
5753  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5754  BMesh *bm = em->bm;
5755  if (bm->totedgesel == 0) {
5756  continue;
5757  }
5758 
5759  float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__);
5760  {
5761  const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
5762  const int defbase_act = BKE_object_defgroup_active_index_get(obedit) - 1;
5763 
5764  if (use_vertex_group && (cd_dvert_offset == -1)) {
5765  BKE_report(op->reports, RPT_WARNING, "No active vertex group");
5766  use_vertex_group = false;
5767  }
5768 
5769  BMIter iter;
5770  BMVert *v;
5771  int i;
5772  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
5773  float weight = 0.0f;
5775  if (use_vertex_group) {
5776  const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
5777  weight = BKE_defvert_find_weight(dv, defbase_act);
5778  if (invert_vertex_group) {
5779  weight = 1.0f - weight;
5780  }
5781  }
5782  else {
5783  weight = 1.0f;
5784  }
5785  }
5786 
5787  vweights[i] = weight;
5788  BM_elem_index_set(v, i); /* set_inline */
5789  }
5791  }
5792 
5793  float ratio_adjust;
5794 
5795  if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) {
5796  ratio_adjust = ratio;
5797  }
5798  else {
5807  int totface_basis = 0;
5808  int totface_adjacent = 0;
5809  BMIter iter;
5810  BMFace *f;
5811  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
5812  /* count faces during decimation, ngons are triangulated */
5813  const int f_len = f->len > 4 ? (f->len - 2) : 1;
5814  totface_basis += f_len;
5815 
5816  BMLoop *l_iter, *l_first;
5817  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
5818  do {
5819  if (vweights[BM_elem_index_get(l_iter->v)] != 0.0f) {
5820  totface_adjacent += f_len;
5821  break;
5822  }
5823  } while ((l_iter = l_iter->next) != l_first);
5824  }
5825 
5826  ratio_adjust = ratio;
5827  ratio_adjust = 1.0f - ratio_adjust;
5828  ratio_adjust *= (float)totface_adjacent / (float)totface_basis;
5829  ratio_adjust = 1.0f - ratio_adjust;
5830  }
5831 
5833  em->bm, ratio_adjust, vweights, vertex_group_factor, false, symmetry_axis, symmetry_eps);
5834 
5835  MEM_freeN(vweights);
5836 
5837  {
5838  short selectmode = em->selectmode;
5839  if ((selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
5840  /* ensure we flush edges -> faces */
5841  selectmode |= SCE_SELECT_EDGE;
5842  }
5843  EDBM_selectmode_flush_ex(em, selectmode);
5844  }
5845  EDBM_update(obedit->data,
5846  &(const struct EDBMUpdate_Params){
5847  .calc_looptri = true,
5848  .calc_normals = true,
5849  .is_destructive = true,
5850  });
5851  }
5852  MEM_freeN(objects);
5853 
5854  return OPERATOR_FINISHED;
5855 }
5856 
5858 {
5859  return true;
5860 }
5861 
5863 {
5864  uiLayout *layout = op->layout, *row, *col, *sub;
5865 
5866  uiLayoutSetPropSep(layout, true);
5867 
5868  uiItemR(layout, op->ptr, "ratio", 0, NULL, ICON_NONE);
5869 
5870  uiItemR(layout, op->ptr, "use_vertex_group", 0, NULL, ICON_NONE);
5871  col = uiLayoutColumn(layout, false);
5872  uiLayoutSetActive(col, RNA_boolean_get(op->ptr, "use_vertex_group"));
5873  uiItemR(col, op->ptr, "vertex_group_factor", 0, NULL, ICON_NONE);
5874  uiItemR(col, op->ptr, "invert_vertex_group", 0, NULL, ICON_NONE);
5875 
5876  row = uiLayoutRowWithHeading(layout, true, IFACE_("Symmetry"));
5877  uiItemR(row, op->ptr, "use_symmetry", 0, "", ICON_NONE);
5878  sub = uiLayoutRow(row, true);
5879  uiLayoutSetActive(sub, RNA_boolean_get(op->ptr, "use_symmetry"));
5880  uiItemR(sub, op->ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
5881 }
5882 
5884 {
5885  /* identifiers */
5886  ot->name = "Decimate Geometry";
5887  ot->idname = "MESH_OT_decimate";
5888  ot->description = "Simplify geometry by collapsing edges";
5889 
5890  /* api callbacks */
5893  ot->ui = edbm_decimate_ui;
5895 
5896  /* flags */
5898 
5899  /* NOTE: keep in sync with 'rna_def_modifier_decimate'. */
5900  RNA_def_float(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f);
5901 
5903  "use_vertex_group",
5904  false,
5905  "Vertex Group",
5906  "Use active vertex group as an influence");
5908  "vertex_group_factor",
5909  1.0f,
5910  0.0f,
5911  1000.0f,
5912  "Weight",
5913  "Vertex group strength",
5914  0.0f,
5915  10.0f);
5917  ot->srna, "invert_vertex_group", false, "Invert", "Invert vertex group influence");
5918 
5919  RNA_def_boolean(ot->srna, "use_symmetry", false, "Symmetry", "Maintain symmetry on an axis");
5920 
5921  RNA_def_enum(ot->srna, "symmetry_axis", rna_enum_axis_xyz_items, 1, "Axis", "Axis of symmetry");
5922 }
5923 
5926 /* -------------------------------------------------------------------- */
5930 static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag)
5931 {
5932  PropertyRNA *prop;
5933 
5934  prop = RNA_def_boolean(
5935  ot->srna, "use_verts", value, "Dissolve Vertices", "Dissolve remaining vertices");
5936 
5937  if (flag) {
5938  RNA_def_property_flag(prop, flag);
5939  }
5940 }
5942 {
5944  "use_face_split",
5945  false,
5946  "Face Split",
5947  "Split off face corners to maintain surrounding geometry");
5948 }
5950 {
5952  "use_boundary_tear",
5953  false,
5954  "Tear Boundary",
5955  "Split off face corners instead of merging faces");
5956 }
5957 
5959 {
5960  const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
5961  const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
5962 
5963  ViewLayer *view_layer = CTX_data_view_layer(C);
5964  uint objects_len = 0;
5966  view_layer, CTX_wm_view3d(C), &objects_len);
5967 
5968  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5969  Object *obedit = objects[ob_index];
5970  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5971 
5972  if (em->bm->totvertsel == 0) {
5973  continue;
5974  }
5975 
5977 
5978  if (!EDBM_op_callf(em,
5979  op,
5980  "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
5982  use_face_split,
5983  use_boundary_tear)) {
5984  continue;
5985  }
5986 
5988 
5989  EDBM_update(obedit->data,
5990  &(const struct EDBMUpdate_Params){
5991  .calc_looptri = true,
5992  .calc_normals = false,
5993  .is_destructive = true,
5994  });
5995  }
5996 
5997  MEM_freeN(objects);
5998  return OPERATOR_FINISHED;
5999 }
6000 
6002 {
6003  /* identifiers */
6004  ot->name = "Dissolve Vertices";
6005  ot->description = "Dissolve vertices, merge edges and faces";
6006  ot->idname = "MESH_OT_dissolve_verts";
6007 
6008  /* api callbacks */
6011 
6012  /* flags */
6014 
6017 }
6018 
6021 /* -------------------------------------------------------------------- */
6026 {
6027  const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
6028  const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
6029 
6030  ViewLayer *view_layer = CTX_data_view_layer(C);
6031  uint objects_len = 0;
6033  view_layer, CTX_wm_view3d(C), &objects_len);
6034  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6035  Object *obedit = objects[ob_index];
6036  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6037 
6038  if (em->bm->totedgesel == 0) {
6039  continue;
6040  }
6041 
6043 
6044  if (!EDBM_op_callf(em,
6045  op,
6046  "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
6048  use_verts,
6049  use_face_split)) {
6050  continue;
6051  }
6052 
6054 
6055  EDBM_update(obedit->data,
6056  &(const struct EDBMUpdate_Params){
6057  .calc_looptri = true,
6058  .calc_normals = false,
6059  .is_destructive = true,
6060  });
6061  }
6062 
6063  MEM_freeN(objects);
6064 
6065  return OPERATOR_FINISHED;
6066 }
6067 
6069 {
6070  /* identifiers */
6071  ot->name = "Dissolve Edges";
6072  ot->description = "Dissolve edges, merging faces";
6073  ot->idname = "MESH_OT_dissolve_edges";
6074 
6075  /* api callbacks */
6078 
6079  /* flags */
6081 
6084 }
6085 
6088 /* -------------------------------------------------------------------- */
6093 {
6094  const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
6095  ViewLayer *view_layer = CTX_data_view_layer(C);
6096  uint objects_len = 0;
6098  view_layer, CTX_wm_view3d(C), &objects_len);
6099  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6100  Object *obedit = objects[ob_index];
6101  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6102 
6103  if (em->bm->totfacesel == 0) {
6104  continue;
6105  }
6106 
6108 
6109  if (!EDBM_op_call_and_selectf(em,
6110  op,
6111  "region.out",
6112  true,
6113  "dissolve_faces faces=%hf use_verts=%b",
6115  use_verts)) {
6116  continue;
6117  }
6118 
6120 
6121  EDBM_update(obedit->data,
6122  &(const struct EDBMUpdate_Params){
6123  .calc_looptri = true,
6124  .calc_normals = false,
6125  .is_destructive = true,
6126  });
6127  }
6128  MEM_freeN(objects);
6129 
6130  return OPERATOR_FINISHED;
6131 }
6132 
6134 {
6135  /* identifiers */
6136  ot->name = "Dissolve Faces";
6137  ot->description = "Dissolve faces";
6138  ot->idname = "MESH_OT_dissolve_faces";
6139 
6140  /* api callbacks */
6143 
6144  /* flags */
6146 
6147  edbm_dissolve_prop__use_verts(ot, false, 0);
6148 }
6149 
6152 /* -------------------------------------------------------------------- */
6157 {
6158  Object *obedit = CTX_data_edit_object(C);
6159  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6160  PropertyRNA *prop;
6161 
6162  prop = RNA_struct_find_property(op->ptr, "use_verts");
6163  if (!RNA_property_is_set(op->ptr, prop)) {
6164  /* always enable in edge-mode */
6165  if ((em->selectmode & SCE_SELECT_FACE) == 0) {
6166  RNA_property_boolean_set(op->ptr, prop, true);
6167  }
6168  }
6169 
6170  if (em->selectmode & SCE_SELECT_VERTEX) {
6171  return edbm_dissolve_verts_exec(C, op);
6172  }
6173  if (em->selectmode & SCE_SELECT_EDGE) {
6174  return edbm_dissolve_edges_exec(C, op);
6175  }
6176  return edbm_dissolve_faces_exec(C, op);
6177 }
6178 
6180 {
6181  /* identifiers */
6182  ot->name = "Dissolve Selection";
6183  ot->description = "Dissolve geometry based on the selection mode";
6184  ot->idname = "MESH_OT_dissolve_mode";
6185 
6186  /* api callbacks */
6189 
6190  /* flags */
6192 
6196 }
6197 
6200 /* -------------------------------------------------------------------- */
6205 {
6206  const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
6207  const bool use_dissolve_boundaries = RNA_boolean_get(op->ptr, "use_dissolve_boundaries");
6208  const int delimit = RNA_enum_get(op->ptr, "delimit");
6209  char dissolve_flag;
6210 
6211  ViewLayer *view_layer = CTX_data_view_layer(C);
6212  uint objects_len = 0;
6214  view_layer, CTX_wm_view3d(C), &objects_len);
6215  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6216  Object *obedit = objects[ob_index];
6217  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6218  BMesh *bm = em->bm;
6219 
6220  if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) {
6221  continue;
6222  }
6223 
6225 
6226  if (em->selectmode == SCE_SELECT_FACE) {
6227  /* flush selection to tags and untag edges/verts with partially selected faces */
6228  BMIter iter;
6229  BMIter liter;
6230 
6231  BMElem *ele;
6232  BMFace *f;
6233  BMLoop *l;
6234 
6235  BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
6237  }
6238  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
6240  }
6241 
6242  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
6243  if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
6244  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
6247  }
6248  }
6249  }
6250 
6251  dissolve_flag = BM_ELEM_TAG;
6252  }
6253  else {
6254  dissolve_flag = BM_ELEM_SELECT;
6255  }
6256 
6258  em,
6259  op,
6260  "region.out",
6261  true,
6262  "dissolve_limit edges=%he verts=%hv angle_limit=%f use_dissolve_boundaries=%b delimit=%i",
6263  dissolve_flag,
6264  dissolve_flag,
6265  angle_limit,
6266  use_dissolve_boundaries,
6267  delimit);
6268 
6270 
6271  EDBM_update(obedit->data,
6272  &(const struct EDBMUpdate_Params){
6273  .calc_looptri = true,
6274  .calc_normals = false,
6275  .is_destructive = true,
6276  });
6277  }
6278  MEM_freeN(objects);
6279 
6280  return OPERATOR_FINISHED;
6281 }
6282 
6284 {
6285  PropertyRNA *prop;
6286 
6287  /* identifiers */
6288  ot->name = "Limited Dissolve";
6289  ot->idname = "MESH_OT_dissolve_limited";
6290  ot->description =
6291  "Dissolve selected edges and vertices, limited by the angle of surrounding geometry";
6292 
6293  /* api callbacks */
6296 
6297  /* flags */
6299 
6300  prop = RNA_def_float_rotation(ot->srna,
6301  "angle_limit",
6302  0,
6303  NULL,
6304  0.0f,
6305  DEG2RADF(180.0f),
6306  "Max Angle",
6307  "Angle limit",
6308  0.0f,
6309  DEG2RADF(180.0f));
6312  "use_dissolve_boundaries",
6313  false,
6314  "All Boundaries",
6315  "Dissolve all vertices in between face boundaries");
6317  "delimit",
6320  "Delimit",
6321  "Delimit dissolve operation");
6322 }
6323 
6326 /* -------------------------------------------------------------------- */
6331 {
6332  ViewLayer *view_layer = CTX_data_view_layer(C);
6333  int totelem_old[3] = {0, 0, 0};
6334  int totelem_new[3] = {0, 0, 0};
6335 
6336  uint objects_len = 0;
6338  view_layer, CTX_wm_view3d(C), &objects_len);
6339 
6340  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6341  Object *obedit = objects[ob_index];
6342  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6343  BMesh *bm = em->bm;
6344  totelem_old[0] += bm->totvert;
6345  totelem_old[1] += bm->totedge;
6346  totelem_old[2] += bm->totface;
6347  } /* objects */
6348 
6349  const float thresh = RNA_float_get(op->ptr, "threshold");
6350 
6351  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6352  Object *obedit = objects[ob_index];
6353  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6354  BMesh *bm = em->bm;
6355 
6356  if (!EDBM_op_callf(em, op, "dissolve_degenerate edges=%he dist=%f", BM_ELEM_SELECT, thresh)) {
6357  continue;
6358  }
6359 
6360  /* tricky to maintain correct selection here, so just flush up from verts */
6361  EDBM_select_flush(em);
6362 
6363  EDBM_update(obedit->data,
6364  &(const struct EDBMUpdate_Params){
6365  .calc_looptri = true,
6366  .calc_normals = false,
6367  .is_destructive = true,
6368  });
6369 
6370  totelem_new[0] += bm->totvert;
6371  totelem_new[1] += bm->totedge;
6372  totelem_new[2] += bm->totface;
6373  }
6374  MEM_freeN(objects);
6375 
6376  edbm_report_delete_info(op->reports, totelem_old, totelem_new);
6377 
6378  return OPERATOR_FINISHED;
6379 }
6380 
6382 {
6383  /* identifiers */
6384  ot->name = "Degenerate Dissolve";
6385  ot->idname = "MESH_OT_dissolve_degenerate";
6386  ot->description = "Dissolve zero area faces and zero length edges";
6387 
6388  /* api callbacks */
6391 
6392  /* flags */
6394 
6396  "threshold",
6397  1e-4f,
6398  1e-6f,
6399  50.0f,
6400  "Merge Distance",
6401  "Maximum distance between elements to merge",
6402  1e-5f,
6403  10.0f);
6404 }
6405 
6408 /* -------------------------------------------------------------------- */
6412 /* internally uses dissolve */
6414 {
6415  const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
6416  ViewLayer *view_layer = CTX_data_view_layer(C);
6417 
6418  uint objects_len = 0;
6420  view_layer, CTX_wm_view3d(C), &objects_len);
6421  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6422  Object *obedit = objects[ob_index];
6423  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6424 
6425  if (em->bm->totedgesel == 0) {
6426  continue;
6427  }
6428 
6429  /* deal with selection */
6430  {
6431  BMEdge *e;
6432  BMIter iter;
6433 
6435 
6436  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
6437  if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
6438  BMLoop *l_iter = e->l;
6439  do {
6440  BM_elem_flag_enable(l_iter->f, BM_ELEM_TAG);
6441  } while ((l_iter = l_iter->radial_next) != e->l);
6442  }
6443  }
6444  }
6445 
6446  if (!EDBM_op_callf(em,
6447  op,
6448  "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
6450  true,
6451  use_face_split)) {
6452  continue;
6453  }
6454 
6456 
6458 
6459  EDBM_update(obedit->data,
6460  &(const struct EDBMUpdate_Params){
6461  .calc_looptri = true,
6462  .calc_normals = false,
6463  .is_destructive = true,
6464  });
6465  }
6466 
6467  MEM_freeN(objects);
6468  return OPERATOR_FINISHED;
6469 }
6470 
6472 {
6473  /* identifiers */
6474  ot->name = "Delete Edge Loop";
6475  ot->description = "Delete an edge loop by merging the faces on each side";
6476  ot->idname = "MESH_OT_delete_edgeloop";
6477 
6478  /* api callbacks */
6481 
6482  /* flags */
6484 
6486  "use_face_split",
6487  true,
6488  "Face Split",
6489  "Split off face corners to maintain surrounding geometry");
6490 }
6491 
6494 /* -------------------------------------------------------------------- */
6499 {
6500  ViewLayer *view_layer = CTX_data_view_layer(C);
6501  uint objects_len = 0;
6503  view_layer, CTX_wm_view3d(C), &objects_len);
6504  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6505  Object *obedit = objects[ob_index];
6506  BMEditMesh *em = BKE_editmesh_from_object(obedit);
6507  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
6508  continue;
6509  }
6511 
6512  BMOperator bmop;
6513  EDBM_op_init(em, &bmop, op, "split geom=%hvef use_only_faces=%b", BM_ELEM_SELECT, false);
6514  BMO_op_exec(em->bm, &bmop);
6517  em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
6518 
6520 
6521  if (!EDBM_op_finish(em, &bmop, op, true)) {
6522  continue;
6523  }
6524 
6525  /* Geometry has changed, need to recalculate normals and tessellation. */
6526  EDBM_update(obedit->data,
6527  &(const struct EDBMUpdate_Params){
6528  .calc_looptri = true,
6529  .calc_normals = true,
6530  .is_destructive = true,
6531  });
6532  }
6533  MEM_freeN(objects);
6534 
6535  return OPERATOR_FINISHED;
6536 }
6537 
6539 {
6540  /* identifiers */
6541  ot->name = "Split";
6542  ot->idname = "MESH_OT_split";
6543  ot->description = "Split off selected geometry from connected unselected geometry";
6544 
6545  /* api callbacks */
6546  ot->exec = edbm_split_exec;
6548 
6549  /* flags */
6551 }
6552 
6555 /* -------------------------------------------------------------------- */
6562 enum {
6578 };
6579 
6580 typedef struct BMElemSort {
6582  float srt;
6584  int org_idx;
6586 
6587 static int bmelemsort_comp(const void *v1, const void *v2)
6588 {
6589  const BMElemSort *x1 = v1, *x2 = v2;
6590 
6591  return (x1->srt > x2->srt) - (x1->srt < x2->srt);
6592 }
6593 
6594 /* Reorders vertices/edges/faces using a given methods. Loops are not supported. */
6596  Scene *scene,
6597  Object *ob,
6598  RegionView3D *rv3d,
6599  const int types,
6600  const int flag,
6601  const int action,
6602  const int reverse,
6603  const uint seed)
6604 {
6606 
6607  BMVert *ve;
6608  BMEdge *ed;
6609  BMFace *fa;
6610  BMIter iter;
6611 
6612  /* In all five elements below, 0 = vertices, 1 = edges, 2 = faces. */
6613  /* Just to mark protected elements. */
6614  char *pblock[3] = {NULL, NULL, NULL}, *pb;
6615  BMElemSort *sblock[3] = {NULL, NULL, NULL}, *sb;
6616  uint *map[3] = {NULL, NULL, NULL}, *mp;
6617  int totelem[3] = {0, 0, 0};
6618  int affected[3] = {0, 0, 0};
6619  int i, j;
6620 
6621  if (!(types && flag && action)) {
6622  return;
6623  }
6624 
6625  if (types & BM_VERT) {
6626  totelem[0] = em->bm->totvert;
6627  }
6628  if (types & BM_EDGE) {
6629  totelem[1] = em->bm->totedge;
6630  }
6631  if (types & BM_FACE) {
6632  totelem[2] = em->bm->totface;
6633  }
6634 
6635  if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) {
6636  float mat[4][4];
6637  float fact = reverse ? -1.0 : 1.0;
6638  int coidx = (action == SRT_VIEW_ZAXIS) ? 2 : 0;
6639 
6640  /* Apply the view matrix to the object matrix. */
6641  mul_m4_m4m4(mat, rv3d->viewmat, ob->obmat);
6642 
6643  if (totelem[0]) {
6644  pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
6645  sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock");
6646 
6647  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6648  if (BM_elem_flag_test(ve, flag)) {
6649  float co[3];
6650  mul_v3_m4v3(co, mat, ve->co);
6651 
6652  pb[i] = false;
6653  sb[affected[0]].org_idx = i;
6654  sb[affected[0]++].srt = co[coidx] * fact;
6655  }
6656  else {
6657  pb[i] = true;
6658  }
6659  }
6660  }
6661 
6662  if (totelem[1]) {
6663  pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
6664  sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock");
6665 
6666  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6667  if (BM_elem_flag_test(ed, flag)) {
6668  float co[3];
6669  mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
6670  mul_m4_v3(mat, co);
6671 
6672  pb[i] = false;
6673  sb[affected[1]].org_idx = i;
6674  sb[affected[1]++].srt = co[coidx] * fact;
6675  }
6676  else {
6677  pb[i] = true;
6678  }
6679  }
6680  }
6681 
6682  if (totelem[2]) {
6683  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6684  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6685 
6686  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6687  if (BM_elem_flag_test(fa, flag)) {
6688  float co[3];
6690  mul_m4_v3(mat, co);
6691 
6692  pb[i] = false;
6693  sb[affected[2]].org_idx = i;
6694  sb[affected[2]++].srt = co[coidx] * fact;
6695  }
6696  else {
6697  pb[i] = true;
6698  }
6699  }
6700  }
6701  }
6702 
6703  else if (action == SRT_CURSOR_DISTANCE) {
6704  float cur[3];
6705  float mat[4][4];
6706  float fact = reverse ? -1.0 : 1.0;
6707 
6709 
6710  invert_m4_m4(mat, ob->obmat);
6711  mul_m4_v3(mat, cur);
6712 
6713  if (totelem[0]) {
6714  pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
6715  sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock");
6716 
6717  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6718  if (BM_elem_flag_test(ve, flag)) {
6719  pb[i] = false;
6720  sb[affected[0]].org_idx = i;
6721  sb[affected[0]++].srt = len_squared_v3v3(cur, ve->co) * fact;
6722  }
6723  else {
6724  pb[i] = true;
6725  }
6726  }
6727  }
6728 
6729  if (totelem[1]) {
6730  pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
6731  sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock");
6732 
6733  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6734  if (BM_elem_flag_test(ed, flag)) {
6735  float co[3];
6736  mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
6737 
6738  pb[i] = false;
6739  sb[affected[1]].org_idx = i;
6740  sb[affected[1]++].srt = len_squared_v3v3(cur, co) * fact;
6741  }
6742  else {
6743  pb[i] = true;
6744  }
6745  }
6746  }
6747 
6748  if (totelem[2]) {
6749  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6750  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6751 
6752  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6753  if (BM_elem_flag_test(fa, flag)) {
6754  float co[3];
6756 
6757  pb[i] = false;
6758  sb[affected[2]].org_idx = i;
6759  sb[affected[2]++].srt = len_squared_v3v3(cur, co) * fact;
6760  }
6761  else {
6762  pb[i] = true;
6763  }
6764  }
6765  }
6766  }
6767 
6768  /* Faces only! */
6769  else if (action == SRT_MATERIAL && totelem[2]) {
6770  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6771  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6772 
6773  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6774  if (BM_elem_flag_test(fa, flag)) {
6775  /* Reverse materials' order, not order of faces inside each mat! */
6776  /* NOTE: cannot use totcol, as mat_nr may sometimes be greater... */
6777  float srt = reverse ? (float)(MAXMAT - fa->mat_nr) : (float)fa->mat_nr;
6778  pb[i] = false;
6779  sb[affected[2]].org_idx = i;
6780  /* Multiplying with totface and adding i ensures us
6781  * we keep current order for all faces of same mat. */
6782  sb[affected[2]++].srt = srt * ((float)totelem[2]) + ((float)i);
6783  // printf("e: %d; srt: %f; final: %f\n",
6784  // i, srt, srt * ((float)totface) + ((float)i));
6785  }
6786  else {
6787  pb[i] = true;
6788  }
6789  }
6790  }
6791 
6792  else if (action == SRT_SELECTED) {
6793  uint *tbuf[3] = {NULL, NULL, NULL}, *tb;
6794 
6795  if (totelem[0]) {
6796  tb = tbuf[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert tbuf");
6797  mp = map[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert map");
6798 
6799  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6800  if (BM_elem_flag_test(ve, flag)) {
6801  mp[affected[0]++] = i;
6802  }
6803  else {
6804  *tb = i;
6805  tb++;
6806  }
6807  }
6808  }
6809 
6810  if (totelem[1]) {
6811  tb = tbuf[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge tbuf");
6812  mp = map[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge map");
6813 
6814  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6815  if (BM_elem_flag_test(ed, flag)) {
6816  mp[affected[1]++] = i;
6817  }
6818  else {
6819  *tb = i;
6820  tb++;
6821  }
6822  }
6823  }
6824 
6825  if (totelem[2]) {
6826  tb = tbuf[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face tbuf");
6827  mp = map[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face map");
6828 
6829  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6830  if (BM_elem_flag_test(fa, flag)) {
6831  mp[affected[2]++] = i;
6832  }
6833  else {
6834  *tb = i;
6835  tb++;
6836  }
6837  }
6838  }
6839 
6840  for (j = 3; j--;) {
6841  int tot = totelem[j];
6842  int aff = affected[j];
6843  tb = tbuf[j];
6844  mp = map[j];
6845  if (!(tb && mp)) {
6846  continue;
6847  }
6848  if (ELEM(aff, 0, tot)) {
6849  MEM_freeN(tb);
6850  MEM_freeN(mp);
6851  map[j] = NULL;
6852  continue;
6853  }
6854  if (reverse) {
6855  memcpy(tb + (tot - aff), mp, aff * sizeof(int));
6856  }
6857  else {
6858  memcpy(mp + aff, tb, (tot - aff) * sizeof(int));
6859  tb = mp;
6860  mp = map[j] = tbuf[j];
6861  tbuf[j] = tb;
6862  }
6863 
6864  /* Reverse mapping, we want an org2new one! */
6865  for (i = tot, tb = tbuf[j] + tot - 1; i--; tb--) {
6866  mp[*tb] = i;
6867  }
6868  MEM_freeN(tbuf[j]);
6869  }
6870  }
6871 
6872  else if (action == SRT_RANDOMIZE) {
6873  if (totelem[0]) {
6874  /* Re-init random generator for each element type, to get consistent random when
6875  * enabling/disabling an element type. */
6876  RNG *rng = BLI_rng_new_srandom(seed);
6877  pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
6878  sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock");
6879 
6880  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6881  if (BM_elem_flag_test(ve, flag)) {
6882  pb[i] = false;
6883  sb[affected[0]].org_idx = i;
6884  sb[affected[0]++].srt = BLI_rng_get_float(rng);
6885  }
6886  else {
6887  pb[i] = true;
6888  }
6889  }
6890 
6891  BLI_rng_free(rng);
6892  }
6893 
6894  if (totelem[1]) {
6895  RNG *rng = BLI_rng_new_srandom(seed);
6896  pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
6897  sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock");
6898 
6899  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6900  if (BM_elem_flag_test(ed, flag)) {
6901  pb[i] = false;
6902  sb[affected[1]].org_idx = i;
6903  sb[affected[1]++].srt = BLI_rng_get_float(rng);
6904  }
6905  else {
6906  pb[i] = true;
6907  }
6908  }
6909 
6910  BLI_rng_free(rng);
6911  }
6912 
6913  if (totelem[2]) {
6914  RNG *rng = BLI_rng_new_srandom(seed);
6915  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6916  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6917 
6918  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6919  if (BM_elem_flag_test(fa, flag)) {
6920  pb[i] = false;
6921  sb[affected[2]].org_idx = i;
6922  sb[affected[2]++].srt = BLI_rng_get_float(rng);
6923  }
6924  else {
6925  pb[i] = true;
6926  }
6927  }
6928 
6929  BLI_rng_free(rng);
6930  }
6931  }
6932 
6933  else if (action == SRT_REVERSE) {
6934  if (totelem[0]) {
6935  pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
6936  sb = sblock[0] = MEM_callocN(sizeof(BMElemSort) * totelem[0], "sort_bmelem vert sblock");
6937 
6938  BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
6939  if (BM_elem_flag_test(ve, flag)) {
6940  pb[i] = false;
6941  sb[affected[0]].org_idx = i;
6942  sb[affected[0]++].srt = (float)-i;
6943  }
6944  else {
6945  pb[i] = true;
6946  }
6947  }
6948  }
6949 
6950  if (totelem[1]) {
6951  pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
6952  sb = sblock[1] = MEM_callocN(sizeof(BMElemSort) * totelem[1], "sort_bmelem edge sblock");
6953 
6954  BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
6955  if (BM_elem_flag_test(ed, flag)) {
6956  pb[i] = false;
6957  sb[affected[1]].org_idx = i;
6958  sb[affected[1]++].srt = (float)-i;
6959  }
6960  else {
6961  pb[i] = true;
6962  }
6963  }
6964  }
6965 
6966  if (totelem[2]) {
6967  pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
6968  sb = sblock[2] = MEM_callocN(sizeof(BMElemSort) * totelem[2], "sort_bmelem face sblock");
6969 
6970  BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
6971  if (BM_elem_flag_test(fa, flag)) {
6972  pb[i] = false;
6973  sb[affected[2]].org_idx = i;
6974  sb[affected[2]++].srt = (float)-i;
6975  }
6976  else {
6977  pb[i] = true;
6978  }
6979  }
6980  }
6981  }
6982 
6983  // printf("%d vertices: %d to be affected...\n", totelem[0], affected[0]);
6984  // printf("%d edges: %d to be affected...\n", totelem[1], affected[1]);
6985  // printf("%d faces: %d to be affected...\n", totelem[2], affected[2]);
6986  if (affected[0] == 0 && affected[1] == 0 && affected[2] == 0) {
6987  for (j = 3; j--;) {
6988  if (pblock[j]) {
6989  MEM_freeN(pblock[j]);
6990  }
6991  if (sblock[j]) {
6992  MEM_freeN(sblock[j]);
6993  }
6994  if (map[j]) {
6995  MEM_freeN(map[j]);
6996  }
6997  }
6998  return;
6999  }
7000 
7001  /* Sort affected elements, and populate mapping arrays, if needed. */
7002  for (j = 3; j--;) {
7003  pb = pblock[j];
7004  sb = sblock[j];
7005  if (pb && sb && !map[j]) {
7006  const char *p_blk;
7007  BMElemSort *s_blk;
7008  int tot = totelem[j];
7009  int aff = affected[j];
7010 
7011  qsort(sb, aff, sizeof(BMElemSort), bmelemsort_comp);
7012 
7013  mp = map[j] = MEM_mallocN(sizeof(int) * tot, "sort_bmelem map");
7014  p_blk = pb + tot - 1;
7015  s_blk = sb + aff - 1;
7016  for (i = tot; i--; p_blk--) {
7017  if (*p_blk) { /* Protected! */
7018  mp[i] = i;
7019  }
7020  else {
7021  mp[s_blk->org_idx] = i;
7022  s_blk--;
7023  }
7024  }
7025  }
7026  if (pb) {
7027  MEM_freeN(pb);
7028  }
7029  if (sb) {
7030  MEM_freeN(sb);
7031  }
7032  }
7033 
7034  BM_mesh_remap(em->bm, map[0], map[1], map[2]);
7035 
7036  EDBM_update(ob->data,
7037  &(const struct EDBMUpdate_Params){
7038  .calc_looptri = (totelem[2] != 0),
7039  .calc_normals = false,
7040  .is_destructive = true,
7041  });
7042 
7045 
7046  for (j = 3; j--;) {
7047  if (map[j]) {
7048  MEM_freeN(map[j]);
7049  }
7050  }
7051 }
7052 
7054 {
7056  ViewLayer *view_layer = CTX_data_view_layer(C);
7057  Object *ob_active = CTX_data_edit_object(C);
7058 
7059  /* may be NULL */
7061 
7062  const int action = RNA_enum_get(op->ptr, "type");
7063  PropertyRNA *prop_elem_types = RNA_struct_find_property(op->ptr, "elements");
7064  const bool use_reverse = RNA_boolean_get(op->ptr, "reverse");
7065  uint seed = RNA_int_get(op->ptr, "seed");
7066  int elem_types = 0;
7067 
7068  if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) {
7069  if (rv3d == NULL) {
7070  BKE_report(op->reports, RPT_ERROR, "View not found, cannot sort by view axis");
7071  return OPERATOR_CANCELLED;
7072  }
7073  }
7074 
7075  /* If no elem_types set, use current selection mode to set it! */
7076  if (RNA_property_is_set(op->ptr, prop_elem_types)) {
7077  elem_types = RNA_property_enum_get(op->ptr, prop_elem_types);
7078  }
7079  else {
7080  BMEditMesh *em = BKE_editmesh_from_object(ob_active);
7081  if (em->selectmode & SCE_SELECT_VERTEX) {
7082  elem_types |= BM_VERT;
7083  }
7084  if (em->selectmode & SCE_SELECT_EDGE) {
7085  elem_types |= BM_EDGE;
7086  }
7087  if (em->selectmode & SCE_SELECT_FACE) {
7088  elem_types |= BM_FACE;
7089  }
7090  RNA_enum_set(op->ptr, "elements", elem_types);
7091  }
7092 
7093  uint objects_len = 0;
7095  view_layer, CTX_wm_view3d(C), &objects_len);
7096 
7097  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7098  Object *ob = objects[ob_index];
7100  BMesh *bm = em->bm;
7101 
7102  if (!((elem_types & BM_VERT && bm->totvertsel > 0) ||
7103  (elem_types & BM_EDGE && bm->totedgesel > 0) ||
7104  (elem_types & BM_FACE && bm->totfacesel > 0))) {
7105  continue;
7106  }
7107 
7108  int seed_iter = seed;
7109 
7110  /* This gives a consistent result regardless of object order */
7111  if (ob_index) {
7112  seed_iter += BLI_ghashutil_strhash_p(ob->id.name);
7113  }
7114 
7116  C, scene, ob, rv3d, elem_types, BM_ELEM_SELECT, action, use_reverse, seed_iter);
7117  }
7118  MEM_freeN(objects);
7119  return OPERATOR_FINISHED;
7120 }
7121 
7123  wmOperator *op,
7124  const PropertyRNA *prop)
7125 {
7126  const char *prop_id = RNA_property_identifier(prop);
7127  const int action = RNA_enum_get(op->ptr, "type");
7128 
7129  /* Only show seed for randomize action! */
7130  if (STREQ(prop_id, "seed")) {
7131  if (action == SRT_RANDOMIZE) {
7132  return true;
7133  }
7134  return false;
7135  }
7136 
7137  /* Hide seed for reverse and randomize actions! */
7138  if (STREQ(prop_id, "reverse")) {
7139  if (ELEM(action, SRT_RANDOMIZE, SRT_REVERSE)) {
7140  return false;
7141  }
7142  return true;
7143  }
7144 
7145  return true;
7146 }
7147 
7149 {
7150  static const EnumPropertyItem type_items[] = {
7151  {SRT_VIEW_ZAXIS,
7152  "VIEW_ZAXIS",
7153  0,
7154  "View Z Axis",
7155  "Sort selected elements from farthest to nearest one in current view"},
7156  {SRT_VIEW_XAXIS,
7157  "VIEW_XAXIS",
7158  0,
7159  "View X Axis",
7160  "Sort selected elements from left to right one in current view"},
7162  "CURSOR_DISTANCE",
7163  0,
7164  "Cursor Distance",
7165  "Sort selected elements from nearest to farthest from 3D cursor"},
7166  {SRT_MATERIAL,
7167  "MATERIAL",
7168  0,
7169  "Material",
7170  "Sort selected faces from smallest to greatest material index"},
7171  {SRT_SELECTED,
7172  "SELECTED",
7173  0,
7174  "Selected",
7175  "Move all selected elements in first places, preserving their relative order.\n"
7176  "Warning: This will affect unselected elements' indices as well"},
7177  {SRT_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Randomize order of selected elements"},
7178  {SRT_REVERSE, "REVERSE", 0, "Reverse", "Reverse current order of selected elements"},
7179  {0, NULL, 0, NULL, NULL},
7180  };
7181 
7182  static const EnumPropertyItem elem_items[] = {
7183  {BM_VERT, "VERT", 0, "Vertices", ""},
7184  {BM_EDGE, "EDGE", 0, "Edges", ""},
7185  {BM_FACE, "FACE", 0, "Faces", ""},
7186  {0, NULL, 0, NULL, NULL},
7187  };
7188 
7189  /* identifiers */
7190  ot->name = "Sort Mesh Elements";
7191  ot->description =
7192  "The order of selected vertices/edges/faces is modified, based on a given method";
7193  ot->idname = "MESH_OT_sort_elements";
7194 
7195  /* api callbacks */
7200 
7201  /* flags */
7203 
7204  /* properties */
7205  ot->prop = RNA_def_enum(ot->srna,
7206  "type",
7207  type_items,
7209  "Type",
7210  "Type of reordering operation to apply");
7212  "elements",
7213  elem_items,
7214  BM_VERT,
7215  "Elements",
7216  "Which elements to affect (vertices, edges and/or faces)");
7217  RNA_def_boolean(ot->srna, "reverse", false, "Reverse", "Reverse the sorting effect");
7218  RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255);
7219 }
7220 
7223 /* -------------------------------------------------------------------- */
7227 enum {
7231 };
7232 
7234 {
7235  /* tags boundary edges from a face selection */
7236  BMIter iter;
7237  BMFace *f;
7238  BMEdge *e;
7239  int totface_del = 0;
7240 
7242 
7243  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
7247  }
7248  else {
7249  BMIter fiter;
7250  bool is_all_sel = true;
7251  /* check if its only used by selected faces */
7252  BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
7254  /* Tag face for removal. */
7255  if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
7257  totface_del++;
7258  }
7259  }
7260  else {
7261  is_all_sel = false;
7262  }
7263  }
7264 
7265  if (is_all_sel == false) {
7267  }
7268  }
7269  }
7270  }
7271 
7272  return totface_del;
7273 }
7274 
7276  BMEditMesh *em,
7277  struct Mesh *me,
7278  const bool use_pairs,
7279  const bool use_cyclic,
7280  const bool use_merge,
7281  const float merge_factor,
7282  const int twist_offset)
7283 {
7284  BMOperator bmop;
7285  char edge_hflag;
7286  int totface_del = 0;
7287  BMFace **totface_del_arr = NULL;
7288  const bool use_faces = (em->bm->totfacesel != 0);
7289 
7290  if (use_faces) {
7291  BMIter iter;
7292  BMFace *f;
7293  int i;
7294 
7295  totface_del = edbm_bridge_tag_boundary_edges(em->bm);
7296  totface_del_arr = MEM_mallocN(sizeof(*totface_del_arr) * totface_del, __func__);
7297 
7298  i = 0;
7299  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
7300  if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
7301  totface_del_arr[i++] = f;
7302  }
7303  }
7304  edge_hflag = BM_ELEM_TAG;
7305  }
7306  else {
7307  edge_hflag = BM_ELEM_SELECT;
7308  }
7309 
7310  EDBM_op_init(em,
7311  &bmop,
7312  op,
7313  "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f "
7314  "twist_offset=%i",
7315  edge_hflag,
7316  use_pairs,
7317  use_cyclic,
7318  use_merge,
7319  merge_factor,
7320  twist_offset);
7321 
7322  if (use_faces && totface_del) {
7323  int i;
7325  for (i = 0; i < totface_del; i++) {
7326  BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG);
7327  }
7328  BMO_op_callf(em->bm,
7330  "delete geom=%hf context=%i",
7331  BM_ELEM_TAG,
7333  }
7334 
7335  BMO_op_exec(em->bm, &bmop);
7336 
7338  /* when merge is used the edges are joined and remain selected */
7339  if (use_merge == false) {
7342  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
7343  }
7344 
7345  if (use_merge == false) {
7346  struct EdgeRingOpSubdProps op_props;
7347  mesh_operator_edgering_props_get(op, &op_props);
7348 
7349  if (op_props.cuts) {
7350  BMOperator bmop_subd;
7351  /* we only need face normals updated */
7353 
7354  BMO_op_initf(em->bm,
7355  &bmop_subd,
7356  0,
7357  "subdivide_edgering edges=%S interp_mode=%i cuts=%i smooth=%f "
7358  "profile_shape=%i profile_shape_factor=%f",
7359  &bmop,
7360  "edges.out",
7361  op_props.interp_mode,
7362  op_props.cuts,
7363  op_props.smooth,
7364  op_props.profile_shape,
7365  op_props.profile_shape_factor);
7366  BMO_op_exec(em->bm, &bmop_subd);
7368  em->bm, bmop_subd.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
7369  BMO_op_finish(em->bm, &bmop_subd);
7370  }
7371  }
7372  }
7373 
7374  if (totface_del_arr) {
7375  MEM_freeN(totface_del_arr);
7376  }
7377 
7378  if (EDBM_op_finish(em, &bmop, op, true)) {
7379  EDBM_update(me,
7380  &(const struct EDBMUpdate_Params){
7381  .calc_looptri = true,
7382  .calc_normals = false,
7383  .is_destructive = true,
7384  });
7385  }
7386 
7387  /* Always return finished so the user can select different options. */
7388  return OPERATOR_FINISHED;
7389 }
7390 
7392 {
7393  const int type = RNA_enum_get(op->ptr, "type");
7394  const bool use_pairs = (type == MESH_BRIDGELOOP_PAIRS);
7395  const bool use_cyclic = (type == MESH_BRIDGELOOP_CLOSED);
7396  const bool use_merge = RNA_boolean_get(op->ptr, "use_merge");
7397  const float merge_factor = RNA_float_get(op->ptr, "merge_factor");
7398  const int twist_offset = RNA_int_get(op->ptr, "twist_offset");
7399  ViewLayer *view_layer = CTX_data_view_layer(C);
7400 
7401  uint objects_len = 0;
7403  view_layer, CTX_wm_view3d(C), &objects_len);
7404  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7405  Object *obedit = objects[ob_index];
7406  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7407 
7408  if (em->bm->totvertsel == 0) {
7409  continue;
7410  }
7411 
7413  op, em, obedit->data, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
7414  }
7415  MEM_freeN(objects);
7416  return OPERATOR_FINISHED;
7417 }
7418 
7420 {
7421  static const EnumPropertyItem type_items[] = {
7422  {MESH_BRIDGELOOP_SINGLE, "SINGLE", 0, "Open Loop", ""},
7423  {MESH_BRIDGELOOP_CLOSED, "CLOSED", 0, "Closed Loop", ""},
7424  {MESH_BRIDGELOOP_PAIRS, "PAIRS", 0, "Loop Pairs", ""},
7425  {0, NULL, 0, NULL, NULL},
7426  };
7427 
7428  /* identifiers */
7429  ot->name = "Bridge Edge Loops";
7430  ot->description = "Create a bridge of faces between two or more selected edge loops";
7431  ot->idname = "MESH_OT_bridge_edge_loops";
7432 
7433  /* api callbacks */
7436 
7437  /* flags */
7439 
7440  ot->prop = RNA_def_enum(ot->srna,
7441  "type",
7442  type_items,
7444  "Connect Loops",
7445  "Method of bridging multiple loops");
7446 
7447  RNA_def_boolean(ot->srna, "use_merge", false, "Merge", "Merge rather than creating faces");
7448  RNA_def_float(ot->srna, "merge_factor", 0.5f, 0.0f, 1.0f, "Merge Factor", "", 0.0f, 1.0f);
7449  RNA_def_int(ot->srna,
7450  "twist_offset",
7451  0,
7452  -1000,
7453  1000,
7454  "Twist",
7455  "Twist offset for closed loops",
7456  -1000,
7457  1000);
7458 
7460 }
7461 
7464 /* -------------------------------------------------------------------- */
7469 {
7470  const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
7471  const bool use_even_offset = RNA_boolean_get(op->ptr, "use_even_offset");
7472  const bool use_replace = RNA_boolean_get(op->ptr, "use_replace");
7473  const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset");
7474  const bool use_crease = RNA_boolean_get(op->ptr, "use_crease");
7475  const float crease_weight = RNA_float_get(op->ptr, "crease_weight");
7476  const float thickness = RNA_float_get(op->ptr, "thickness");
7477  const float offset = RNA_float_get(op->ptr, "offset");
7478 
7479  ViewLayer *view_layer = CTX_data_view_layer(C);
7480  uint objects_len = 0;
7482  view_layer, CTX_wm_view3d(C), &objects_len);
7483  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7484  Object *obedit = objects[ob_index];
7485  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7486 
7487  if (em->bm->totfacesel == 0) {
7488  continue;
7489  }
7490 
7491  BMOperator bmop;
7492 
7493  EDBM_op_init(em,
7494  &bmop,
7495  op,
7496  "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b "
7497  "use_relative_offset=%b "
7498  "use_crease=%b crease_weight=%f thickness=%f offset=%f",
7500  use_replace,
7501  use_boundary,
7502  use_even_offset,
7503  use_relative_offset,
7504  use_crease,
7505  crease_weight,
7506  thickness,
7507  offset);
7508 
7509  BMO_op_exec(em->bm, &bmop);
7510 
7513  em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
7514 
7515  if (!EDBM_op_finish(em, &bmop, op, true)) {
7516  continue;
7517  }
7518 
7519  EDBM_update(obedit->data,
7520  &(const struct EDBMUpdate_Params){
7521  .calc_looptri = true,
7522  .calc_normals = false,
7523  .is_destructive = true,
7524  });
7525  }
7526 
7527  MEM_freeN(objects);
7528 
7529  return OPERATOR_FINISHED;
7530 }
7531 
7533 {
7534  PropertyRNA *prop;
7535 
7536  /* identifiers */
7537  ot->name = "Wireframe";
7538  ot->idname = "MESH_OT_wireframe";
7539  ot->description = "Create a solid wireframe from faces";
7540 
7541  /* api callbacks */
7544 
7545  /* flags */
7547 
7548  /* properties */
7549  RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
7551  "use_even_offset",
7552  true,
7553  "Offset Even",
7554  "Scale the offset to give more even thickness");
7556  "use_relative_offset",
7557  false,
7558  "Offset Relative",
7559  "Scale the offset by surrounding geometry");
7560  RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces");
7561  prop = RNA_def_float_distance(
7562  ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f);
7563  /* use 1 rather than 10 for max else dragging the button moves too far */
7564  RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
7565  RNA_def_float_distance(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f);
7567  "use_crease",
7568  false,
7569  "Crease",
7570  "Crease hub edges for an improved subdivision surface");
7571  prop = RNA_def_float(
7572  ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease Weight", "", 0.0f, 1.0f);
7573  RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
7574 }
7575 
7578 /* -------------------------------------------------------------------- */
7583 {
7584  const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint");
7585  bool changed_multi = false;
7587  ViewLayer *view_layer = CTX_data_view_layer(C);
7588  uint bases_len = 0;
7590  view_layer, CTX_wm_view3d(C), &bases_len);
7591  for (uint base_index = 0; base_index < bases_len; base_index++) {
7592  Object *obedit = bases[base_index]->object;
7593  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7594 
7595  if (em->bm->totedgesel == 0) {
7596  continue;
7597  }
7598 
7599  BMOperator bmop;
7600  EDBM_op_init(em,
7601  &bmop,
7602  op,
7603  "offset_edgeloops edges=%he use_cap_endpoint=%b",
7605  use_cap_endpoint);
7606 
7607  BMO_op_exec(em->bm, &bmop);
7608 
7610 
7612  em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
7613 
7614  if (EDBM_op_finish(em, &bmop, op, true)) {
7615  EDBM_update(obedit->data,
7616  &(const struct EDBMUpdate_Params){
7617  .calc_looptri = true,
7618  .calc_normals = false,
7619  .is_destructive = true,
7620  });
7621  changed_multi = true;
7622  }
7623  }
7624 
7625  if (changed_multi) {
7633  }
7634  }
7635 
7636  MEM_freeN(bases);
7637 
7638  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
7639 }
7640 
7642 {
7643  /* identifiers */
7644  ot->name = "Offset Edge Loop";
7645  ot->idname = "MESH_OT_offset_edge_loops";
7646  ot->description = "Create offset edge loop from the current selection";
7647 
7648  /* api callbacks */
7651 
7652  /* Keep internal, since this is only meant to be accessed via
7653  * 'MESH_OT_offset_edge_loops_slide'. */
7654 
7655  /* flags */
7657 
7659  ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points");
7660 }
7661 
7664 /* -------------------------------------------------------------------- */
7668 #ifdef WITH_BULLET
7669 static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
7670 {
7671  const bool use_existing_faces = RNA_boolean_get(op->ptr, "use_existing_faces");
7672  const bool delete_unused = RNA_boolean_get(op->ptr, "delete_unused");
7673  const bool make_holes = RNA_boolean_get(op->ptr, "make_holes");
7674  const bool join_triangles = RNA_boolean_get(op->ptr, "join_triangles");
7675 
7676  float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold");
7677  float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold");
7678 
7679  ViewLayer *view_layer = CTX_data_view_layer(C);
7680  uint objects_len = 0;
7682  view_layer, CTX_wm_view3d(C), &objects_len);
7683  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7684  Object *obedit = objects[ob_index];
7685  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7686 
7687  if (em->bm->totvertsel == 0) {
7688  continue;
7689  }
7690 
7691  BMOperator bmop;
7692 
7693  EDBM_op_init(em,
7694  &bmop,
7695  op,
7696  "convex_hull input=%hvef "
7697  "use_existing_faces=%b",
7699  use_existing_faces);
7700  BMO_op_exec(em->bm, &bmop);
7701 
7702  /* Hull fails if input is coplanar */
7704  EDBM_op_finish(em, &bmop, op, true);
7705  continue;
7706  }
7707 
7709  em->bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
7710 
7711  /* Delete unused vertices, edges, and faces */
7712  if (delete_unused) {
7713  if (!EDBM_op_callf(
7714  em, op, "delete geom=%S context=%i", &bmop, "geom_unused.out", DEL_ONLYTAGGED)) {
7715  EDBM_op_finish(em, &bmop, op, true);
7716  continue;
7717  }
7718  }
7719 
7720  /* Delete hole edges/faces */
7721  if (make_holes) {
7722  if (!EDBM_op_callf(
7723  em, op, "delete geom=%S context=%i", &bmop, "geom_holes.out", DEL_ONLYTAGGED)) {
7724  EDBM_op_finish(em, &bmop, op, true);
7725  continue;
7726  }
7727  }
7728 
7729  /* Merge adjacent triangles */
7730  if (join_triangles) {
7731  if (!EDBM_op_call_and_selectf(em,
7732  op,
7733  "faces.out",
7734  true,
7735  "join_triangles faces=%S "
7736  "angle_face_threshold=%f angle_shape_threshold=%f",
7737  &bmop,
7738  "geom.out",
7739  angle_face_threshold,
7740  angle_shape_threshold)) {
7741  EDBM_op_finish(em, &bmop, op, true);
7742  continue;
7743  }
7744  }
7745 
7746  if (!EDBM_op_finish(em, &bmop, op, true)) {
7747  continue;
7748  }
7749 
7750  EDBM_update(obedit->data,
7751  &(const struct EDBMUpdate_Params){
7752  .calc_looptri = true,
7753  .calc_normals = false,
7754  .is_destructive = true,
7755  });
7757  }
7758 
7759  MEM_freeN(objects);
7760  return OPERATOR_FINISHED;
7761 }
7762 
7764 {
7765  /* identifiers */
7766  ot->name = "Convex Hull";
7767  ot->description = "Enclose selected vertices in a convex polyhedron";
7768  ot->idname = "MESH_OT_convex_hull";
7769 
7770  /* api callbacks */
7771  ot->exec = edbm_convex_hull_exec;
7773 
7774  /* flags */
7776 
7777  /* props */
7779  "delete_unused",
7780  true,
7781  "Delete Unused",
7782  "Delete selected elements that are not used by the hull");
7783 
7785  "use_existing_faces",
7786  true,
7787  "Use Existing Faces",
7788  "Skip hull triangles that are covered by a pre-existing face");
7789 
7791  "make_holes",
7792  false,
7793  "Make Holes",
7794  "Delete selected faces that are used by the hull");
7795 
7797  ot->srna, "join_triangles", true, "Join Triangles", "Merge adjacent triangles into quads");
7798 
7800 }
7801 #endif /* WITH_BULLET */
7802 
7805 /* -------------------------------------------------------------------- */
7810 {
7811  const float thresh = RNA_float_get(op->ptr, "threshold");
7812  ViewLayer *view_layer = CTX_data_view_layer(C);
7813  uint objects_len = 0;
7815  view_layer, CTX_wm_view3d(C), &objects_len);
7816 
7817  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7818  Object *obedit = objects[ob_index];
7819  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7820 
7821  if (em->bm->totvertsel == 0) {
7822  continue;
7823  }
7824 
7825  BMOperator bmop;
7826  EDBM_op_init(em,
7827  &bmop,
7828  op,
7829  "symmetrize input=%hvef direction=%i dist=%f",
7831  RNA_enum_get(op->ptr, "direction"),
7832  thresh);
7833  BMO_op_exec(em->bm, &bmop);
7834 
7836 
7838  em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
7839 
7840  if (!EDBM_op_finish(em, &bmop, op, true)) {
7841  continue;
7842  }
7843  EDBM_update(obedit->data,
7844  &(const struct EDBMUpdate_Params){
7845  .calc_looptri = true,
7846  .calc_normals = false,
7847  .is_destructive = true,
7848  });
7850  }
7851  MEM_freeN(objects);
7852 
7853  return OPERATOR_FINISHED;
7854 }
7855 
7857 {
7858  /* identifiers */
7859  ot->name = "Symmetrize";
7860  ot->description = "Enforce symmetry (both form and topological) across an axis";
7861  ot->idname = "MESH_OT_symmetrize";
7862 
7863  /* api callbacks */
7866 
7867  /* flags */
7869 
7870  ot->prop = RNA_def_enum(ot->srna,
7871  "direction",
7874  "Direction",
7875  "Which sides to copy from and to");
7877  "threshold",
7878  1e-4f,
7879  0.0f,
7880  10.0f,
7881  "Threshold",
7882  "Limit for snap middle vertices to the axis center",
7883  1e-5f,
7884  0.1f);
7885 }
7886 
7889 /* -------------------------------------------------------------------- */
7894 {
7895  const float eps = 0.00001f;
7896  const float eps_sq = eps * eps;
7897  const bool use_topology = false;
7898 
7899  const float thresh = RNA_float_get(op->ptr, "threshold");
7900  const float fac = RNA_float_get(op->ptr, "factor");
7901  const bool use_center = RNA_boolean_get(op->ptr, "use_center");
7902  const int axis_dir = RNA_enum_get(op->ptr, "direction");
7903 
7904  /* Vertices stats (total over all selected objects). */
7905  int totvertfound = 0, totvertmirr = 0, totvertfail = 0;
7906 
7907  /* Axis. */
7908  int axis = axis_dir % 3;
7909  bool axis_sign = axis != axis_dir;
7910 
7911  ViewLayer *view_layer = CTX_data_view_layer(C);
7912  uint objects_len = 0;
7914  view_layer, CTX_wm_view3d(C), &objects_len);
7915 
7916  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
7917  Object *obedit = objects[ob_index];
7918  BMEditMesh *em = BKE_editmesh_from_object(obedit);
7919  BMesh *bm = em->bm;
7920 
7921  if (em->bm->totvertsel == 0) {
7922  continue;
7923  }
7924 
7925  /* Only allocate memory after checking whether to skip object. */
7926  int *index = MEM_mallocN(bm->totvert * sizeof(*index), __func__);
7927 
7928  /* Vertex iter. */
7929  BMIter iter;
7930  BMVert *v;
7931  int i;
7932 
7933  EDBM_verts_mirror_cache_begin_ex(em, axis, true, true, false, use_topology, thresh, index);
7934 
7936 
7938 
7939  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
7940  if ((BM_elem_flag_test(v, BM_ELEM_SELECT) != false) &&
7941  (BM_elem_flag_test(v, BM_ELEM_TAG) == false)) {
7942  int i_mirr = index[i];
7943  if (i_mirr != -1) {
7944 
7945  BMVert *v_mirr = BM_vert_at_index(bm, index[i]);
7946 
7947  if (v != v_mirr) {
7948  float co[3], co_mirr[3];
7949 
7950  if ((v->co[axis] > v_mirr->co[axis]) == axis_sign) {
7951  SWAP(BMVert *, v, v_mirr);
7952  }
7953 
7954  copy_v3_v3(co_mirr, v_mirr->co);
7955  co_mirr[axis] *= -1.0f;
7956 
7957  if (len_squared_v3v3(v->co, co_mirr) > eps_sq) {
7958  totvertmirr++;
7959  }
7960 
7961  interp_v3_v3v3(co, v->co, co_mirr, fac);
7962 
7963  copy_v3_v3(v->co, co);
7964 
7965  co[axis] *= -1.0f;
7966  copy_v3_v3(v_mirr->co, co);
7967 
7970  totvertfound++;
7971  }
7972  else {
7973  if (use_center) {
7974 
7975  if (fabsf(v->co[axis]) > eps) {
7976  totvertmirr++;
7977  }
7978 
7979  v->co[axis] = 0.0f;
7980  }
7982  totvertfound++;
7983  }
7984  }
7985  else {
7986  totvertfail++;
7987  }
7988  }
7989  }
7990  EDBM_update(obedit->data,
7991  &(const struct EDBMUpdate_Params){
7992  .calc_looptri = false,
7993  .calc_normals = false,
7994  .is_destructive = false,
7995  });
7996 
7997  /* No need to end cache, just free the array. */
7998  MEM_freeN(index);
7999  }
8000  MEM_freeN(objects);
8001 
8002  if (totvertfail) {
8003  BKE_reportf(op->reports,
8004  RPT_WARNING,
8005  "%d already symmetrical, %d pairs mirrored, %d failed",
8006  totvertfound - totvertmirr,
8007  totvertmirr,
8008  totvertfail);
8009  }
8010  else {
8011  BKE_reportf(op->reports,
8012  RPT_INFO,
8013  "%d already symmetrical, %d pairs mirrored",
8014  totvertfound - totvertmirr,
8015  totvertmirr);
8016  }
8017 
8018  return OPERATOR_FINISHED;
8019 }
8020 
8022 {
8023  /* identifiers */
8024  ot->name = "Snap to Symmetry";
8025  ot->description = "Snap vertex pairs to their mirrored locations";
8026  ot->idname = "MESH_OT_symmetry_snap";
8027 
8028  /* api callbacks */
8031 
8032  /* flags */
8034 
8035  ot->prop = RNA_def_enum(ot->srna,
8036  "direction",
8039  "Direction",
8040  "Which sides to copy from and to");
8042  "threshold",
8043  0.05f,
8044  0.0f,
8045  10.0f,
8046  "Threshold",
8047  "Distance within which matching vertices are searched",
8048  1e-4f,
8049  1.0f);
8051  "factor",
8052  0.5f,
8053  0.0f,
8054  1.0f,
8055  "Factor",
8056  "Mix factor of the locations of the vertices",
8057  0.0f,
8058  1.0f);
8060  ot->srna, "use_center", true, "Center", "Snap middle vertices to the axis center");
8061 }
8062 
8065 #if defined(WITH_FREESTYLE)
8066 
8067 /* -------------------------------------------------------------------- */
8071 static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op)
8072 {
8073  BMEdge *eed;
8074  BMIter iter;
8075  FreestyleEdge *fed;
8076  const bool clear = RNA_boolean_get(op->ptr, "clear");
8077  ViewLayer *view_layer = CTX_data_view_layer(C);
8078 
8079  uint objects_len = 0;
8081  view_layer, CTX_wm_view3d(C), &objects_len);
8082  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
8083  Object *obedit = objects[ob_index];
8084  BMEditMesh *em = BKE_editmesh_from_object(obedit);
8085 
8086  if (em == NULL) {
8087  continue;
8088  }
8089 
8090  BMesh *bm = em->bm;
8091 
8092  if (bm->totedgesel == 0) {
8093  continue;
8094  }
8095 
8098  }
8099 
8100  if (clear) {
8101  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
8104  fed->flag &= ~FREESTYLE_EDGE_MARK;
8105  }
8106  }
8107  }
8108  else {
8109  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
8112  fed->flag |= FREESTYLE_EDGE_MARK;
8113  }
8114  }
8115  }
8116 
8119  }
8120  MEM_freeN(objects);
8121 
8122  return OPERATOR_FINISHED;
8123 }
8124 
8125 void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
8126 {
8127  PropertyRNA *prop;
8128 
8129  /* identifiers */
8130  ot->name = "Mark Freestyle Edge";
8131  ot->description = "(Un)mark selected edges as Freestyle feature edges";
8132  ot->idname = "MESH_OT_mark_freestyle_edge";
8133 
8134  /* api callbacks */
8135  ot->exec = edbm_mark_freestyle_edge_exec;
8137 
8138  /* flags */
8140 
8141  prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
8143 }
8144 
8147 /* -------------------------------------------------------------------- */
8151 static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
8152 {
8153  BMFace *efa;
8154  BMIter iter;
8155  FreestyleFace *ffa;
8156  const bool clear = RNA_boolean_get(op->ptr, "clear");
8157  ViewLayer *view_layer = CTX_data_view_layer(C);
8158 
8159  uint objects_len = 0;
8161  view_layer, CTX_wm_view3d(C), &objects_len);
8162  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
8163  Object *obedit = objects[ob_index];
8164  BMEditMesh *em = BKE_editmesh_from_object(obedit);
8165 
8166  if (em == NULL) {
8167  continue;
8168  }
8169 
8170  if (em->bm->totfacesel == 0) {
8171  continue;
8172  }
8173 
8176  }
8177 
8178  if (clear) {
8179  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
8182  ffa->flag &= ~FREESTYLE_FACE_MARK;
8183  }
8184  }
8185  }
8186  else {
8187  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
8190  ffa->flag |= FREESTYLE_FACE_MARK;
8191  }
8192  }
8193  }
8194 
8197  }
8198  MEM_freeN(objects);
8199 
8200  return OPERATOR_FINISHED;
8201 }
8202 
8203 void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
8204 {
8205  PropertyRNA *prop;
8206 
8207  /* identifiers */
8208  ot->name = "Mark Freestyle Face";
8209  ot->description = "(Un)mark selected faces for exclusion from Freestyle feature edge detection";
8210  ot->idname = "MESH_OT_mark_freestyle_face";
8211 
8212  /* api callbacks */
8213  ot->exec = edbm_mark_freestyle_face_exec;
8215 
8216  /* flags */
8218 
8219  prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
8221 }
8222 
8225 #endif /* WITH_FREESTYLE */
8226 
8227 /* -------------------------------------------------------------------- */
8231 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
8232 /* NOTE: We could add more here, like e.g. a switch between local or global coordinates of target,
8233  * use number-input to type in explicit vector values. */
8234 enum {
8235  /* Generic commands. */
8238 
8239  /* Point To operator. */
8244 
8250 };
8251 
8253 {
8254  static const EnumPropertyItem modal_items[] = {
8255  {EDBM_CLNOR_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
8256  {EDBM_CLNOR_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
8257 
8258  /* Point To operator. */
8259  {EDBM_CLNOR_MODAL_POINTTO_RESET, "RESET", 0, "Reset", "Reset normals to initial ones"},
8261  "INVERT",
8262  0,
8263  "Invert",
8264  "Toggle inversion of affected normals"},
8266  "SPHERIZE",
8267  0,
8268  "Spherize",
8269  "Interpolate between new and original normals"},
8270  {EDBM_CLNOR_MODAL_POINTTO_ALIGN, "ALIGN", 0, "Align", "Make all affected normals parallel"},
8271 
8273  "USE_MOUSE",
8274  0,
8275  "Use Mouse",
8276  "Follow mouse cursor position"},
8278  "USE_PIVOT",
8279  0,
8280  "Use Pivot",
8281  "Use current rotation/scaling pivot point coordinates"},
8283  "USE_OBJECT",
8284  0,
8285  "Use Object",
8286  "Use current edited object's location"},
8288  "SET_USE_3DCURSOR",
8289  0,
8290  "Set and Use 3D Cursor",
8291  "Set new 3D cursor position and use it"},
8293  "SET_USE_SELECTED",
8294  0,
8295  "Select and Use Mesh Item",
8296  "Select new active mesh element and use its location"},
8297  {0, NULL, 0, NULL, NULL},
8298  };
8299  static const char *keymap_name = "Custom Normals Modal Map";
8300 
8301  wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
8302 
8303  /* We only need to add map once */
8304  if (keymap && keymap->modal_items) {
8305  return NULL;
8306  }
8307 
8308  keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
8309 
8310  WM_modalkeymap_assign(keymap, "MESH_OT_point_normals");
8311 
8312  return keymap;
8313 }
8314 
8315 #define CLNORS_VALID_VEC_LEN (1e-4f)
8316 
8319 /* -------------------------------------------------------------------- */
8323 enum {
8326 };
8327 
8330  "COORDINATES",
8331  0,
8332  "Coordinates",
8333  "Use static coordinates (defined by various means)"},
8334  {EDBM_CLNOR_POINTTO_MODE_MOUSE, "MOUSE", 0, "Mouse", "Follow mouse cursor"},
8335  {0, NULL, 0, NULL, NULL},
8336 };
8337 
8338 /* Initialize loop normal data */
8340 {
8341  Object *obedit = CTX_data_edit_object(C);
8342  BMEditMesh *em = BKE_editmesh_from_object(obedit);
8343  BMesh *bm = em->bm;
8344 
8345  BKE_editmesh_ensure_autosmooth(em, obedit->data);
8346  BKE_editmesh_lnorspace_update(em, obedit->data);
8348 
8349  op->customdata = lnors_ed_arr;
8350 
8351  return (lnors_ed_arr->totloop != 0);
8352 }
8353 
8355 {
8356  if (op->customdata != NULL) {
8357  return true;
8358  }
8359  return point_normals_init(C, op);
8360 }
8361 
8363 {
8364  if (op->customdata != NULL) {
8365  BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
8366  BM_loop_normal_editdata_array_free(lnors_ed_arr);
8367  op->customdata = NULL;
8368  }
8369 }
8370 
8372 {
8373  point_normals_free(op);
8375 }
8376 
8378 {
8379  char header[UI_MAX_DRAW_STR];
8380  char buf[UI_MAX_DRAW_STR];
8381 
8382  char *p = buf;
8383  int available_len = sizeof(buf);
8384 
8385 #define WM_MODALKEY(_id) \
8386  WM_modalkeymap_operator_items_to_string_buf( \
8387  op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p)
8388 
8389  BLI_snprintf(header,
8390  sizeof(header),
8391  TIP_("%s: confirm, %s: cancel, "
8392  "%s: point to mouse (%s), %s: point to Pivot, "
8393  "%s: point to object origin, %s: reset normals, "
8394  "%s: set & point to 3D cursor, %s: select & point to mesh item, "
8395  "%s: invert normals (%s), %s: spherize (%s), %s: align (%s)"),
8406  WM_bool_as_string(RNA_boolean_get(op->ptr, "invert")),
8408  WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")),
8410  WM_bool_as_string(RNA_boolean_get(op->ptr, "align")));
8411 
8412 #undef WM_MODALKEY
8413 
8414  ED_area_status_text(CTX_wm_area(C), header);
8415 }
8416 
8417 /* TODO: move that to generic function in BMesh? */
8418 static void bmesh_selected_verts_center_calc(BMesh *bm, float *r_center)
8419 {
8420  BMVert *v;
8421  BMIter viter;
8422  int i = 0;
8423 
8424  zero_v3(r_center);
8425  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
8427  add_v3_v3(r_center, v->co);
8428  i++;
8429  }
8430  }
8431  mul_v3_fl(r_center, 1.0f / (float)i);
8432 }
8433 
8434 static void point_normals_apply(bContext *C, wmOperator *op, float target[3], const bool do_reset)
8435 {
8436  Object *obedit = CTX_data_edit_object(C);
8437  BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
8438  BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
8439 
8440  const bool do_invert = RNA_boolean_get(op->ptr, "invert");
8441  const bool do_spherize = RNA_boolean_get(op->ptr, "spherize");
8442  const bool do_align = RNA_boolean_get(op->ptr, "align");
8443  float center[3];
8444 
8445  if (do_align && !do_reset) {
8447  }
8448 
8449  sub_v3_v3(target, obedit->loc); /* Move target to local coordinates. */
8450 
8451  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
8452  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
8453  if (do_reset) {
8454  copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
8455  }
8456  else if (do_spherize) {
8457  /* Note that this is *not* real spherical interpolation.
8458  * Probably good enough in this case though? */
8459  const float strength = RNA_float_get(op->ptr, "spherize_strength");
8460  float spherized_normal[3];
8461 
8462  sub_v3_v3v3(spherized_normal, target, lnor_ed->loc);
8463 
8464  /* otherwise, multiplication by strength is meaningless... */
8465  normalize_v3(spherized_normal);
8466 
8467  mul_v3_fl(spherized_normal, strength);
8468  mul_v3_v3fl(lnor_ed->nloc, lnor_ed->niloc, 1.0f - strength);
8469  add_v3_v3(lnor_ed->nloc, spherized_normal);
8470  }
8471  else if (do_align) {
8472  sub_v3_v3v3(lnor_ed->nloc, target, center);
8473  }
8474  else {
8475  sub_v3_v3v3(lnor_ed->nloc, target, lnor_ed->loc);
8476  }
8477 
8478  if (do_invert && !do_reset) {
8479  negate_v3(lnor_ed->nloc);
8480  }
8481  if (normalize_v3(lnor_ed->nloc) >= CLNORS_VALID_VEC_LEN) {
8483  bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
8484  }
8485  }
8486 }
8487 
8488 static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event)
8489 {
8490  /* As this operator passes events through, we can't be sure the user didn't exit edit-mode.
8491  * or performed some other operation. */
8492  if (!WM_operator_poll(C, op->type)) {
8493  point_normals_cancel(C, op);
8494  return OPERATOR_CANCELLED;
8495  }
8496 
8497  View3D *v3d = CTX_wm_view3d(C);
8499  Object *obedit = CTX_data_edit_object(C);
8500  BMEditMesh *em = BKE_editmesh_from_object(obedit);
8501  BMesh *bm = em->bm;
8502 
8503  float target[3];
8504 
8505  int ret = OPERATOR_PASS_THROUGH;
8506  int mode = RNA_enum_get(op->ptr, "mode");
8507  int new_mode = mode;
8508  bool force_mousemove = false;
8509  bool do_reset = false;
8510 
8511  PropertyRNA *prop_target = RNA_struct_find_property(op->ptr, "target_location");
8512 
8513  if (event->type == EVT_MODAL_MAP) {
8514  switch (event->val) {
8516  RNA_property_float_get_array(op->ptr, prop_target, target);
8518  break;
8519 
8521  do_reset = true;
8523  break;
8524 
8526  do_reset = true;
8528  break;
8529 
8531  PropertyRNA *prop_invert = RNA_struct_find_property(op->ptr, "invert");
8533  op->ptr, prop_invert, !RNA_property_boolean_get(op->ptr, prop_invert));
8534  RNA_property_float_get_array(op->ptr, prop_target, target);
8536  break;
8537  }
8538 
8540  PropertyRNA *prop_spherize = RNA_struct_find_property(op->ptr, "spherize");
8542  op->ptr, prop_spherize, !RNA_property_boolean_get(op->ptr, prop_spherize));
8543  RNA_property_float_get_array(op->ptr, prop_target, target);
8545  break;
8546  }
8547 
8549  PropertyRNA *prop_align = RNA_struct_find_property(op->ptr, "align");
8551  op->ptr, prop_align, !RNA_property_boolean_get(op->ptr, prop_align));
8552  RNA_property_float_get_array(op->ptr, prop_target, target);
8554  break;
8555  }
8556 
8558  new_mode = EDBM_CLNOR_POINTTO_MODE_MOUSE;
8559  /* We want to immediately update to mouse cursor position... */
8560  force_mousemove = true;
8562  break;
8563 
8566  copy_v3_v3(target, obedit->loc);
8568  break;
8569 
8573  copy_v3_v3(target, scene->cursor.location);
8575  break;
8576 
8580  const struct SelectPick_Params params = {
8581  .sel_op = SEL_OP_SET,
8582  };
8583  if (EDBM_select_pick(C, event->mval, &params)) {
8584  /* Point to newly selected active. */
8585  ED_object_calc_active_center_for_editmode(obedit, false, target);
8586 
8587  add_v3_v3(target, obedit->loc);
8589  }
8590  break;
8591 
8595  case V3D_AROUND_CENTER_BOUNDS: /* calculateCenterBound */
8596  {
8597  BMVert *v;
8598  BMIter viter;
8599  float min[3], max[3];
8600  int i = 0;
8601 
8602  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
8604  if (i) {
8605  minmax_v3v3_v3(min, max, v->co);
8606  }
8607  else {
8608  copy_v3_v3(min, v->co);
8609  copy_v3_v3(max, v->co);
8610  }
8611  i++;
8612  }
8613  }
8614  mid_v3_v3v3(target, min, max);
8615  add_v3_v3(target, obedit->loc);
8616  break;
8617  }
8618 
8619  case V3D_AROUND_CENTER_MEDIAN: {
8621  add_v3_v3(target, obedit->loc);
8622  break;
8623  }
8624 
8625  case V3D_AROUND_CURSOR:
8626  copy_v3_v3(target, scene->cursor.location);
8627  break;
8628 
8629  case V3D_AROUND_ACTIVE:
8630  if (!ED_object_calc_active_center_for_editmode(obedit, false, target)) {
8631  zero_v3(target);
8632  }
8633  add_v3_v3(target, obedit->loc);
8634  break;
8635 
8636  default:
8637  BKE_report(op->reports, RPT_WARNING, "Does not support Individual Origin as pivot");
8638  copy_v3_v3(target, obedit->loc);
8639  }
8641  break;
8642  default:
8643  break;
8644  }
8645  }
8646 
8647  if (new_mode != mode) {
8648  mode = new_mode;
8649  RNA_enum_set(op->ptr, "mode", mode);
8650  }
8651 
8652  /* Only handle mouse-move event in case we are in mouse mode. */
8653  if (event->type == MOUSEMOVE || force_mousemove) {
8654  if (mode == EDBM_CLNOR_POINTTO_MODE_MOUSE) {
8655  ARegion *region = CTX_wm_region(C);
8656  float center[3];
8657 
8659 
8660  ED_view3d_win_to_3d_int(v3d, region, center, event->mval, target);
8661 
8663  }
8664  }
8665 
8666  if (ret != OPERATOR_PASS_THROUGH) {
8668  RNA_property_float_set_array(op->ptr, prop_target, target);
8669  }
8670 
8671  if (point_normals_ensure(C, op)) {
8672  point_normals_apply(C, op, target, do_reset);
8673  EDBM_update(obedit->data,
8674  &(const struct EDBMUpdate_Params){
8675  .calc_looptri = true,
8676  .calc_normals = false,
8677  .is_destructive = false,
8678  }); /* Recheck bools. */
8680  }
8681  else {
8683  }
8684  }
8685 
8687  point_normals_cancel(C, op);
8688  }
8689 
8690  /* If we allow other tools to run, we can't be sure if they will re-allocate
8691  * the data this operator uses, see: T68159.
8692  * Free the data here, then use #point_normals_ensure to add it back on demand. */
8693  if (ret == OPERATOR_PASS_THROUGH) {
8694  /* Don't free on mouse-move, causes creation/freeing of the loop data in an inefficient way. */
8695  if (!ISMOUSE_MOTION(event->type)) {
8696  point_normals_free(op);
8697  }
8698  }
8699  return ret;
8700 }
8701 
8703 {
8704  if (!point_normals_init(C, op)) {
8705  point_normals_cancel(C, op);
8706  return OPERATOR_CANCELLED;
8707  }
8708 
8710 
8712 
8714  return OPERATOR_RUNNING_MODAL;
8715 }
8716 
8717 /* TODO: make this work on multiple objects at once */
8719 {
8720  Object *obedit = CTX_data_edit_object(C);
8721 
8722  if (!point_normals_init(C, op)) {
8723  point_normals_cancel(C, op);
8724  return OPERATOR_CANCELLED;
8725  }
8726 
8727  /* Note that 'mode' is ignored in exec case,
8728  * we directly use vector stored in target_location, whatever that is. */
8729 
8730  float target[3];
8731  RNA_float_get_array(op->ptr, "target_location", target);
8732 
8733  point_normals_apply(C, op, target, false);
8734 
8735  EDBM_update(obedit->data,
8736  &(const struct EDBMUpdate_Params){
8737  .calc_looptri = true,
8738  .calc_normals = false,
8739  .is_destructive = false,
8740  });
8741  point_normals_cancel(C, op);
8742 
8743  return OPERATOR_FINISHED;
8744 }
8745 
8747  PropertyRNA *prop,
8748  void *UNUSED(user_data))
8749 {
8750  const char *prop_id = RNA_property_identifier(prop);
8751 
8752  /* Only show strength option if spherize is enabled. */
8753  if (STREQ(prop_id, "spherize_strength")) {
8754  return (bool)RNA_boolean_get(ptr, "spherize");
8755  }
8756 
8757  /* Else, show it! */
8758  return true;
8759 }
8760 
8762 {
8763  uiLayout *layout = op->layout;
8765  PointerRNA ptr;
8766 
8767  RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
8768 
8769  uiLayoutSetPropSep(layout, true);
8770 
8771  /* Main auto-draw call */
8772  uiDefAutoButsRNA(layout, &ptr, point_normals_draw_check_prop, NULL, NULL, '\0', false);
8773 }
8774 
8776 {
8777  /* identifiers */
8778  ot->name = "Point Normals to Target";
8779  ot->description = "Point selected custom normals to specified Target";
8780  ot->idname = "MESH_OT_point_normals";
8781 
8782  /* api callbacks */
8789 
8790  /* flags */
8792 
8793  ot->prop = RNA_def_enum(ot->srna,
8794  "mode",
8797  "Mode",
8798  "How to define coordinates to point custom normals to");
8800 
8801  RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert affected normals");
8802 
8803  RNA_def_boolean(ot->srna, "align", false, "Align", "Make all affected normals parallel");
8804 
8806  "target_location",
8807  3,
8808  NULL,
8809  -FLT_MAX,
8810  FLT_MAX,
8811  "Target",
8812  "Target location to which normals will point",
8813  -1000.0f,
8814  1000.0f);
8815 
8817  ot->srna, "spherize", false, "Spherize", "Interpolate between original and new normals");
8818 
8820  "spherize_strength",
8821  0.1,
8822  0.0f,
8823  1.0f,
8824  "Spherize Strength",
8825  "Ratio of spherized normal to original normal",
8826  0.0f,
8827  1.0f);
8828 }
8829 
8832 /* -------------------------------------------------------------------- */
8836 static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
8837 {
8838  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
8839 
8840  BLI_SMALLSTACK_DECLARE(clnors, short *);
8841 
8843 
8845 
8846  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
8848 
8849  if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) {
8850  continue;
8851  }
8852 
8853  MLoopNorSpace *lnor_space = bm->lnor_spacearr->lspacearr[lnor_ed->loop_index];
8854 
8855  if ((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0) {
8856  LinkNode *loops = lnor_space->loops;
8857  float avg_normal[3] = {0.0f, 0.0f, 0.0f};
8858  short *clnors_data;
8859 
8860  for (; loops; loops = loops->next) {
8861  BMLoop *l = loops->link;
8862  const int loop_index = BM_elem_index_get(l);
8863 
8864  BMLoopNorEditData *lnor_ed_tmp = lnors_ed_arr->lidx_to_lnor_editdata[loop_index];
8865  BLI_assert(lnor_ed_tmp->loop_index == loop_index && lnor_ed_tmp->loop == l);
8866  add_v3_v3(avg_normal, lnor_ed_tmp->nloc);
8867  BLI_SMALLSTACK_PUSH(clnors, lnor_ed_tmp->clnors_data);
8869  }
8870  if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
8871  /* If avg normal is nearly 0, set clnor to default value. */
8872  zero_v3(avg_normal);
8873  }
8874  while ((clnors_data = BLI_SMALLSTACK_POP(clnors))) {
8875  BKE_lnor_space_custom_normal_to_data(lnor_space, avg_normal, clnors_data);
8876  }
8877  }
8878  }
8879 }
8880 
8881 static void normals_split(BMesh *bm)
8882 {
8883  BMFace *f;
8884  BMLoop *l, *l_curr, *l_first;
8885  BMIter fiter;
8886 
8888 
8890 
8891  BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
8892 
8893  const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
8894  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
8895  BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
8896 
8897  l_curr = l_first = BM_FACE_FIRST_LOOP(f);
8898  do {
8899  if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
8900  (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
8902  if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
8903  !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
8904  const int loop_index = BM_elem_index_get(l_curr);
8905  short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
8907  bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
8908  }
8909  else {
8910  BMVert *v_pivot = l_curr->v;
8911  UNUSED_VARS_NDEBUG(v_pivot);
8912  BMEdge *e_next;
8913  const BMEdge *e_org = l_curr->e;
8914  BMLoop *lfan_pivot, *lfan_pivot_next;
8915 
8916  lfan_pivot = l_curr;
8917  e_next = lfan_pivot->e;
8918  float avg_normal[3] = {0.0f};
8919 
8920  while (true) {
8921  lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
8922  if (lfan_pivot_next) {
8923  BLI_assert(lfan_pivot_next->v == v_pivot);
8924  }
8925  else {
8926  e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
8927  }
8928 
8929  BLI_SMALLSTACK_PUSH(loop_stack, lfan_pivot);
8930  add_v3_v3(avg_normal, lfan_pivot->f->no);
8931 
8932  if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
8933  break;
8934  }
8935  lfan_pivot = lfan_pivot_next;
8936  }
8937  if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
8938  /* If avg normal is nearly 0, set clnor to default value. */
8939  zero_v3(avg_normal);
8940  }
8941  while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
8942  const int l_index = BM_elem_index_get(l);
8943  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
8945  bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
8946  }
8947  }
8948  }
8949  } while ((l_curr = l_curr->next) != l_first);
8950  }
8951 }
8952 
8953 static int normals_split_merge(bContext *C, const bool do_merge)
8954 {
8955  ViewLayer *view_layer = CTX_data_view_layer(C);
8956  uint objects_len = 0;
8958  view_layer, CTX_wm_view3d(C), &objects_len);
8959 
8960  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
8961  Object *obedit = objects[ob_index];
8962  BMEditMesh *em = BKE_editmesh_from_object(obedit);
8963  BMesh *bm = em->bm;
8964  BMEdge *e;
8965  BMIter eiter;
8966 
8967  BKE_editmesh_ensure_autosmooth(em, obedit->data);
8968  BKE_editmesh_lnorspace_update(em, obedit->data);
8969 
8970  /* Note that we need temp lnor editing data for all loops of all affected vertices, since by
8971  * setting some faces/edges as smooth we are going to change clnors spaces... See also T65809.
8972  */
8973  BMLoopNorEditDataArray *lnors_ed_arr = do_merge ?
8975  NULL;
8976 
8977  mesh_set_smooth_faces(em, do_merge);
8978 
8979  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
8981  BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge);
8982  }
8983  }
8984 
8986  BKE_editmesh_lnorspace_update(em, obedit->data);
8987 
8988  if (do_merge) {
8989  normals_merge(bm, lnors_ed_arr);
8990  }
8991  else {
8992  normals_split(bm);
8993  }
8994 
8995  if (lnors_ed_arr) {
8996  BM_loop_normal_editdata_array_free(lnors_ed_arr);
8997  }
8998 
8999  EDBM_update(obedit->data,
9000  &(const struct EDBMUpdate_Params){
9001  .calc_looptri = true,
9002  .calc_normals = false,
9003  .is_destructive = false,
9004  });
9005  }
9006 
9007  MEM_freeN(objects);
9008  return OPERATOR_FINISHED;
9009 }
9010 
9012 {
9013  return normals_split_merge(C, true);
9014 }
9015 
9017 {
9018  /* identifiers */
9019  ot->name = "Merge Normals";
9020  ot->description = "Merge custom normals of selected vertices";
9021  ot->idname = "MESH_OT_merge_normals";
9022 
9023  /* api callbacks */
9026 
9027  /* flags */
9029 }
9030 
9032 {
9033  return normals_split_merge(C, false);
9034 }
9035 
9037 {
9038  /* identifiers */
9039  ot->name = "Split Normals";
9040  ot->description = "Split custom normals of selected vertices";
9041  ot->idname = "MESH_OT_split_normals";
9042 
9043  /* api callbacks */
9046 
9047  /* flags */
9049 }
9050 
9053 /* -------------------------------------------------------------------- */
9057 enum {
9061 };
9062 
9065  "CUSTOM_NORMAL",
9066  0,
9067  "Custom Normal",
9068  "Take average of vertex normals"},
9070  "FACE_AREA",
9071  0,
9072  "Face Area",
9073  "Set all vertex normals by face area"},
9075  "CORNER_ANGLE",
9076  0,
9077  "Corner Angle",
9078  "Set all vertex normals by corner angle"},
9079  {0, NULL, 0, NULL, NULL},
9080 };
9081 
9083 {
9084  ViewLayer *view_layer = CTX_data_view_layer(C);
9085  uint objects_len = 0;
9087  view_layer, CTX_wm_view3d(C), &objects_len);
9088  const int average_type = RNA_enum_get(op->ptr, "average_type");
9089  const float absweight = (float)RNA_int_get(op->ptr, "weight");
9090  const float threshold = RNA_float_get(op->ptr, "threshold");
9091 
9092  HeapSimple *loop_weight = BLI_heapsimple_new();
9093  BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
9094 
9095  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
9096  BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
9097  BLI_assert(BLI_heapsimple_is_empty(loop_weight));
9098 
9099  Object *obedit = objects[ob_index];
9100  BMEditMesh *em = BKE_editmesh_from_object(obedit);
9101  BMesh *bm = em->bm;
9102  BMFace *f;
9103  BMLoop *l, *l_curr, *l_first;
9104  BMIter fiter;
9105 
9106  BKE_editmesh_ensure_autosmooth(em, obedit->data);
9108  BKE_editmesh_lnorspace_update(em, obedit->data);
9109 
9110  const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
9111 
9112  float weight = absweight / 50.0f;
9113  if (absweight == 100.0f) {
9114  weight = (float)SHRT_MAX;
9115  }
9116  else if (absweight == 1.0f) {
9117  weight = 1 / (float)SHRT_MAX;
9118  }
9119  else if ((weight - 1) * 25 > 1) {
9120  weight = (weight - 1) * 25;
9121  }
9122 
9124 
9125  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9126  l_curr = l_first = BM_FACE_FIRST_LOOP(f);
9127  do {
9128  if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
9129  (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
9130  (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) &&
9131  BM_loop_check_cyclic_smooth_fan(l_curr)))) {
9132  if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
9133  !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
9134  const int loop_index = BM_elem_index_get(l_curr);
9135  short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
9137  bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
9138  }
9139  else {
9140  BMVert *v_pivot = l_curr->v;
9141  UNUSED_VARS_NDEBUG(v_pivot);
9142  BMEdge *e_next;
9143  const BMEdge *e_org = l_curr->e;
9144  BMLoop *lfan_pivot, *lfan_pivot_next;
9145 
9146  lfan_pivot = l_curr;
9147  e_next = lfan_pivot->e;
9148 
9149  while (true) {
9150  lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
9151  if (lfan_pivot_next) {
9152  BLI_assert(lfan_pivot_next->v == v_pivot);
9153  }
9154  else {
9155  e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
9156  }
9157 
9158  float val = 1.0f;
9159  if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) {
9160  val = 1.0f / BM_face_calc_area(lfan_pivot->f);
9161  }
9162  else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) {
9163  val = 1.0f / BM_loop_calc_face_angle(lfan_pivot);
9164  }
9165 
9166  BLI_heapsimple_insert(loop_weight, val, lfan_pivot);
9167 
9168  if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
9169  break;
9170  }
9171  lfan_pivot = lfan_pivot_next;
9172  }
9173 
9174  float wnor[3], avg_normal[3] = {0.0f}, count = 0;
9175  float val = BLI_heapsimple_top_value(loop_weight);
9176 
9177  while (!BLI_heapsimple_is_empty(loop_weight)) {
9178  const float cur_val = BLI_heapsimple_top_value(loop_weight);
9179  if (!compare_ff(val, cur_val, threshold)) {
9180  count++;
9181  val = cur_val;
9182  }
9183  l = BLI_heapsimple_pop_min(loop_weight);
9184  BLI_SMALLSTACK_PUSH(loop_stack, l);
9185 
9186  const float n_weight = pow(weight, count);
9187 
9188  if (average_type == EDBM_CLNOR_AVERAGE_LOOP) {
9189  const int l_index = BM_elem_index_get(l);
9190  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
9192  bm->lnor_spacearr->lspacearr[l_index], clnors, wnor);
9193  }
9194  else {
9195  copy_v3_v3(wnor, l->f->no);
9196  }
9197  mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight));
9198  add_v3_v3(avg_normal, wnor);
9199  }
9200 
9201  if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
9202  /* If avg normal is nearly 0, set clnor to default value. */
9203  zero_v3(avg_normal);
9204  }
9205  while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
9206  const int l_index = BM_elem_index_get(l);
9207  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
9209  bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
9210  }
9211  }
9212  }
9213  } while ((l_curr = l_curr->next) != l_first);
9214  }
9215 
9216  EDBM_update(obedit->data,
9217  &(const struct EDBMUpdate_Params){
9218  .calc_looptri = true,
9219  .calc_normals = false,
9220  .is_destructive = false,
9221  });
9222  }
9223 
9224  BLI_heapsimple_free(loop_weight, NULL);
9225 
9226  MEM_freeN(objects);
9227  return OPERATOR_FINISHED;
9228 }
9229 
9231  PropertyRNA *prop,
9232  void *UNUSED(user_data))
9233 {
9234  const char *prop_id = RNA_property_identifier(prop);
9235  const int average_type = RNA_enum_get(ptr, "average_type");
9236 
9237  /* Only show weight/threshold options when not in loop average type. */
9238  const bool is_clor_average_loop = average_type == EDBM_CLNOR_AVERAGE_LOOP;
9239  if (STREQ(prop_id, "weight")) {
9240  return !is_clor_average_loop;
9241  }
9242  if (STREQ(prop_id, "threshold")) {
9243  return !is_clor_average_loop;
9244  }
9245 
9246  /* Else, show it! */
9247  return true;
9248 }
9249 
9251 {
9252  uiLayout *layout = op->layout;
9254  PointerRNA ptr;
9255 
9256  RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
9257 
9258  uiLayoutSetPropSep(layout, true);
9259 
9260  /* Main auto-draw call */
9261  uiDefAutoButsRNA(layout, &ptr, average_normals_draw_check_prop, NULL, NULL, '\0', false);
9262 }
9263 
9265 {
9266  /* identifiers */
9267  ot->name = "Average Normals";
9268  ot->description = "Average custom normals of selected vertices";
9269  ot->idname = "MESH_OT_average_normals";
9270 
9271  /* api callbacks */
9275 
9276  /* flags */
9278 
9279  ot->prop = RNA_def_enum(ot->srna,
9280  "average_type",
9283  "Type",
9284  "Averaging method");
9285 
9286  RNA_def_int(ot->srna, "weight", 50, 1, 100, "Weight", "Weight applied per face", 1, 100);
9287 
9289  "threshold",
9290  0.01f,
9291  0,
9292  10,
9293  "Threshold",
9294  "Threshold value for different weights to be considered equal",
9295  0,
9296  5);
9297 }
9298 
9301 /* -------------------------------------------------------------------- */
9305 enum {
9311 };
9312 
9314  {EDBM_CLNOR_TOOLS_COPY, "COPY", 0, "Copy Normal", "Copy normal to buffer"},
9315  {EDBM_CLNOR_TOOLS_PASTE, "PASTE", 0, "Paste Normal", "Paste normal from buffer"},
9316  {EDBM_CLNOR_TOOLS_ADD, "ADD", 0, "Add Normal", "Add normal vector with selection"},
9318  "MULTIPLY",
9319  0,
9320  "Multiply Normal",
9321  "Multiply normal vector with selection"},
9323  "RESET",
9324  0,
9325  "Reset Normal",
9326  "Reset buffer and/or normal of selected element"},
9327  {0, NULL, 0, NULL, NULL},
9328 };
9329 
9331 {
9333  ViewLayer *view_layer = CTX_data_view_layer(C);
9334  uint objects_len = 0;
9336  view_layer, CTX_wm_view3d(C), &objects_len);
9337  const int mode = RNA_enum_get(op->ptr, "mode");
9338  const bool absolute = RNA_boolean_get(op->ptr, "absolute");
9339  float *normal_vector = scene->toolsettings->normal_vector;
9340  bool done_copy = false;
9341 
9342  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
9343  Object *obedit = objects[ob_index];
9344  BMEditMesh *em = BKE_editmesh_from_object(obedit);
9345  BMesh *bm = em->bm;
9346 
9347  if (bm->totloop == 0) {
9348  continue;
9349  }
9350 
9351  BKE_editmesh_ensure_autosmooth(em, obedit->data);
9352  BKE_editmesh_lnorspace_update(em, obedit->data);
9354  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
9355 
9356  switch (mode) {
9357  case EDBM_CLNOR_TOOLS_COPY:
9358  if (bm->totfacesel == 0 && bm->totvertsel == 0) {
9359  BM_loop_normal_editdata_array_free(lnors_ed_arr);
9360  continue;
9361  }
9362 
9363  if (done_copy ||
9364  (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1)) {
9365  BKE_report(op->reports,
9366  RPT_ERROR,
9367  "Can only copy one custom normal, vertex normal or face normal");
9368  BM_loop_normal_editdata_array_free(lnors_ed_arr);
9369  continue;
9370  }
9371  if (lnors_ed_arr->totloop == 1) {
9373  }
9374  else if (bm->totfacesel == 1) {
9375  BMFace *f;
9376  BMIter fiter;
9377  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9380  }
9381  }
9382  }
9383  else {
9384  /* 'Vertex' normal, i.e. common set of loop normals on the same vertex,
9385  * only if they are all the same. */
9386  bool are_same_lnors = true;
9387  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9388  if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) {
9389  are_same_lnors = false;
9390  }
9391  }
9392  if (are_same_lnors) {
9394  }
9395  }
9396  done_copy = true;
9397  break;
9398 
9400  if (!absolute) {
9401  if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) {
9402  /* If normal is nearly 0, do nothing. */
9403  break;
9404  }
9405  }
9406  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9407  if (absolute) {
9408  float abs_normal[3];
9409  copy_v3_v3(abs_normal, lnor_ed->loc);
9410  negate_v3(abs_normal);
9411  add_v3_v3(abs_normal, normal_vector);
9412 
9413  if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) {
9414  /* If abs normal is nearly 0, set clnor to initial value. */
9415  copy_v3_v3(abs_normal, lnor_ed->niloc);
9416  }
9418  abs_normal,
9419  lnor_ed->clnors_data);
9420  }
9421  else {
9423  normal_vector,
9424  lnor_ed->clnors_data);
9425  }
9426  }
9427  break;
9428 
9430  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9431  mul_v3_v3(lnor_ed->nloc, normal_vector);
9432 
9433  if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
9434  /* If abs normal is nearly 0, set clnor to initial value. */
9435  copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
9436  }
9438  lnor_ed->nloc,
9439  lnor_ed->clnors_data);
9440  }
9441  break;
9442 
9443  case EDBM_CLNOR_TOOLS_ADD:
9444  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9445  add_v3_v3(lnor_ed->nloc, normal_vector);
9446 
9447  if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
9448  /* If abs normal is nearly 0, set clnor to initial value. */
9449  copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
9450  }
9452  lnor_ed->nloc,
9453  lnor_ed->clnors_data);
9454  }
9455  break;
9456 
9458  zero_v3(normal_vector);
9459  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9461  normal_vector,
9462  lnor_ed->clnors_data);
9463  }
9464  break;
9465 
9466  default:
9467  BLI_assert(0);
9468  break;
9469  }
9470 
9471  BM_loop_normal_editdata_array_free(lnors_ed_arr);
9472 
9473  EDBM_update(obedit->data,
9474  &(const struct EDBMUpdate_Params){
9475  .calc_looptri = true,
9476  .calc_normals = false,
9477  .is_destructive = false,
9478  });
9479  }
9480 
9481  MEM_freeN(objects);
9482  return OPERATOR_FINISHED;
9483 }
9484 
9486  PropertyRNA *prop,
9487  void *UNUSED(user_data))
9488 {
9489  const char *prop_id = RNA_property_identifier(prop);
9490  const int mode = RNA_enum_get(ptr, "mode");
9491 
9492  /* Only show absolute option in paste mode. */
9493  if (STREQ(prop_id, "absolute")) {
9494  return (mode == EDBM_CLNOR_TOOLS_PASTE);
9495  }
9496 
9497  /* Else, show it! */
9498  return true;
9499 }
9500 
9502 {
9503  uiLayout *layout = op->layout;
9505  PointerRNA ptr;
9506 
9507  RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
9508 
9509  /* Main auto-draw call */
9510  uiDefAutoButsRNA(layout, &ptr, normals_tools_draw_check_prop, NULL, NULL, '\0', false);
9511 }
9512 
9514 {
9515  /* identifiers */
9516  ot->name = "Normals Vector Tools";
9517  ot->description = "Custom normals tools using Normal Vector of UI";
9518  ot->idname = "MESH_OT_normals_tools";
9519 
9520  /* api callbacks */
9524 
9525  /* flags */
9527 
9528  ot->prop = RNA_def_enum(ot->srna,
9529  "mode",
9532  "Mode",
9533  "Mode of tools taking input from interface");
9535 
9537  "absolute",
9538  false,
9539  "Absolute Coordinates",
9540  "Copy Absolute coordinates or Normal vector");
9541 }
9542 
9545 /* -------------------------------------------------------------------- */
9550 {
9551  ViewLayer *view_layer = CTX_data_view_layer(C);
9552  uint objects_len = 0;
9554  view_layer, CTX_wm_view3d(C), &objects_len);
9555 
9556  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
9557  Object *obedit = objects[ob_index];
9558  BMEditMesh *em = BKE_editmesh_from_object(obedit);
9559  BMesh *bm = em->bm;
9560  if (bm->totfacesel == 0) {
9561  continue;
9562  }
9563 
9564  BMFace *f;
9565  BMVert *v;
9566  BMEdge *e;
9567  BMLoop *l;
9568  BMIter fiter, viter, eiter, liter;
9569 
9570  const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp");
9571 
9572  BKE_editmesh_ensure_autosmooth(em, obedit->data);
9573  BKE_editmesh_lnorspace_update(em, obedit->data);
9574 
9575  float(*vnors)[3] = MEM_mallocN(sizeof(*vnors) * bm->totvert, __func__);
9576  {
9577  int v_index;
9578  BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, v_index) {
9579  BM_vert_calc_normal_ex(v, BM_ELEM_SELECT, vnors[v_index]);
9580  }
9581  }
9582 
9583  BLI_bitmap *loop_set = BLI_BITMAP_NEW(bm->totloop, __func__);
9584  const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
9585 
9586  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9587  BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
9588  if (!keep_sharp ||
9590  BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
9591  l = BM_face_vert_share_loop(f, v);
9592  const int l_index = BM_elem_index_get(l);
9593  const int v_index = BM_elem_index_get(l->v);
9594 
9595  if (!is_zero_v3(vnors[v_index])) {
9596  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
9598  bm->lnor_spacearr->lspacearr[l_index], vnors[v_index], clnors);
9599 
9601  BLI_BITMAP_ENABLE(loop_set, l_index);
9602  }
9603  else {
9604  LinkNode *loops = bm->lnor_spacearr->lspacearr[l_index]->loops;
9605  for (; loops; loops = loops->next) {
9606  BLI_BITMAP_ENABLE(loop_set, BM_elem_index_get((BMLoop *)loops->link));
9607  }
9608  }
9609  }
9610  }
9611  }
9612  }
9613  }
9614 
9615  int v_index;
9616  BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, v_index) {
9617  BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
9618  if (BLI_BITMAP_TEST(loop_set, BM_elem_index_get(l))) {
9619  const int loop_index = BM_elem_index_get(l);
9620  short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
9622  bm->lnor_spacearr->lspacearr[loop_index], vnors[v_index], clnors);
9623  }
9624  }
9625  }
9626 
9627  MEM_freeN(loop_set);
9628  MEM_freeN(vnors);
9629  EDBM_update(obedit->data,
9630  &(const struct EDBMUpdate_Params){
9631  .calc_looptri = true,
9632  .calc_normals = false,
9633  .is_destructive = false,
9634  });
9635  }
9636 
9637  MEM_freeN(objects);
9638  return OPERATOR_FINISHED;
9639 }
9640 
9642 {
9643  /* identifiers */
9644  ot->name = "Set Normals from Faces";
9645  ot->description = "Set the custom normals from the selected faces ones";
9646  ot->idname = "MESH_OT_set_normals_from_faces";
9647 
9648  /* api callbacks */
9651 
9652  /* flags */
9654 
9655  RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face");
9656 }
9657 
9660 /* -------------------------------------------------------------------- */
9665 {
9666  ViewLayer *view_layer = CTX_data_view_layer(C);
9667  uint objects_len = 0;
9669  view_layer, CTX_wm_view3d(C), &objects_len);
9670 
9671  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
9672  Object *obedit = objects[ob_index];
9673  BMEditMesh *em = BKE_editmesh_from_object(obedit);
9674  BMesh *bm = em->bm;
9675  BMFace *f;
9676  BMLoop *l;
9677  BMIter fiter, liter;
9678 
9679  BKE_editmesh_ensure_autosmooth(em, obedit->data);
9680  BKE_editmesh_lnorspace_update(em, obedit->data);
9682 
9683  float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop,
9684  __func__);
9685 
9686  /* NOTE(@mont29): This is weird choice of operation, taking all loops of faces of current
9687  * vertex. Could lead to some rather far away loops weighting as much as very close ones
9688  * (topologically speaking), with complex polygons.
9689  * Using topological distance here (rather than geometrical one)
9690  * makes sense IMHO, but would rather go with a more consistent and flexible code,
9691  * we could even add max topological distance to take into account, and a weighting curve.
9692  * Would do that later though, think for now we can live with that choice. */
9693  BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
9694  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9695  l = lnor_ed->loop;
9696  float loop_normal[3];
9697 
9698  BM_ITER_ELEM (f, &fiter, l->v, BM_FACES_OF_VERT) {
9699  BMLoop *l_other;
9700  BM_ITER_ELEM (l_other, &liter, f, BM_LOOPS_OF_FACE) {
9701  const int l_index_other = BM_elem_index_get(l_other);
9702  short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset);
9704  bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal);
9705  add_v3_v3(smooth_normal[i], loop_normal);
9706  }
9707  }
9708  }
9709 
9710  const float factor = RNA_float_get(op->ptr, "factor");
9711 
9712  lnor_ed = lnors_ed_arr->lnor_editdata;
9713  for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
9714  float current_normal[3];
9715 
9716  if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) {
9717  /* Skip in case the smooth normal is invalid. */
9718  continue;
9719  }
9720 
9722  bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal);
9723 
9724  /* NOTE: again, this is not true spherical interpolation that normals would need...
9725  * But it's probably good enough for now. */
9726  mul_v3_fl(current_normal, 1.0f - factor);
9727  mul_v3_fl(smooth_normal[i], factor);
9728  add_v3_v3(current_normal, smooth_normal[i]);
9729 
9730  if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) {
9731  /* Skip in case the smoothed normal is invalid. */
9732  continue;
9733  }
9734 
9736  bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data);
9737  }
9738 
9739  BM_loop_normal_editdata_array_free(lnors_ed_arr);
9740  MEM_freeN(smooth_normal);
9741 
9742  EDBM_update(obedit->data,
9743  &(const struct EDBMUpdate_Params){
9744  .calc_looptri = true,
9745  .calc_normals = false,
9746  .is_destructive = false,
9747  });
9748  }
9749 
9750  MEM_freeN(objects);
9751  return OPERATOR_FINISHED;
9752 }
9753 
9755 {
9756  /* identifiers */
9757  ot->name = "Smooth Normals Vectors";
9758  ot->description = "Smooth custom normals based on adjacent vertex normals";
9759  ot->idname = "MESH_OT_smooth_normals";
9760 
9761  /* api callbacks */
9764 
9765  /* flags */
9767 
9769  "factor",
9770  0.5f,
9771  0.0f,
9772  1.0f,
9773  "Factor",
9774  "Specifies weight of smooth vs original normal",
9775  0.0f,
9776  1.0f);
9777 }
9778 
9781 /* -------------------------------------------------------------------- */
9786 {
9787  ViewLayer *view_layer = CTX_data_view_layer(C);
9788  uint objects_len = 0;
9790  view_layer, CTX_wm_view3d(C), &objects_len);
9791 
9792  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
9793  Object *obedit = objects[ob_index];
9794  BMEditMesh *em = BKE_editmesh_from_object(obedit);
9795  BMesh *bm = em->bm;
9796  BMFace *f;
9797  BMIter fiter;
9798  const int face_strength = RNA_enum_get(op->ptr, "face_strength");
9799  const bool set = RNA_boolean_get(op->ptr, "set");
9800 
9802 
9803  const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
9804  int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT32, layer_id);
9805  if (cd_prop_int_index == -1) {
9807  cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT32, layer_id);
9808  }
9809  cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT32);
9810  const int cd_prop_int_offset = CustomData_get_n_offset(
9811  &bm->pdata, CD_PROP_INT32, cd_prop_int_index);
9812 
9814 
9815  if (set) {
9816  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9818  int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
9819  *strength = face_strength;
9820  }
9821  }
9822  }
9823  else {
9824  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
9825  int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
9826  if (*strength == face_strength) {
9827  BM_face_select_set(bm, f, true);
9829  }
9830  else {
9831  BM_face_select_set(bm, f, false);
9832  }
9833  }
9834  }
9835 
9836  EDBM_update(obedit->data,
9837  &(const struct EDBMUpdate_Params){
9838  .calc_looptri = false,
9839  .calc_normals = false,
9840  .is_destructive = false,
9841  });
9842  }
9843 
9844  MEM_freeN(objects);
9845  return OPERATOR_FINISHED;
9846 }
9847 
9849  {FACE_STRENGTH_WEAK, "WEAK", 0, "Weak", ""},
9850  {FACE_STRENGTH_MEDIUM, "MEDIUM", 0, "Medium", ""},
9851  {FACE_STRENGTH_STRONG, "STRONG", 0, "Strong", ""},
9852  {0, NULL, 0, NULL, NULL},
9853 };
9854 
9856 {
9857  /* identifiers */
9858  ot->name = "Face Normals Strength";
9859  ot->description = "Set/Get strength of face (used in Weighted Normal modifier)";
9860  ot->idname = "MESH_OT_mod_weighted_strength";
9861 
9862  /* api callbacks */
9865 
9866  /* flags */
9868 
9869  ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set Value", "Set value of faces");
9870 
9871  ot->prop = RNA_def_enum(
9872  ot->srna,
9873  "face_strength",
9876  "Face Strength",
9877  "Strength to use for assigning or selecting face influence for weighted normal modifier");
9878 }
9879 
typedef float(TangentPoint)[2]
Generic geometry attributes built on CustomData.
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
struct CustomDataLayer * BKE_id_attributes_active_color_get(const struct ID *id)
int BKE_id_attribute_to_index(const struct ID *id, const CustomDataLayer *layer, eAttrDomainMask domain_mask, eCustomDataMask layer_mask)
eAttrDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer)
#define ATTR_DOMAIN_MASK_COLOR
Definition: BKE_attribute.h:48
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:269
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
#define CTX_DATA_END
Definition: BKE_context.h:278
CustomData interface, see also DNA_customdata_types.h.
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.
int BKE_object_defgroup_active_index_get(const struct Object *ob)
float BKE_defvert_find_weight(const struct MDeformVert *dvert, int defgroup)
Definition: deform.c:704
void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me)
Definition: editmesh.c:276
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me)
Definition: editmesh.c:297
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
struct KeyBlock * BKE_keyblock_find_name(struct Key *key, const char name[])
Definition: key.c:1930
#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:536
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:542
#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:546
bool BKE_id_is_editable(const struct Main *bmain, const struct ID *id)
void id_us_plus(struct ID *id)
Definition: lib_id.c:305
General operations, lookup, etc. for materials.
struct Material *** BKE_object_material_array_p(struct Object *ob)
Definition: material.c:311
struct Material *** BKE_id_material_array_p(struct ID *id)
Definition: material.c:377
short * BKE_id_material_len_p(struct ID *id)
Definition: material.c:403
void BKE_object_material_resize(struct Main *bmain, struct Object *ob, short totcol, bool do_id_user)
Definition: material.c:819
void BKE_object_material_array_assign(struct Main *bmain, struct Object *ob, struct Material ***matar, int totcol, bool to_object_only)
Definition: material.c:1173
void BKE_id_material_clear(struct Main *bmain, struct ID *id)
Definition: material.c:621
short * BKE_object_material_len_p(struct Object *ob)
Definition: material.c:344
void BKE_id_material_resize(struct Main *bmain, struct ID *id, short totcol, bool do_id_user)
Definition: material.c:528
@ MLNOR_SPACEARR_BMLOOP_PTR
Definition: BKE_mesh.h:572
@ MLNOR_SPACE_IS_SINGLE
Definition: BKE_mesh.h:553
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])
General operations, lookup, etc. for blender objects.
struct Mesh * BKE_object_get_original_mesh(const struct Object *object)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:64
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
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:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1
int BLI_listbase_count_at_most(const struct ListBase *listbase, 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, 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 float min_ff(float a, float b)
MINLINE int mod_i(int i, int n)
#define M_PI
Definition: BLI_math_base.h:20
MINLINE int compare_ff(float a, float b, float max_diff)
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:5845
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
#define DEG2RADF(_deg)
MINLINE bool compare_v3v3(const float a[3], const float b[3], float limit) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:867
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
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
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
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:237
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:361
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:58
struct RNG * BLI_rng_new_srandom(unsigned int seed)
Definition: rand.cc:46
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: rand.cc:93
int BLI_sortutil_cmp_float_reverse(const void *a_, const void *b_)
Definition: sort_utils.c:38
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:67
#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_LEGACY
#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:818
@ ID_RECALC_GEOMETRY_ALL_MODES
Definition: DNA_ID.h:884
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
#define CD_MASK_COLOR_ALL
@ CD_CUSTOMLOOPNORMAL
@ CD_MDEFORMVERT
@ CD_PROP_INT32
@ CD_FREESTYLE_EDGE
@ CD_SHAPEKEY
@ CD_FREESTYLE_FACE
#define MAXMAT
@ ME_EDIT_MIRROR_TOPO
@ ME_SYMMETRY_X
@ FREESTYLE_EDGE_MARK
@ FREESTYLE_FACE_MARK
@ eModifierMode_Realtime
@ MOD_TRIANGULATE_NGON_BEAUTY
@ eModifierType_Mirror
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID
@ MOD_MIR_AXIS_Z
@ MOD_MIR_CLIPPING
@ MOD_MIR_AXIS_X
@ MOD_MIR_AXIS_Y
@ MOD_TRIANGULATE_QUAD_BEAUTY
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 void EDBM_redo_state_restore_and_free(struct BMBackup *backup, struct BMEditMesh *em, bool recalc_looptri) ATTR_NONNULL(1
bool EDBM_select_pick(struct bContext *C, const int mval[2], const struct SelectPick_Params *params)
void EDBM_verts_mirror_apply(struct BMEditMesh *em, int sel_from, int sel_to)
void EDBM_mesh_stats_multi(struct Object **objects, uint objects_len, int totelem[3], int totelem_sel[3])
Definition: meshtools.cc:1483
void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params)
void ED_mesh_geometry_clear(struct Mesh *mesh)
Definition: mesh_data.cc:1368
bool EDBM_mesh_hide(struct BMEditMesh *em, bool swap)
struct BMBackup EDBM_redo_state_store(struct BMEditMesh *em)
bool EDBM_selectmode_disable_multi_ex(struct Scene *scene, struct Base **bases, uint bases_len, short selectmode_disable, short selectmode_fallback)
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, int axis, bool use_self, bool use_select, bool respecthide, bool use_topology, float maxdist, int *r_index)
void EDBM_select_flush(struct BMEditMesh *em)
void EDBM_automerge(struct Object *ob, bool update, char hflag, float dist)
void EDBM_verts_mirror_cache_end(struct BMEditMesh *em)
void EDBM_flag_disable_all(struct BMEditMesh *em, char hflag)
bool EDBM_mesh_reveal(struct BMEditMesh *em, bool select)
void EDBM_verts_mirror_cache_begin(struct BMEditMesh *em, int axis, bool use_self, bool use_select, bool respecthide, bool use_topology)
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, short selectmode)
void void void EDBM_redo_state_free(struct BMBackup *backup) ATTR_NONNULL(1)
void EDBM_selectmode_flush(struct BMEditMesh *em)
void EDBM_mesh_normals_update(struct BMEditMesh *em)
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:76
struct Base * ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, eDupli_ID_Flags dupflag)
Definition: object_add.cc:3632
@ BA_SELECT
Definition: ED_object.h:155
bool ED_object_calc_active_center_for_editmode(struct Object *obedit, bool select_only, float r_center[3])
Definition: object_utils.c:41
void ED_outliner_select_sync_from_object_tag(struct bContext *C)
void ED_area_status_text(ScrArea *area, const char *str)
Definition: area.c:792
bool ED_operator_editmesh(struct bContext *C)
Definition: screen_ops.c:433
bool ED_operator_scene_editable(struct bContext *C)
Definition: screen_ops.c:177
@ SEL_OP_SET
@ TFM_TRANSLATION
Definition: ED_transform.h:30
void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, int objects_len)
@ V3D_PROJ_TEST_CLIP_NEAR
Definition: ED_view3d.h:237
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])
void ED_view3d_cursor3d_update(struct bContext *C, const int mval[2], bool use_depth, enum eV3DCursorOrient orientation)
Definition: view3d_edit.c:984
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:217
@ V3D_CURSOR_ORIENT_NONE
Definition: ED_view3d.h:86
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void view3d_operator_needs_opengl(const struct bContext *C)
struct RegionView3D * ED_view3d_context_rv3d(struct bContext *C)
Definition: space_view3d.c:82
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:166
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:543
#define RNA_END
Definition: RNA_access.h:550
@ PROP_ENUM
Definition: RNA_types.h:63
@ PROP_NEVER_UNLINK
Definition: RNA_types.h:246
@ PROP_ENUM_NO_TRANSLATE
Definition: RNA_types.h:294
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
@ PROP_NONE
Definition: RNA_types.h:126
#define C
Definition: RandGen.cpp:25
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
void uiLayoutSetActive(uiLayout *layout, bool active)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
@ UI_ITEM_R_EXPAND
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:91
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
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, bool compact)
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
@ OPTYPE_INTERNAL
Definition: WM_types.h:168
@ OPTYPE_BLOCKING
Definition: WM_types.h:150
@ OPTYPE_DEPENDS_ON_CURSOR
Definition: WM_types.h:184
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DRAW
Definition: WM_types.h:410
#define ND_DATA
Definition: WM_types.h:456
#define ND_SELECT
Definition: WM_types.h:455
#define NC_OBJECT
Definition: WM_types.h:329
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
#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:625
#define BM_ALL_NOLOOP
Definition: bmesh_class.h:411
#define BM_ALL
Definition: bmesh_class.h:410
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ 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_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
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:2234
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:939
void BM_face_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:828
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:123
void BM_mesh_decimate_collapse(BMesh *bm, float factor, float *vweights, float vweight_factor, bool do_triangulate, int symmetry_axis, float symmetry_eps)
BM_mesh_decimate.
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type)
Definition: bmesh_delete.c:258
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)
@ BMO_ERROR_FATAL
Definition: bmesh_error.h:34
@ BMO_ERROR_CANCEL
Definition: bmesh_error.h:21
bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level)
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:111
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:13
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
Definition: bmesh_interp.c:839
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
Definition: bmesh_interp.c:857
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_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.cc:23
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
Definition: bmesh_mesh.cc:726
void BM_mesh_elem_toolflags_ensure(BMesh *bm)
Definition: bmesh_mesh.cc:75
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
Definition: bmesh_mesh.cc:258
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
Definition: bmesh_mesh.cc:125
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:558
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:103
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
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 BM_lnorspace_update(BMesh *bm)
void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges)
bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
void BM_mesh_normals_update(BMesh *bm)
BMLoopNorEditDataArray * BM_loop_normal_editdata_array_init(BMesh *bm, const bool do_all_loops_of_vert)
void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges)
@ BMO_SYMMETRIZE_NEGATIVE_X
void * BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int len)
void * BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
BMO_FLAG_BUFFER.
void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
BMO_FLAG_BUFFER.
@ DEL_ONLYTAGGED
@ DEL_FACES_KEEP_BOUNDARY
@ DEL_EDGESFACES
@ DEL_EDGES
@ DEL_FACES
@ DEL_ONLYFACES
@ DEL_VERTS
void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float f)
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
#define BMO_edge_flag_set(bm, e, oflag, val)
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
@ BMO_FLAG_RESPECT_HIDE
void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int i)
void BMO_op_init(BMesh *bm, BMOperator *op, int flag, const char *opname)
BMESH OPSTACK INIT OP.
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt,...)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
#define BMO_FLAG_DEFAULTS
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, bool i)
@ BMO_DELIM_NORMAL
BLI_INLINE void BMO_slot_map_float_insert(BMOperator *op, BMOpSlot *slot, void *element, const float val)
void BM_mesh_esubdivide(BMesh *bm, char edge_hflag, float smooth, short smooth_falloff, bool use_smooth_even, float fractal, float along_normal, int numcuts, int seltype, int cornertype, short use_single_edge, short use_grid_fill, short use_only_quads, int seed)
@ FACE_STRENGTH_STRONG
@ FACE_STRENGTH_WEAK
@ FACE_STRENGTH_MEDIUM
@ SUBDIV_SELECT_ORIG
@ SUBD_RING_INTERP_SURF
@ SUBD_RING_INTERP_PATH
@ SUBD_RING_INTERP_LINEAR
@ SUBD_CORNER_FAN
@ SUBD_CORNER_STRAIGHT_CUT
@ SUBD_CORNER_PATH
@ SUBD_CORNER_INNERVERT
@ SUBD_FALLOFF_LIN
@ BMOP_POKE_MEDIAN_WEIGHTED
@ BMOP_POKE_BOUNDS
@ BMOP_POKE_MEDIAN
void BM_vert_normal_update(BMVert *v)
bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3])
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:2367
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1553
bool BM_vert_is_wire(const BMVert *v)
Definition: bmesh_query.c:688
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:193
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
Definition: bmesh_query.c:538
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1115
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
Definition: bmesh_query.c:1036
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
BMESH EDGE/FACE ANGLE.
Definition: bmesh_query.c:1329
float BM_loop_calc_face_angle(const BMLoop *l)
Definition: bmesh_query.c:1192
BMLoop * BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
Definition: bmesh_query.c:461
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
Definition: bmesh_query.c:1100
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:116
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
int len
Definition: draw_manager.c:108
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)
@ EDBM_CLNOR_AVERAGE_LOOP
@ EDBM_CLNOR_AVERAGE_FACE_AREA
@ EDBM_CLNOR_AVERAGE_ANGLE
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)
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)
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)
@ MESH_MERGE_LAST
@ MESH_MERGE_CENTER
@ MESH_MERGE_CURSOR
@ MESH_MERGE_FIRST
@ MESH_MERGE_COLLAPSE
void MESH_OT_delete(wmOperatorType *ot)
static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
@ MESH_SEPARATE_LOOSE
@ MESH_SEPARATE_MATERIAL
@ MESH_SEPARATE_SELECTED
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)
static void edbm_average_normals_ui(bContext *C, wmOperator *op)
@ EDBM_CLNOR_POINTTO_MODE_MOUSE
@ EDBM_CLNOR_POINTTO_MODE_COORDINATES
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)
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)
#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)
static void edbm_decimate_ui(bContext *UNUSED(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 void edbm_flip_normals_custom_loop_normals(Object *obedit, BMEditMesh *em)
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)
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[]
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))
@ MESH_BRIDGELOOP_PAIRS
@ MESH_BRIDGELOOP_SINGLE
@ MESH_BRIDGELOOP_CLOSED
@ 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_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)
static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
static int normals_split_merge(bContext *C, const bool do_merge)
static void edbm_flip_normals_face_winding(wmOperator *op, Object *obedit, BMEditMesh *em)
static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
@ SRT_VIEW_XAXIS
@ SRT_SELECTED
@ SRT_RANDOMIZE
@ SRT_MATERIAL
@ SRT_CURSOR_DISTANCE
@ SRT_REVERSE
@ SRT_VIEW_ZAXIS
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)
@ EDBM_CLNOR_TOOLS_RESET
@ EDBM_CLNOR_TOOLS_COPY
@ EDBM_CLNOR_TOOLS_ADD
@ EDBM_CLNOR_TOOLS_MULTIPLY
@ EDBM_CLNOR_TOOLS_PASTE
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)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int count
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
static char ** types
Definition: makesdna.c:67
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float3 pow(float3 v, float e)
Definition: math_float3.h:533
static ulong * next
static char faces[256]
void MESH_OT_convex_hull(struct wmOperatorType *ot)
#define fabsf(x)
Definition: metal/compat.h:219
static void clear(Message *msg)
Definition: msgfmt.c:278
static unsigned a[3]
Definition: RandGen.cpp:78
SocketIndexByIdentifierMap * map
smooth(Type::FLOAT, "mask_weight")
const btScalar eps
Definition: poly34.cpp:11
return ret
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2767
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:2449
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
Definition: rna_access.c:2879
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
int RNA_collection_length(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5239
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2153
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2429
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
Definition: rna_access.c:2180
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
Definition: rna_access.c:2978
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3402
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:5015
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
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:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
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:3806
void RNA_def_property_float_default(PropertyRNA *prop, float value)
Definition: rna_define.c:2022
void RNA_def_property_enum_default(PropertyRNA *prop, int value)
Definition: rna_define.c:2106
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:4052
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description)
Definition: rna_define.c:1645
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
Definition: rna_define.c:4221
void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item)
Definition: rna_define.c:1872
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:4144
PropertyRNA * RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier, int type, int subtype)
Definition: rna_define.c:1257
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4487
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4436
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
Definition: rna_define.c:2848
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:3894
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
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:3597
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3830
void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item, int value)
Definition: rna_define.c:4472
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
Definition: rna_define.c:1664
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:4016
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:3783
const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]
Definition: rna_mesh.c:36
const EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[]
Definition: rna_modifier.c:333
const EnumPropertyItem rna_enum_axis_xyz_items[]
Definition: rna_modifier.c:615
const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[]
Definition: rna_modifier.c:304
const EnumPropertyItem DummyRNA_NULL_items[]
Definition: rna_rna.c:26
const EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[]
Definition: rna_scene.c:120
const EnumPropertyItem rna_enum_symmetrize_direction_items[]
#define min(a, b)
Definition: sort.c:35
void * regiondata
BMHeader head
Definition: bmesh_class.h:111
BMVert * v1
Definition: bmesh_class.h:122
BMVert * v2
Definition: bmesh_class.h:122
struct BMLoop * l
Definition: bmesh_class.h:128
short selectmode
Definition: BKE_editmesh.h:52
struct BMesh * bm
Definition: BKE_editmesh.h:40
short mat_nr
Definition: BKE_editmesh.h:54
struct BMEditSelection * next
Definition: bmesh_marking.h:10
struct BMEditSelection * prev
Definition: bmesh_marking.h:10
BMHeader head
Definition: bmesh_class.h:243
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:267
BMHeader head
Definition: bmesh_class.h:255
float no[3]
Definition: bmesh_class.h:271
char htype
Definition: bmesh_class.h:64
void * data
Definition: bmesh_class.h:51
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:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:87
struct BMEdge * e
Definition: bmesh_class.h:97
BMHeader head
Definition: bmesh_class.h:85
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:461
const char * name
Definition: RNA_types.h:465
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
char name[64]
Definition: DNA_key_types.h:52
short relative
Definition: DNA_key_types.h:41
ListBase block
Definition: DNA_key_types.h:84
void * data
Definition: DNA_listBase.h:26
struct LinkData * next
Definition: DNA_listBase.h:25
void * link
Definition: BLI_linklist.h:24
struct LinkNode * next
Definition: BLI_linklist.h:23
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
MLoopNorSpace ** lspacearr
Definition: BKE_mesh.h:560
struct LinkNode * loops
Definition: BKE_mesh.h:543
Definition: BKE_main.h:121
struct BMEditMesh * edit_mesh
char editflag
struct Key * key
ListBase modifiers
struct Material ** mat
float loc[3]
char * matbits
float imat[4][4]
float obmat[4][4]
void * data
Definition: rand.cc:33
float viewmat[4][4]
struct ToolSettings * toolsettings
View3DCursor cursor
char transform_pivot_point
float normal_vector[3]
short val
Definition: WM_types.h:680
int mval[2]
Definition: WM_types.h:684
short type
Definition: WM_types.h:678
const void * modal_items
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
bool(* poll_property)(const struct bContext *C, struct wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:949
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
void(* ui)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:954
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:911
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
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
void WM_cursor_wait(bool val)
Definition: wm_cursors.c:209
@ WM_CURSOR_KNIFE
Definition: wm_cursors.h:31
@ WM_CURSOR_NUM
Definition: wm_cursors.h:64
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)
#define ISMOUSE_MOTION(event_type)
@ EVT_MODAL_MAP
@ MOUSEMOVE
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
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:2052
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))