Blender  V3.3
editmesh_loopcut.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2007 Blender Foundation. All rights reserved. */
3 
8 #include "DNA_object_types.h"
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "BLI_math.h"
13 #include "BLI_string.h"
14 
15 #include "BLT_translation.h"
16 
17 #include "DNA_mesh_types.h"
18 
19 #include "BKE_context.h"
20 #include "BKE_editmesh.h"
21 #include "BKE_layer.h"
22 #include "BKE_modifier.h"
23 #include "BKE_report.h"
24 #include "BKE_unit.h"
25 
26 #include "UI_interface.h"
27 
28 #include "ED_mesh.h"
29 #include "ED_numinput.h"
30 #include "ED_screen.h"
31 #include "ED_space_api.h"
32 #include "ED_view3d.h"
33 
34 #include "RNA_access.h"
35 #include "RNA_define.h"
36 #include "RNA_enum_types.h"
37 
38 #include "WM_api.h"
39 #include "WM_types.h"
40 
41 #include "DEG_depsgraph.h"
42 #include "DEG_depsgraph_query.h"
43 
44 #include "mesh_intern.h" /* own include */
45 
46 #define SUBD_SMOOTH_MAX 4.0f
47 #define SUBD_CUTS_MAX 500
48 
49 /* ringsel operator */
50 
53  const float (*coords)[3];
54 };
55 
56 /* struct for properties used while drawing */
57 typedef struct RingSelOpData {
58  ARegion *region; /* region that ringsel was activated in */
59  void *draw_handle; /* for drawing preview loop */
60 
62 
64 
66 
69 
71 
72  /* These values switch objects based on the object under the cursor. */
77 
79 
80  bool extend;
81  bool do_cut;
82 
83  float cuts; /* cuts as float so smooth mouse pan works in small increments */
84  float smoothness;
86 
87 /* modal loop selection drawing callback */
88 static void ringsel_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
89 {
90  RingSelOpData *lcd = arg;
92 }
93 
94 static void edgering_select(RingSelOpData *lcd)
95 {
96  if (!lcd->eed) {
97  return;
98  }
99 
100  if (!lcd->extend) {
101  for (uint base_index = 0; base_index < lcd->bases_len; base_index++) {
102  Object *ob_iter = lcd->bases[base_index]->object;
103  BMEditMesh *em = BKE_editmesh_from_object(ob_iter);
107  }
108  }
109 
110  BMEditMesh *em = lcd->em;
111  BMEdge *eed_start = lcd->eed;
112  BMWalker walker;
113  BMEdge *eed;
114  BMW_init(&walker,
115  em->bm,
116  BMW_EDGERING,
117  BMW_MASK_NOP,
118  BMW_MASK_NOP,
119  BMW_MASK_NOP,
121  BMW_NIL_LAY);
122 
123  for (eed = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
124  BM_edge_select_set(em->bm, eed, true);
125  }
126  BMW_end(&walker);
127 }
128 
129 static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines)
130 {
131  if (lcd->eed) {
132  struct MeshCoordsCache *gcache = &lcd->geom_cache[lcd->base_index];
133  if (gcache->is_init == false) {
134  Scene *scene_eval = (Scene *)DEG_get_evaluated_id(lcd->vc.depsgraph, &lcd->vc.scene->id);
135  Object *ob_eval = DEG_get_evaluated_object(lcd->vc.depsgraph, lcd->ob);
136  BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
138  lcd->vc.depsgraph, em_eval, scene_eval, ob_eval, NULL, &gcache->is_alloc);
139  gcache->is_init = true;
140  }
141 
143  lcd->presel_edgering, lcd->em->bm, lcd->eed, previewlines, gcache->coords);
144  }
145  else {
147  }
148 }
149 
151 {
152  RingSelOpData *lcd = op->customdata;
153  const int cuts = RNA_int_get(op->ptr, "number_cuts");
154  const float smoothness = RNA_float_get(op->ptr, "smoothness");
155  const int smooth_falloff = RNA_enum_get(op->ptr, "falloff");
156 #ifdef BMW_EDGERING_NGON
157  const bool use_only_quads = false;
158 #else
159  const bool use_only_quads = false;
160 #endif
161 
162  if (lcd->eed) {
163  BMEditMesh *em = lcd->em;
164  BMVert *v_eed_orig[2] = {lcd->eed->v1, lcd->eed->v2};
165 
166  edgering_select(lcd);
167 
168  if (lcd->do_cut) {
169  const bool is_macro = (op->opm != NULL);
170  /* a single edge (rare, but better support) */
171  const bool is_edge_wire = BM_edge_is_wire(lcd->eed);
172  const bool is_single = is_edge_wire || !BM_edge_is_any_face_len_test(lcd->eed, 4);
173  const int seltype = is_edge_wire ? SUBDIV_SELECT_INNER :
174  is_single ? SUBDIV_SELECT_NONE :
176 
177  /* Enable grid-fill, so that intersecting loop-cut works as one would expect.
178  * Note though that it will break edge-slide in this specific case.
179  * See T31939. */
182  smoothness,
183  smooth_falloff,
184  true,
185  0.0f,
186  0.0f,
187  cuts,
188  seltype,
190  0,
191  true,
192  use_only_quads,
193  0);
194 
195  /* when used in a macro the tessfaces will be recalculated anyway,
196  * this is needed here because modifiers depend on updated tessellation, see T45920 */
197  EDBM_update(lcd->ob->data,
198  &(const struct EDBMUpdate_Params){
199  .calc_looptri = true,
200  .calc_normals = false,
201  .is_destructive = true,
202  });
203 
204  if (is_single) {
205  /* de-select endpoints */
206  BM_vert_select_set(em->bm, v_eed_orig[0], false);
207  BM_vert_select_set(em->bm, v_eed_orig[1], false);
208 
210  }
211  /* We can't slide multiple edges in vertex select mode, force edge select mode. Do this for
212  * all meshes in multi-object editmode so their selectmode is in sync for following
213  * operators. */
214  else if (is_macro && (cuts > 1) && (em->selectmode & SCE_SELECT_VERTEX)) {
216  }
217  /* Force edge slide to edge select mode in face select mode. Do this for all meshes in
218  * multi-object editmode so their selectmode is in sync for following operators. */
220  /* pass, the change will flush selection */
221  }
222  else {
223  /* else flush explicitly */
225  }
226  }
227  else {
228  /* XXX Is this piece of code ever used now? Simple loop select is now
229  * in editmesh_select.c (around line 1000)... */
230  /* sets as active, useful for other tools */
231  if (em->selectmode & SCE_SELECT_VERTEX) {
232  /* low priority TODO: get vertrex close to mouse. */
233  BM_select_history_store(em->bm, lcd->eed->v1);
234  }
235  if (em->selectmode & SCE_SELECT_EDGE) {
236  BM_select_history_store(em->bm, lcd->eed);
237  }
238 
242  }
243  }
244 }
245 
246 /* called when modal loop selection is done... */
248 {
249  RingSelOpData *lcd = op->customdata;
250 
251  /* deactivate the extra drawing stuff in 3D-View */
253 
255 
256  for (uint i = 0; i < lcd->bases_len; i++) {
257  struct MeshCoordsCache *gcache = &lcd->geom_cache[i];
258  if (gcache->is_alloc) {
259  MEM_freeN((void *)gcache->coords);
260  }
261  }
262  MEM_freeN(lcd->geom_cache);
263 
264  MEM_freeN(lcd->bases);
265 
267 
268  /* free the custom data */
269  MEM_freeN(lcd);
270  op->customdata = NULL;
271 }
272 
273 /* called when modal loop selection gets set up... */
274 static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
275 {
276  RingSelOpData *lcd;
278 
279  /* alloc new customdata */
280  lcd = op->customdata = MEM_callocN(sizeof(RingSelOpData), "ringsel Modal Op Data");
281 
282  em_setup_viewcontext(C, &lcd->vc);
283 
285 
286  /* assign the drawing handle for drawing preview line... */
287  lcd->region = CTX_wm_region(C);
291  /* Initialize once the cursor is over a mesh. */
292  lcd->ob = NULL;
293  lcd->em = NULL;
294  lcd->extend = do_cut ? false : RNA_boolean_get(op->ptr, "extend");
295  lcd->do_cut = do_cut;
296  lcd->cuts = RNA_int_get(op->ptr, "number_cuts");
297  lcd->smoothness = RNA_float_get(op->ptr, "smoothness");
298 
299  initNumInput(&lcd->num);
300  lcd->num.idx_max = 1;
302  /* No specific flags for smoothness. */
303  lcd->num.unit_sys = scene->unit.system;
304  lcd->num.unit_type[0] = B_UNIT_NONE;
305  lcd->num.unit_type[1] = B_UNIT_NONE;
306 
308 
309  return 1;
310 }
311 
313 {
314  /* this is just a wrapper around exit() */
315  ringsel_exit(C, op);
316 }
317 
319  uint base_index,
320  BMEdge *e,
321  const int previewlines)
322 {
323  if (e != lcd->eed) {
324  lcd->eed = e;
325  lcd->ob = lcd->vc.obedit;
326  lcd->base_index = base_index;
327  lcd->em = lcd->vc.em;
328  ringsel_find_edge(lcd, previewlines);
329  }
330  else if (e == NULL) {
331  lcd->ob = NULL;
332  lcd->em = NULL;
333  lcd->base_index = UINT_MAX;
334  }
335 }
336 
337 static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines)
338 {
339  struct {
340  Object *ob;
341  BMEdge *eed;
342  float dist;
343  int base_index;
344  } best = {
345  .dist = ED_view3d_select_dist_px(),
346  };
347 
348  uint base_index;
349  BMEdge *eed_test = EDBM_edge_find_nearest_ex(
350  &lcd->vc, &best.dist, NULL, false, false, NULL, lcd->bases, lcd->bases_len, &base_index);
351 
352  if (eed_test) {
353  best.ob = lcd->bases[base_index]->object;
354  best.eed = eed_test;
355  best.base_index = base_index;
356  }
357 
358  if (best.eed) {
359  ED_view3d_viewcontext_init_object(&lcd->vc, best.ob);
360  }
361 
362  loopcut_update_edge(lcd, best.base_index, best.eed, previewlines);
363 }
364 
365 /* called by both init() and exec() */
366 static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
367 {
368  const bool is_interactive = (event != NULL);
369 
370  /* Use for redo - intentionally wrap int to uint. */
371  const struct {
372  uint base_index;
373  uint e_index;
374  } exec_data = {
375  .base_index = (uint)RNA_int_get(op->ptr, "object_index"),
376  .e_index = (uint)RNA_int_get(op->ptr, "edge_index"),
377  };
378 
379  ViewLayer *view_layer = CTX_data_view_layer(C);
380 
381  uint bases_len;
383  view_layer, CTX_wm_view3d(C), &bases_len);
384 
385  if (is_interactive) {
386  for (uint base_index = 0; base_index < bases_len; base_index++) {
387  Object *ob_iter = bases[base_index]->object;
390  BKE_report(
391  op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display");
392  break;
393  }
394  }
395  }
396 
398 
399  /* for re-execution, check edge index is in range before we setup ringsel */
400  bool ok = true;
401  if (is_interactive == false) {
402  if (exec_data.base_index >= bases_len) {
403  ok = false;
404  }
405  else {
406  Object *ob_iter = bases[exec_data.base_index]->object;
407  BMEditMesh *em = BKE_editmesh_from_object(ob_iter);
408  if (exec_data.e_index >= em->bm->totedge) {
409  ok = false;
410  }
411  }
412  }
413 
414  if (!ok || !ringsel_init(C, op, true)) {
415  MEM_freeN(bases);
416  return OPERATOR_CANCELLED;
417  }
418 
419  /* add a modal handler for this operator - handles loop selection */
420  if (is_interactive) {
423  }
424 
425  RingSelOpData *lcd = op->customdata;
426 
427  lcd->bases = bases;
428  lcd->bases_len = bases_len;
429  lcd->geom_cache = MEM_callocN(sizeof(*lcd->geom_cache) * bases_len, __func__);
430 
431  if (is_interactive) {
432  copy_v2_v2_int(lcd->vc.mval, event->mval);
433  loopcut_mouse_move(lcd, is_interactive ? 1 : 0);
434  }
435  else {
436 
437  Object *ob_iter = bases[exec_data.base_index]->object;
438  ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter);
439 
440  BMEdge *e;
442  e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index);
443  loopcut_update_edge(lcd, exec_data.base_index, e, 0);
444  }
445 
446 #ifdef USE_LOOPSLIDE_HACK
447  /* for use in macro so we can restore, HACK */
448  {
450  ToolSettings *settings = scene->toolsettings;
451  const bool mesh_select_mode[3] = {
452  (settings->selectmode & SCE_SELECT_VERTEX) != 0,
453  (settings->selectmode & SCE_SELECT_EDGE) != 0,
454  (settings->selectmode & SCE_SELECT_FACE) != 0,
455  };
456 
457  RNA_boolean_set_array(op->ptr, "mesh_select_mode_init", mesh_select_mode);
458  }
459 #endif
460 
461  if (is_interactive) {
463  C,
464  TIP_("Select a ring to be cut, use mouse-wheel or page-up/down for number of cuts, "
465  "hold Alt for smooth"));
466  return OPERATOR_RUNNING_MODAL;
467  }
468 
469  ringsel_finish(C, op);
470  ringsel_exit(C, op);
471  return OPERATOR_FINISHED;
472 }
473 
474 static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event)
475 {
476  /* When accessed as a tool, get the active edge from the preselection gizmo. */
477  {
478  ARegion *region = CTX_wm_region(C);
479  wmGizmoMap *gzmap = region->gizmo_map;
480  wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap,
481  "VIEW3D_GGT_mesh_preselect_edgering") :
482  NULL;
483  if ((gzgroup != NULL) && gzgroup->gizmos.first) {
484  wmGizmo *gz = gzgroup->gizmos.first;
485  const int object_index = RNA_int_get(gz->ptr, "object_index");
486  const int edge_index = RNA_int_get(gz->ptr, "edge_index");
487 
488  if (object_index != -1 && edge_index != -1) {
489  RNA_int_set(op->ptr, "object_index", object_index);
490  RNA_int_set(op->ptr, "edge_index", edge_index);
491  return loopcut_init(C, op, NULL);
492  }
493  return OPERATOR_CANCELLED;
494  }
495  }
496 
497  return loopcut_init(C, op, event);
498 }
499 
501 {
502  return loopcut_init(C, op, NULL);
503 }
504 
506 {
507  /* finish */
510 
511  if (lcd->eed) {
512  /* set for redo */
514  RNA_int_set(op->ptr, "object_index", lcd->base_index);
515  RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed));
516 
517  /* execute */
518  ringsel_finish(C, op);
519  ringsel_exit(C, op);
520  }
521  else {
522  ringcut_cancel(C, op);
523  return OPERATOR_CANCELLED;
524  }
525 
526  return OPERATOR_FINISHED;
527 }
528 
529 static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
530 {
531  if (event->type == NDOF_MOTION) {
532  return OPERATOR_PASS_THROUGH;
533  }
534 
535  RingSelOpData *lcd = op->customdata;
536  float cuts = lcd->cuts;
537  float smoothness = lcd->smoothness;
538  bool show_cuts = false;
539  const bool has_numinput = hasNumInput(&lcd->num);
540 
541  em_setup_viewcontext(C, &lcd->vc);
542  lcd->region = lcd->vc.region;
543 
545 
546  /* using the keyboard to input the number of cuts */
547  /* Modal numinput active, try to handle numeric inputs first... */
548  if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) {
549  float values[2] = {cuts, smoothness};
550  applyNumInput(&lcd->num, values);
551  cuts = values[0];
552  smoothness = values[1];
553  }
554  else {
555  bool handled = false;
556  switch (event->type) {
557  case EVT_RETKEY:
558  case EVT_PADENTER:
559  case LEFTMOUSE: /* confirm */ /* XXX hardcoded */
560  if (event->val == KM_PRESS) {
561  return loopcut_finish(lcd, C, op);
562  }
563 
565  handled = true;
566  break;
567  case RIGHTMOUSE: /* abort */ /* XXX hardcoded */
569  ringsel_exit(C, op);
571 
572  return OPERATOR_CANCELLED;
573  case EVT_ESCKEY:
574  if (event->val == KM_RELEASE) {
575  /* cancel */
578 
579  ringcut_cancel(C, op);
580  return OPERATOR_CANCELLED;
581  }
582 
584  handled = true;
585  break;
586  case MOUSEPAN:
587  if ((event->modifier & KM_ALT) == 0) {
588  cuts += 0.02f * (event->xy[1] - event->prev_xy[1]);
589  if (cuts < 1 && lcd->cuts >= 1) {
590  cuts = 1;
591  }
592  }
593  else {
594  smoothness += 0.002f * (event->xy[1] - event->prev_xy[1]);
595  }
596  handled = true;
597  break;
598  case EVT_PADPLUSKEY:
599  case EVT_PAGEUPKEY:
600  case WHEELUPMOUSE: /* change number of cuts */
601  if (event->val == KM_RELEASE) {
602  break;
603  }
604  if ((event->modifier & KM_ALT) == 0) {
605  cuts += 1;
606  }
607  else {
608  smoothness += 0.05f;
609  }
610  handled = true;
611  break;
612  case EVT_PADMINUS:
613  case EVT_PAGEDOWNKEY:
614  case WHEELDOWNMOUSE: /* change number of cuts */
615  if (event->val == KM_RELEASE) {
616  break;
617  }
618  if ((event->modifier & KM_ALT) == 0) {
619  cuts = max_ff(cuts - 1, 1);
620  }
621  else {
622  smoothness -= 0.05f;
623  }
624  handled = true;
625  break;
626  case MOUSEMOVE: {
627  /* mouse moved somewhere to select another loop */
628 
629  /* This is normally disabled for all modal operators.
630  * This is an exception since mouse movement doesn't relate to numeric input.
631  *
632  * If numeric input changes we'll need to add this back see: D2973 */
633 #if 0
634  if (!has_numinput)
635 #endif
636  {
637  lcd->vc.mval[0] = event->mval[0];
638  lcd->vc.mval[1] = event->mval[1];
639  loopcut_mouse_move(lcd, (int)lcd->cuts);
640 
642  handled = true;
643  }
644  break;
645  }
646  }
647 
648  /* Modal numinput inactive, try to handle numeric inputs last... */
649  if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) {
650  float values[2] = {cuts, smoothness};
651  applyNumInput(&lcd->num, values);
652  cuts = values[0];
653  smoothness = values[1];
654  }
655  }
656 
657  if (cuts != lcd->cuts) {
658  /* allow zero so you can backspace and type in a value
659  * otherwise 1 as minimum would make more sense */
660  lcd->cuts = clamp_f(cuts, 0, SUBD_CUTS_MAX);
661  RNA_int_set(op->ptr, "number_cuts", (int)lcd->cuts);
662  ringsel_find_edge(lcd, (int)lcd->cuts);
663  show_cuts = true;
665  }
666 
667  if (smoothness != lcd->smoothness) {
668  lcd->smoothness = clamp_f(smoothness, -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
669  RNA_float_set(op->ptr, "smoothness", lcd->smoothness);
670  show_cuts = true;
672  }
673 
674  if (show_cuts) {
675  Scene *sce = CTX_data_scene(C);
676  char buf[UI_MAX_DRAW_STR];
677  char str_rep[NUM_STR_REP_LEN * 2];
678  if (hasNumInput(&lcd->num)) {
679  outputNumInput(&lcd->num, str_rep, &sce->unit);
680  }
681  else {
682  BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", (int)lcd->cuts);
683  BLI_snprintf(str_rep + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%.2f", smoothness);
684  }
685  BLI_snprintf(buf,
686  sizeof(buf),
687  TIP_("Number of Cuts: %s, Smooth: %s (Alt)"),
688  str_rep,
689  str_rep + NUM_STR_REP_LEN);
691  }
692 
693  /* keep going until the user confirms */
694  return OPERATOR_RUNNING_MODAL;
695 }
696 
697 /* for bmesh this tool is in bmesh_select.c */
698 #if 0
699 
701 {
702  /* description */
703  ot->name = "Edge Ring Select";
704  ot->idname = "MESH_OT_edgering_select";
705  ot->description = "Select an edge ring";
706 
707  /* callbacks */
708  ot->invoke = ringsel_invoke;
710 
711  /* flags */
713 
714  RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
715 }
716 
717 #endif
718 
720 {
721  PropertyRNA *prop;
722 
723  /* description */
724  ot->name = "Loop Cut";
725  ot->idname = "MESH_OT_loopcut";
726  ot->description = "Add a new loop between existing loops";
727 
728  /* callbacks */
730  ot->exec = loopcut_exec;
734 
735  /* flags */
737 
738  /* properties */
739  prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000000, "Number of Cuts", "", 1, 100);
740  /* avoid re-using last var because it can cause
741  * _very_ high poly meshes and annoy users (or worse crash) */
743 
744  prop = RNA_def_float(ot->srna,
745  "smoothness",
746  0.0f,
747  -1e3f,
748  1e3f,
749  "Smoothness",
750  "Smoothness factor",
754 
756 
757  prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE);
760  RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather");
762  BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */
763 
764  /* For redo only. */
765  prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", 0, INT_MAX);
767  prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", 0, INT_MAX);
769 
770 #ifdef USE_LOOPSLIDE_HACK
771  prop = RNA_def_boolean_array(ot->srna, "mesh_select_mode_init", 3, NULL, "", "");
773 #endif
774 }
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
const float(* BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph, struct BMEditMesh *em, struct Scene *scene, struct Object *obedit, int *r_vert_len, bool *r_is_alloc))[3]
Definition: editmesh.c:241
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:539
struct Object * BKE_modifiers_is_deformed_by_armature(struct Object *ob)
struct Object * BKE_modifiers_is_deformed_by_lattice(struct Object *ob)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
@ B_UNIT_NONE
Definition: BKE_unit.h:100
MINLINE float max_ff(float a, float b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
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 UNUSED(x)
#define BLT_I18NCONTEXT_ID_CURVE_LEGACY
#define TIP_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
struct ID * DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
Object is a sort of wrapper for general info.
#define SCE_SELECT_FACE
#define SCE_SELECT_VERTEX
#define PROP_INVSQUARE
#define SCE_SELECT_EDGE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ OP_IS_MODAL_CURSOR_REGION
bool EDBM_selectmode_disable_multi(struct bContext *C, short selectmode_disable, short selectmode_fallback)
void EDBM_preselect_edgering_destroy(struct EditMesh_PreSelEdgeRing *psel)
void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params)
void EDBM_preselect_edgering_clear(struct EditMesh_PreSelEdgeRing *psel)
void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc)
struct BMEdge * EDBM_edge_find_nearest_ex(struct ViewContext *vc, float *dist_px_manhattan, float *r_dist_center, bool use_select_bias, bool use_cycle, struct BMEdge **r_eed_zbuf, struct Base **bases, uint bases_len, uint *r_base_index)
struct EditMesh_PreSelEdgeRing * EDBM_preselect_edgering_create(void)
void EDBM_flag_disable_all(struct BMEditMesh *em, char hflag)
void EDBM_preselect_edgering_draw(struct EditMesh_PreSelEdgeRing *psel, const float matrix[4][4])
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, short selectmode)
void EDBM_preselect_edgering_update_from_edge(struct EditMesh_PreSelEdgeRing *psel, struct BMesh *bm, struct BMEdge *eed_start, int previewlines, const float(*coords)[3])
void EDBM_selectmode_flush(struct BMEditMesh *em)
void outputNumInput(NumInput *n, char *str, struct UnitSettings *unit_settings)
Definition: numinput.c:87
void initNumInput(NumInput *n)
Definition: numinput.c:69
#define NUM_STR_REP_LEN
Definition: ED_numinput.h:13
@ NUM_NO_NEGATIVE
Definition: ED_numinput.h:56
@ NUM_NO_FRACTION
Definition: ED_numinput.h:58
bool applyNumInput(NumInput *n, float *vec)
Definition: numinput.c:189
bool hasNumInput(const NumInput *n)
Definition: numinput.c:170
bool handleNumInput(struct bContext *C, NumInput *n, const struct wmEvent *event)
bool ED_operator_editmesh_region_view3d(struct bContext *C)
Definition: screen_ops.c:447
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:816
#define REGION_DRAW_POST_VIEW
Definition: ED_space_api.h:62
void * ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *customdata, int type)
Definition: spacetypes.c:226
bool ED_region_draw_cb_exit(struct ARegionType *art, void *handle)
Definition: spacetypes.c:241
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact)
void view3d_operator_needs_opengl(const struct bContext *C)
float ED_view3d_select_dist_px(void)
Read Guarded memory(de)allocation.
@ PROP_ENUM
Definition: RNA_types.h:63
@ 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
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:91
@ KM_PRESS
Definition: WM_types.h:267
@ KM_RELEASE
Definition: WM_types.h:268
@ OPTYPE_BLOCKING
Definition: WM_types.h:150
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_SELECT
Definition: WM_types.h:455
@ KM_ALT
Definition: WM_types.h:240
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
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.
#define BM_select_history_store(bm, ele)
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 BMEdge * BM_edge_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:109
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)
@ SUBDIV_SELECT_INNER
@ SUBDIV_SELECT_LOOPCUT
@ SUBDIV_SELECT_NONE
@ SUBD_CORNER_PATH
bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len)
Definition: bmesh_query.c:2017
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
void BMW_init(BMWalker *walker, BMesh *bm, int type, short mask_vert, short mask_edge, short mask_face, BMWFlag flag, int layer)
Init Walker.
Definition: bmesh_walkers.c:49
void BMW_end(BMWalker *walker)
End Walker.
void * BMW_begin(BMWalker *walker, void *start)
Definition: bmesh_walkers.c:40
void * BMW_step(BMWalker *walker)
Step Walker.
#define BMW_NIL_LAY
@ BMW_FLAG_TEST_HIDDEN
Definition: bmesh_walkers.h:20
#define BMW_MASK_NOP
Definition: bmesh_walkers.h:54
@ BMW_EDGERING
Scene scene
static void loopcut_update_edge(RingSelOpData *lcd, uint base_index, BMEdge *e, const int previewlines)
static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines)
struct RingSelOpData RingSelOpData
#define SUBD_SMOOTH_MAX
static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
static void ringcut_cancel(bContext *C, wmOperator *op)
#define SUBD_CUTS_MAX
static void ringsel_exit(bContext *UNUSED(C), wmOperator *op)
static void ringsel_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
static int loopcut_exec(bContext *C, wmOperator *op)
static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
void MESH_OT_loopcut(wmOperatorType *ot)
static void ringsel_finish(bContext *C, wmOperator *op)
static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op)
static void edgering_select(RingSelOpData *lcd)
static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines)
static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void MESH_OT_edgering_select(wmOperatorType *ot)
#define UINT_MAX
Definition: hash_md5.c:43
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void RNA_boolean_set_array(PointerRNA *ptr, const char *name, const bool *values)
Definition: rna_access.c:4898
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:4968
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
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
void RNA_def_property_enum_default(PropertyRNA *prop, int value)
Definition: rna_define.c:2106
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description)
Definition: rna_define.c:1645
void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item)
Definition: rna_define.c:1872
PropertyRNA * RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier, int type, int subtype)
Definition: rna_define.c:1257
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
Definition: rna_define.c:2848
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
PropertyRNA * RNA_def_boolean_array(StructOrFunctionRNA *cont_, const char *identifier, int len, bool *default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3509
const EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[]
Definition: rna_scene.c:120
struct wmGizmoMap * gizmo_map
struct ARegionType * type
BMVert * v1
Definition: bmesh_class.h:122
BMVert * v2
Definition: bmesh_class.h:122
short selectmode
Definition: BKE_editmesh.h:52
struct BMesh * bm
Definition: BKE_editmesh.h:40
int totedge
Definition: bmesh_class.h:297
struct Object * object
void * first
Definition: DNA_listBase.h:31
const float(* coords)[3]
short idx_max
Definition: ED_numinput.h:20
short val_flag[NUM_MAX_ELEMENTS]
Definition: ED_numinput.h:29
int unit_sys
Definition: ED_numinput.h:21
int unit_type[NUM_MAX_ELEMENTS]
Definition: ED_numinput.h:23
float obmat[4][4]
void * data
struct EditMesh_PreSelEdgeRing * presel_edgering
Depsgraph * depsgraph
ARegion * region
BMEditMesh * em
ViewContext vc
struct MeshCoordsCache * geom_cache
struct ToolSettings * toolsettings
struct UnitSettings unit
struct Depsgraph * depsgraph
Definition: ED_view3d.h:64
int mval[2]
Definition: ED_view3d.h:74
struct Scene * scene
Definition: ED_view3d.h:65
struct ARegion * region
Definition: ED_view3d.h:69
struct BMEditMesh * em
Definition: ED_view3d.h:73
struct Object * obedit
Definition: ED_view3d.h:68
short val
Definition: WM_types.h:680
int mval[2]
Definition: WM_types.h:684
uint8_t modifier
Definition: WM_types.h:693
short type
Definition: WM_types.h:678
ListBase gizmos
struct PointerRNA * ptr
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
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
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct PointerRNA * ptr
struct wmOperator * opm
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ MOUSEPAN
@ RIGHTMOUSE
@ WHEELUPMOUSE
@ EVT_PAGEUPKEY
@ EVT_PAGEDOWNKEY
@ EVT_PADENTER
@ WHEELDOWNMOUSE
@ MOUSEMOVE
@ EVT_PADMINUS
@ LEFTMOUSE
@ NDOF_MOTION
@ EVT_ESCKEY
@ EVT_PADPLUSKEY
@ EVT_RETKEY
wmOperatorType * ot
Definition: wm_files.c:3479
wmGizmoGroup * WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idname)
Definition: wm_gizmo_map.c:202
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)