Blender V4.3
editmesh_loopcut.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "DNA_object_types.h"
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_math_vector.h"
14#include "BLI_string.h"
15
16#include "BLT_translation.hh"
17
18#include "BKE_context.hh"
19#include "BKE_editmesh.hh"
20#include "BKE_layer.hh"
21#include "BKE_modifier.hh"
22#include "BKE_report.hh"
23#include "BKE_unit.hh"
24
25#include "UI_interface.hh"
26
27#include "ED_mesh.hh"
28#include "ED_numinput.hh"
29#include "ED_screen.hh"
30#include "ED_space_api.hh"
31#include "ED_view3d.hh"
32
33#include "RNA_access.hh"
34#include "RNA_define.hh"
35#include "RNA_enum_types.hh"
36
37#include "WM_api.hh"
38#include "WM_types.hh"
39
40#include "DEG_depsgraph.hh"
42
43#include "mesh_intern.hh" /* own include */
44
45using blender::Array;
46using blender::float3;
47using blender::Span;
48using blender::Vector;
49
50#define SUBD_SMOOTH_MAX 4.0f
51#define SUBD_CUTS_MAX 500
52
53/* ringsel operator */
54
60
61/* struct for properties used while drawing */
63 ARegion *region; /* region that ringsel was activated in */
64 void *draw_handle; /* for drawing preview loop */
65
67
69
70 Depsgraph *depsgraph;
71
73
75
76 /* These values switch objects based on the object under the cursor. */
81
83
84 bool extend;
85 bool do_cut;
86
87 float cuts; /* cuts as float so smooth mouse pan works in small increments */
89};
90
91/* modal loop selection drawing callback */
92static void ringsel_draw(const bContext * /*C*/, ARegion * /*region*/, void *arg)
93{
94 RingSelOpData *lcd = static_cast<RingSelOpData *>(arg);
95 if (lcd->ob != nullptr) {
96 EDBM_preselect_edgering_draw(lcd->presel_edgering, lcd->ob->object_to_world().ptr());
97 }
98}
99
101{
102 if (!lcd->eed) {
103 return;
104 }
105
106 if (!lcd->extend) {
107 for (Base *base : lcd->bases) {
108 Object *ob_iter = base->object;
111 DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT);
113 }
114 }
115
116 BMEditMesh *em = lcd->em;
117 BMEdge *eed_start = lcd->eed;
118 BMWalker walker;
119 BMEdge *eed;
120 BMW_init(&walker,
121 em->bm,
128
129 for (eed = static_cast<BMEdge *>(BMW_begin(&walker, eed_start)); eed;
130 eed = static_cast<BMEdge *>(BMW_step(&walker)))
131 {
132 BM_edge_select_set(em->bm, eed, true);
133 }
134 BMW_end(&walker);
135}
136
137static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines)
138{
139 if (lcd->eed) {
140 MeshCoordsCache *gcache = &lcd->geom_cache[lcd->base_index];
141 if (gcache->is_init == false) {
142 Scene *scene_eval = (Scene *)DEG_get_evaluated_id(lcd->vc.depsgraph, &lcd->vc.scene->id);
143 Object *ob_eval = DEG_get_evaluated_object(lcd->vc.depsgraph, lcd->ob);
144 BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
146 lcd->vc.depsgraph, em_eval, scene_eval, ob_eval, gcache->allocated_vert_positions);
147 gcache->is_init = true;
148 }
149
151 lcd->presel_edgering, lcd->em->bm, lcd->eed, previewlines, gcache->vert_positions);
152 }
153 else {
155 }
156}
157
159{
160 RingSelOpData *lcd = static_cast<RingSelOpData *>(op->customdata);
161 const int cuts = RNA_int_get(op->ptr, "number_cuts");
162 const float smoothness = RNA_float_get(op->ptr, "smoothness");
163 const int smooth_falloff = RNA_enum_get(op->ptr, "falloff");
164#ifdef BMW_EDGERING_NGON
165 const bool use_only_quads = false;
166#else
167 const bool use_only_quads = false;
168#endif
169
170 if (lcd->eed) {
171 BMEditMesh *em = lcd->em;
172 BMVert *v_eed_orig[2] = {lcd->eed->v1, lcd->eed->v2};
173
174 edgering_select(lcd);
175
176 if (lcd->do_cut) {
177 const bool is_macro = (op->opm != nullptr);
178 /* a single edge (rare, but better support) */
179 const bool is_edge_wire = BM_edge_is_wire(lcd->eed);
180 const bool is_single = is_edge_wire || !BM_edge_is_any_face_len_test(lcd->eed, 4);
181 const int seltype = is_edge_wire ? SUBDIV_SELECT_INNER :
182 is_single ? SUBDIV_SELECT_NONE :
184
185 /* Enable grid-fill, so that intersecting loop-cut works as one would expect.
186 * Note though that it will break edge-slide in this specific case.
187 * See #31939. */
190 smoothness,
191 smooth_falloff,
192 true,
193 0.0f,
194 0.0f,
195 cuts,
196 seltype,
198 0,
199 true,
200 use_only_quads,
201 0);
202
203 /* When used in a macro the tessellation will be recalculated anyway,
204 * this is needed here because modifiers depend on updated tessellation, see #45920 */
206 params.calc_looptris = true;
207 params.calc_normals = false;
208 params.is_destructive = true;
209 EDBM_update(static_cast<Mesh *>(lcd->ob->data), &params);
210
211 if (is_single) {
212 /* de-select endpoints */
213 BM_vert_select_set(em->bm, v_eed_orig[0], false);
214 BM_vert_select_set(em->bm, v_eed_orig[1], false);
215
217 }
218 /* We can't slide multiple edges in vertex select mode, force edge select mode. Do this for
219 * all meshes in multi-object editmode so their selectmode is in sync for following
220 * operators. */
221 else if (is_macro && (cuts > 1) && (em->selectmode & SCE_SELECT_VERTEX)) {
223 }
224 /* Force edge slide to edge select mode in face select mode. Do this for all meshes in
225 * multi-object editmode so their selectmode is in sync for following operators. */
227 /* pass, the change will flush selection */
228 }
229 else {
230 /* else flush explicitly */
232 }
233 }
234 else {
235 /* XXX Is this piece of code ever used now? Simple loop select is now
236 * in editmesh_select.cc (around line 1000)... */
237 /* sets as active, useful for other tools */
238 if (em->selectmode & SCE_SELECT_VERTEX) {
239 /* low priority TODO: get vertex close to mouse. */
240 BM_select_history_store(em->bm, lcd->eed->v1);
241 }
242 if (em->selectmode & SCE_SELECT_EDGE) {
243 BM_select_history_store(em->bm, lcd->eed);
244 }
245
247 DEG_id_tag_update(static_cast<ID *>(lcd->ob->data), ID_RECALC_SELECT);
249 }
250 }
251}
252
253/* called when modal loop selection is done... */
254static void ringsel_exit(bContext * /*C*/, wmOperator *op)
255{
256 RingSelOpData *lcd = static_cast<RingSelOpData *>(op->customdata);
257
258 /* deactivate the extra drawing stuff in 3D-View */
260
262
264
265 MEM_delete(lcd);
266 op->customdata = nullptr;
267}
268
269/* called when modal loop selection gets set up... */
270static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
271{
272 Scene *scene = CTX_data_scene(C);
273
274 /* alloc new customdata */
275 RingSelOpData *lcd = MEM_new<RingSelOpData>(__func__);
276 op->customdata = lcd;
277 lcd->vc = em_setup_viewcontext(C);
278
280
281 /* assign the drawing handle for drawing preview line... */
282 lcd->region = CTX_wm_region(C);
286 /* Initialize once the cursor is over a mesh. */
287 lcd->ob = nullptr;
288 lcd->em = nullptr;
289 lcd->extend = do_cut ? false : RNA_boolean_get(op->ptr, "extend");
290 lcd->do_cut = do_cut;
291 lcd->cuts = RNA_int_get(op->ptr, "number_cuts");
292 lcd->smoothness = RNA_float_get(op->ptr, "smoothness");
293
294 initNumInput(&lcd->num);
295 lcd->num.idx_max = 1;
297 /* No specific flags for smoothness. */
298 lcd->num.unit_sys = scene->unit.system;
299 lcd->num.unit_type[0] = B_UNIT_NONE;
300 lcd->num.unit_type[1] = B_UNIT_NONE;
301
303
304 return 1;
305}
306
308{
309 /* this is just a wrapper around exit() */
310 ringsel_exit(C, op);
311}
312
314 uint base_index,
315 BMEdge *e,
316 const int previewlines)
317{
318 if (e != lcd->eed) {
319 lcd->eed = e;
320 lcd->ob = lcd->vc.obedit;
321 lcd->base_index = base_index;
322 lcd->em = lcd->vc.em;
323 ringsel_find_edge(lcd, previewlines);
324 }
325 else if (e == nullptr) {
326 lcd->ob = nullptr;
327 lcd->em = nullptr;
328 lcd->base_index = UINT_MAX;
329 }
330}
331
332static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines)
333{
334 struct {
335 Object *ob;
336 BMEdge *eed;
337 float dist;
338 int base_index;
339 } best{};
340 best.dist = ED_view3d_select_dist_px();
341
342 uint base_index;
344 &lcd->vc, &best.dist, nullptr, false, false, nullptr, lcd->bases, &base_index);
345
346 if (eed_test) {
347 best.ob = lcd->bases[base_index]->object;
348 best.eed = eed_test;
349 best.base_index = base_index;
350 }
351
352 if (best.eed) {
354 }
355
356 loopcut_update_edge(lcd, best.base_index, best.eed, previewlines);
357}
358
359/* called by both init() and exec() */
360static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
361{
362 /* Check whether both `rv3d` and `event` is present, this way we allow the loopcut operator to
363 * run non-interactively no matter whether the graphical UI is present or not (e.g. from scripts
364 * with UI running, or entirely in the background with `blender -b`). */
366 const bool is_interactive = (rv3d != nullptr) && (event != nullptr);
367
368 /* Use for redo - intentionally wrap int to uint. */
369 struct {
370 uint base_index;
371 uint e_index;
372 } exec_data{};
373 exec_data.base_index = uint(RNA_int_get(op->ptr, "object_index"));
374 exec_data.e_index = uint(RNA_int_get(op->ptr, "edge_index"));
375
376 const Scene *scene = CTX_data_scene(C);
377 ViewLayer *view_layer = CTX_data_view_layer(C);
378
380 scene, view_layer, CTX_wm_view3d(C));
381
382 if (is_interactive) {
383 for (Base *base : bases) {
384 Object *ob_iter = base->object;
387 {
389 op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display");
390 break;
391 }
392 }
393 }
394
395 if (is_interactive) {
397 }
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.size()) {
403 ok = false;
404 }
405 else {
406 Object *ob_iter = bases[exec_data.base_index]->object;
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 return OPERATOR_CANCELLED;
416 }
417
418 /* add a modal handler for this operator - handles loop selection */
419 if (is_interactive) {
422 }
423
424 RingSelOpData *lcd = static_cast<RingSelOpData *>(op->customdata);
425
426 lcd->bases = std::move(bases);
427 lcd->geom_cache.reinitialize(lcd->bases.size());
428
429 if (is_interactive) {
430 copy_v2_v2_int(lcd->vc.mval, event->mval);
431 loopcut_mouse_move(lcd, is_interactive ? 1 : 0);
432 }
433 else {
434
435 Object *ob_iter = lcd->bases[exec_data.base_index]->object;
437
438 BMEdge *e;
440 e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index);
441 loopcut_update_edge(lcd, exec_data.base_index, e, 0);
442 }
443
444#ifdef USE_LOOPSLIDE_HACK
445 /* for use in macro so we can restore, HACK */
446 {
447 ToolSettings *settings = scene->toolsettings;
448 const bool mesh_select_mode[3] = {
449 (settings->selectmode & SCE_SELECT_VERTEX) != 0,
450 (settings->selectmode & SCE_SELECT_EDGE) != 0,
451 (settings->selectmode & SCE_SELECT_FACE) != 0,
452 };
453
454 RNA_boolean_set_array(op->ptr, "mesh_select_mode_init", mesh_select_mode);
455 }
456#endif
457
458 if (is_interactive) {
459 char buf[UI_MAX_DRAW_STR];
460 char str_rep[NUM_STR_REP_LEN * 2];
461 if (hasNumInput(&lcd->num)) {
462 outputNumInput(&lcd->num, str_rep, &scene->unit);
463 }
464 else {
465 BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", int(lcd->cuts));
466 BLI_snprintf(str_rep + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%.2f", lcd->smoothness);
467 }
468 SNPRINTF(buf, IFACE_("Cuts: %s, Smoothness: %s"), str_rep, str_rep + NUM_STR_REP_LEN);
470
471 WorkspaceStatus status(C);
472 status.item(IFACE_("Confirm"), ICON_MOUSE_LMB);
473 status.item(IFACE_("Cancel"), ICON_MOUSE_RMB);
474 status.item(IFACE_("Select Ring"), ICON_MOUSE_MOVE);
475 status.item("", ICON_MOUSE_MMB);
476 status.item(IFACE_("Number of Cuts"), ICON_EVENT_PAGEUP, ICON_EVENT_PAGEDOWN);
477 status.item(IFACE_("Smoothness"), ICON_EVENT_ALT, ICON_MOUSE_MMB);
479 }
480
481 ringsel_finish(C, op);
482 ringsel_exit(C, op);
483 return OPERATOR_FINISHED;
484}
485
486static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event)
487{
488 /* When accessed as a tool, get the active edge from the pre-selection gizmo. */
489 {
490 ARegion *region = CTX_wm_region(C);
491 wmGizmoMap *gzmap = region->gizmo_map;
492 wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap,
493 "VIEW3D_GGT_mesh_preselect_edgering") :
494 nullptr;
495 if ((gzgroup != nullptr) && gzgroup->gizmos.first) {
496 wmGizmo *gz = static_cast<wmGizmo *>(gzgroup->gizmos.first);
497 const int object_index = RNA_int_get(gz->ptr, "object_index");
498 const int edge_index = RNA_int_get(gz->ptr, "edge_index");
499
500 if (object_index != -1 && edge_index != -1) {
501 RNA_int_set(op->ptr, "object_index", object_index);
502 RNA_int_set(op->ptr, "edge_index", edge_index);
503 return loopcut_init(C, op, nullptr);
504 }
505 return OPERATOR_CANCELLED;
506 }
507 }
508
509 return loopcut_init(C, op, event);
510}
511
513{
514 return loopcut_init(C, op, nullptr);
515}
516
518{
519 /* finish */
521 ED_workspace_status_text(C, nullptr);
522 ED_area_status_text(CTX_wm_area(C), nullptr);
523
524 if (lcd->eed) {
525 /* set for redo */
527 RNA_int_set(op->ptr, "object_index", lcd->base_index);
528 RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed));
529
530 /* execute */
531 ringsel_finish(C, op);
532 ringsel_exit(C, op);
533 }
534 else {
535 ringcut_cancel(C, op);
536 return OPERATOR_CANCELLED;
537 }
538
539 return OPERATOR_FINISHED;
540}
541
542static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
543{
544 if (event->type == NDOF_MOTION) {
546 }
547
548 RingSelOpData *lcd = static_cast<RingSelOpData *>(op->customdata);
549 float cuts = lcd->cuts;
550 float smoothness = lcd->smoothness;
551 bool show_cuts = false;
552 const bool has_numinput = hasNumInput(&lcd->num);
553
554 lcd->vc = em_setup_viewcontext(C);
555 lcd->region = lcd->vc.region;
556
558
559 /* using the keyboard to input the number of cuts */
560 /* Modal numinput active, try to handle numeric inputs first... */
561 if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) {
562 float values[2] = {cuts, smoothness};
563 applyNumInput(&lcd->num, values);
564 cuts = values[0];
565 smoothness = values[1];
566 }
567 else {
568 bool handled = false;
569 switch (event->type) {
570 case EVT_RETKEY:
571 case EVT_PADENTER:
572 case LEFTMOUSE: /* confirm */ /* XXX hardcoded */
573 if (event->val == KM_PRESS) {
574 return loopcut_finish(lcd, C, op);
575 }
576
578 handled = true;
579 break;
580 case RIGHTMOUSE: /* abort */ /* XXX hardcoded */
582 ringsel_exit(C, op);
583 ED_workspace_status_text(C, nullptr);
584 ED_area_status_text(CTX_wm_area(C), nullptr);
585
586 return OPERATOR_CANCELLED;
587 case EVT_ESCKEY:
588 if (event->val == KM_RELEASE) {
589 /* cancel */
591 ED_workspace_status_text(C, nullptr);
592 ED_area_status_text(CTX_wm_area(C), nullptr);
593
594 ringcut_cancel(C, op);
595 return OPERATOR_CANCELLED;
596 }
597
599 handled = true;
600 break;
601 case MOUSEPAN:
602 if ((event->modifier & KM_ALT) == 0) {
603 cuts += 0.02f * (event->xy[1] - event->prev_xy[1]);
604 if (cuts < 1 && lcd->cuts >= 1) {
605 cuts = 1;
606 }
607 }
608 else {
609 smoothness += 0.002f * (event->xy[1] - event->prev_xy[1]);
610 }
611 handled = true;
612 break;
613 case EVT_PADPLUSKEY:
614 case EVT_PAGEUPKEY:
615 case WHEELUPMOUSE: /* change number of cuts */
616 if (event->val == KM_RELEASE) {
617 break;
618 }
619 if ((event->modifier & KM_ALT) == 0) {
620 cuts += 1;
621 }
622 else {
623 smoothness += 0.05f;
624 }
625 handled = true;
626 break;
627 case EVT_PADMINUS:
628 case EVT_PAGEDOWNKEY:
629 case WHEELDOWNMOUSE: /* change number of cuts */
630 if (event->val == KM_RELEASE) {
631 break;
632 }
633 if ((event->modifier & KM_ALT) == 0) {
634 cuts = max_ff(cuts - 1, 1);
635 }
636 else {
637 smoothness -= 0.05f;
638 }
639 handled = true;
640 break;
641 case MOUSEMOVE: {
642/* mouse moved somewhere to select another loop */
643
644/* This is normally disabled for all modal operators.
645 * This is an exception since mouse movement doesn't relate to numeric input.
646 *
647 * If numeric input changes we'll need to add this back see: D2973 */
648#if 0
649 if (!has_numinput)
650#endif
651 {
652 lcd->vc.mval[0] = event->mval[0];
653 lcd->vc.mval[1] = event->mval[1];
654 loopcut_mouse_move(lcd, int(lcd->cuts));
655
657 handled = true;
658 }
659 break;
660 }
661 }
662
663 /* Modal numinput inactive, try to handle numeric inputs last... */
664 if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) {
665 float values[2] = {cuts, smoothness};
666 applyNumInput(&lcd->num, values);
667 cuts = values[0];
668 smoothness = values[1];
669 }
670 }
671
672 if (cuts != lcd->cuts) {
673 /* allow zero so you can backspace and type in a value
674 * otherwise 1 as minimum would make more sense */
675 lcd->cuts = clamp_f(cuts, 0, SUBD_CUTS_MAX);
676 RNA_int_set(op->ptr, "number_cuts", int(lcd->cuts));
677 ringsel_find_edge(lcd, int(lcd->cuts));
678 show_cuts = true;
680 }
681
682 if (smoothness != lcd->smoothness) {
684 RNA_float_set(op->ptr, "smoothness", lcd->smoothness);
685 show_cuts = true;
687 }
688
689 if (show_cuts) {
690 Scene *sce = CTX_data_scene(C);
691 char buf[UI_MAX_DRAW_STR];
692 char str_rep[NUM_STR_REP_LEN * 2];
693 if (hasNumInput(&lcd->num)) {
694 outputNumInput(&lcd->num, str_rep, &sce->unit);
695 }
696 else {
697 BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", int(lcd->cuts));
698 BLI_snprintf(str_rep + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%.2f", smoothness);
699 }
700 SNPRINTF(buf, IFACE_("Cuts: %s, Smoothness: %s"), str_rep, str_rep + NUM_STR_REP_LEN);
702 }
703
704 /* keep going until the user confirms */
706}
707
708/* for bmesh this tool is in bmesh_select.c */
709#if 0
710
712{
713 /* description */
714 ot->name = "Edge Ring Select";
715 ot->idname = "MESH_OT_edgering_select";
716 ot->description = "Select an edge ring";
717
718 /* callbacks */
719 ot->invoke = ringsel_invoke;
721
722 /* flags */
724
725 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
726}
727
728#endif
729
731{
732 PropertyRNA *prop;
733
734 /* description */
735 ot->name = "Loop Cut";
736 ot->idname = "MESH_OT_loopcut";
737 ot->description = "Add a new loop between existing loops";
738
739 /* callbacks */
744 /* Note the #RegionView3D is needed for interactive use, the operator must check this. */
746
747 /* flags */
749
750 /* properties */
751 prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000000, "Number of Cuts", "", 1, 100);
752 /* avoid re-using last var because it can cause
753 * _very_ high poly meshes and annoy users (or worse crash) */
755
756 prop = RNA_def_float(ot->srna,
757 "smoothness",
758 0.0f,
759 -1e3f,
760 1e3f,
761 "Smoothness",
762 "Smoothness factor",
766
768
769 prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE);
772 RNA_def_property_ui_text(prop, "Falloff", "Falloff type of the feather");
774 BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */
775
776 /* For redo only. */
777 prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", 0, INT_MAX);
780 prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", 0, INT_MAX);
782
783#ifdef USE_LOOPSLIDE_HACK
784 prop = RNA_def_boolean_array(ot->srna, "mesh_select_mode_init", 3, nullptr, "", "");
786#endif
787}
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
blender::Span< blender::float3 > BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, Object *obedit, blender::Array< blender::float3 > &r_alloc)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:63
blender::Vector< Base * > BKE_view_layer_array_from_bases_in_edit_mode(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
Object * BKE_modifiers_is_deformed_by_lattice(Object *ob)
Object * BKE_modifiers_is_deformed_by_armature(Object *ob)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
@ B_UNIT_NONE
Definition BKE_unit.hh:106
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])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
#define BLT_I18NCONTEXT_ID_CURVE_LEGACY
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_ID_MESH
void DEG_id_tag_update(ID *id, unsigned int flags)
ID * DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ ID_RECALC_SELECT
Definition DNA_ID.h:1068
Object is a sort of wrapper for general info.
@ PROP_INVSQUARE
@ SCE_SELECT_FACE
@ SCE_SELECT_VERTEX
@ SCE_SELECT_EDGE
@ OP_IS_MODAL_CURSOR_REGION
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void EDBM_flag_disable_all(BMEditMesh *em, char hflag)
void EDBM_update(Mesh *mesh, const EDBMUpdate_Params *params)
void EDBM_preselect_edgering_destroy(EditMesh_PreSelEdgeRing *psel)
void EDBM_preselect_edgering_clear(EditMesh_PreSelEdgeRing *psel)
BMEdge * EDBM_edge_find_nearest_ex(ViewContext *vc, float *dist_px_manhattan, float *r_dist_center, bool use_select_bias, bool use_cycle, BMEdge **r_eed_zbuf, blender::Span< Base * > bases, uint *r_base_index)
ViewContext em_setup_viewcontext(bContext *C)
void EDBM_selectmode_flush(BMEditMesh *em)
void EDBM_preselect_edgering_draw(EditMesh_PreSelEdgeRing *psel, const float matrix[4][4])
void EDBM_selectmode_flush_ex(BMEditMesh *em, short selectmode)
bool EDBM_selectmode_disable_multi(bContext *C, short selectmode_disable, short selectmode_fallback)
EditMesh_PreSelEdgeRing * EDBM_preselect_edgering_create()
void EDBM_preselect_edgering_update_from_edge(EditMesh_PreSelEdgeRing *psel, BMesh *bm, BMEdge *eed_start, int previewlines, blender::Span< blender::float3 > vert_positions)
void initNumInput(NumInput *n)
Definition numinput.cc:70
#define NUM_STR_REP_LEN
void outputNumInput(NumInput *n, char *str, const UnitSettings *unit_settings)
Definition numinput.cc:88
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
Definition numinput.cc:312
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:190
@ NUM_NO_NEGATIVE
@ NUM_NO_FRACTION
bool hasNumInput(const NumInput *n)
Definition numinput.cc:171
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:803
bool ED_operator_editmesh_region_view3d(bContext *C)
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
bool ED_operator_editmesh(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
#define REGION_DRAW_POST_VIEW
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
float ED_view3d_select_dist_px()
void view3d_operator_needs_opengl(const bContext *C)
void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
Read Guarded memory(de)allocation.
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
@ PROP_NONE
Definition RNA_types.hh:136
#define UI_MAX_DRAW_STR
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_GEOM
Definition WM_types.hh:360
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#define ND_SELECT
Definition WM_types.hh:474
@ KM_ALT
Definition WM_types.hh:257
@ BM_ELEM_SELECT
#define BM_elem_index_get(ele)
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)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BLI_INLINE BMEdge * BM_edge_at_index(BMesh *bm, const int index)
#define BM_EDGE
@ SUBD_CORNER_PATH
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
bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len)
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_begin(BMWalker *walker, void *start)
void BMW_init(BMWalker *walker, BMesh *bm, int type, short mask_vert, short mask_edge, short mask_face, BMWFlag flag, int layer)
Init Walker.
void BMW_end(BMWalker *walker)
End Walker.
void * BMW_step(BMWalker *walker)
Step Walker.
#define BMW_NIL_LAY
@ BMW_FLAG_TEST_HIDDEN
#define BMW_MASK_NOP
@ BMW_EDGERING
void item(std::string text, int icon1, int icon2=0)
Definition area.cc:908
int64_t size() const
static void loopcut_update_edge(RingSelOpData *lcd, uint base_index, BMEdge *e, const int previewlines)
static void ringsel_draw(const bContext *, ARegion *, void *arg)
static void ringsel_exit(bContext *, wmOperator *op)
static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines)
#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 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.cc:44
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void RNA_boolean_set_array(PointerRNA *ptr, const char *name, const bool *values)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean_array(StructOrFunctionRNA *cont_, const char *identifier, const int len, const bool *default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_enum_default(PropertyRNA *prop, int value)
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item)
PropertyRNA * RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier, int type, int subtype)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[]
Definition rna_scene.cc:114
struct ARegionType * type
BMVert * v1
BMVert * v2
short selectmode
int totedge
Definition DNA_ID.h:413
void * first
Array< float3 > allocated_vert_positions
Span< float3 > vert_positions
short idx_max
short val_flag[NUM_MAX_ELEMENTS]
int unit_type[NUM_MAX_ELEMENTS]
Depsgraph * depsgraph
BMEditMesh * em
Vector< Base * > bases
Array< MeshCoordsCache > geom_cache
EditMesh_PreSelEdgeRing * presel_edgering
struct UnitSettings unit
ARegion * region
Definition ED_view3d.hh:73
int mval[2]
Definition ED_view3d.hh:78
Scene * scene
Definition ED_view3d.hh:69
BMEditMesh * em
Definition ED_view3d.hh:77
Object * obedit
Definition ED_view3d.hh:72
Depsgraph * depsgraph
Definition ED_view3d.hh:68
short val
Definition WM_types.hh:724
int mval[2]
Definition WM_types.hh:728
uint8_t modifier
Definition WM_types.hh:739
short type
Definition WM_types.hh:722
PointerRNA * ptr
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct PointerRNA * ptr
struct wmOperator * opm
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
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.cc:4125
wmGizmoGroup * WM_gizmomap_group_find(wmGizmoMap *gzmap, const char *idname)
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)