Blender V5.0
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
8
9#include "DNA_object_types.h"
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_math_vector.h"
14#include "BLI_string_utf8.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_screen.hh"
24#include "BKE_unit.hh"
25
26#include "UI_interface.hh"
27
28#include "ED_mesh.hh"
29#include "ED_numinput.hh"
30#include "ED_screen.hh"
31#include "ED_space_api.hh"
32#include "ED_view3d.hh"
33
34#include "RNA_access.hh"
35#include "RNA_define.hh"
36#include "RNA_enum_types.hh"
37
38#include "WM_api.hh"
39#include "WM_types.hh"
40
41#include "DEG_depsgraph.hh"
43
44#include "mesh_intern.hh" /* own include */
45
46using blender::Array;
47using blender::float3;
48using blender::Span;
49using blender::Vector;
50
51#define SUBD_SMOOTH_MAX 4.0f
52#define SUBD_CUTS_MAX 500
53
54/* ringsel operator */
55
61
62/* struct for properties used while drawing */
64 ARegion *region; /* region that ringsel was activated in */
65 void *draw_handle; /* for drawing preview loop */
66
68
70
71 Depsgraph *depsgraph;
72
74
76
77 /* These values switch objects based on the object under the cursor. */
82
84
85 bool extend;
86 bool do_cut;
87
88 float cuts; /* cuts as float so smooth mouse pan works in small increments */
90};
91
92/* modal loop selection drawing callback */
93static void ringsel_draw(const bContext * /*C*/, ARegion * /*region*/, void *arg)
94{
95 RingSelOpData *lcd = static_cast<RingSelOpData *>(arg);
96 if (lcd->ob != nullptr) {
97 EDBM_preselect_edgering_draw(lcd->presel_edgering, lcd->ob->object_to_world().ptr());
98 }
99}
100
102{
103 if (!lcd->eed) {
104 return;
105 }
106
107 if (!lcd->extend) {
108 for (Base *base : lcd->bases) {
109 Object *ob_iter = base->object;
112 DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT);
114 }
115 }
116
117 BMEditMesh *em = lcd->em;
118 BMEdge *eed_start = lcd->eed;
119 BMWalker walker;
120 BMEdge *eed;
121 BMW_init(&walker,
122 em->bm,
129
130 for (eed = static_cast<BMEdge *>(BMW_begin(&walker, eed_start)); eed;
131 eed = static_cast<BMEdge *>(BMW_step(&walker)))
132 {
133 BM_edge_select_set(em->bm, eed, true);
134 }
135 BMW_end(&walker);
136}
137
138static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines)
139{
140 if (lcd->eed) {
141 MeshCoordsCache *gcache = &lcd->geom_cache[lcd->base_index];
142 if (gcache->is_init == false) {
143 Scene *scene_eval = DEG_get_evaluated(lcd->vc.depsgraph, lcd->vc.scene);
144 Object *ob_eval = DEG_get_evaluated(lcd->vc.depsgraph, lcd->ob);
145 BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
147 lcd->vc.depsgraph, em_eval, scene_eval, ob_eval, gcache->allocated_vert_positions);
148 gcache->is_init = true;
149 }
150
152 lcd->presel_edgering, lcd->em->bm, lcd->eed, previewlines, gcache->vert_positions);
153 }
154 else {
156 }
157}
158
160{
161 RingSelOpData *lcd = static_cast<RingSelOpData *>(op->customdata);
162 const int cuts = RNA_int_get(op->ptr, "number_cuts");
163 const float smoothness = RNA_float_get(op->ptr, "smoothness");
164 const int smooth_falloff = RNA_enum_get(op->ptr, "falloff");
165#ifdef BMW_EDGERING_NGON
166 const bool use_only_quads = false;
167#else
168 const bool use_only_quads = false;
169#endif
170
171 if (lcd->eed) {
172 BMEditMesh *em = lcd->em;
173 BMVert *v_eed_orig[2] = {lcd->eed->v1, lcd->eed->v2};
174
175 edgering_select(lcd);
176
177 if (lcd->do_cut) {
178 const bool is_macro = (op->opm != nullptr);
179 /* a single edge (rare, but better support) */
180 const bool is_edge_wire = BM_edge_is_wire(lcd->eed);
181 const bool is_single = is_edge_wire || !BM_edge_is_any_face_len_test(lcd->eed, 4);
182 const int seltype = is_edge_wire ? SUBDIV_SELECT_INNER :
183 is_single ? SUBDIV_SELECT_NONE :
185
186 /* Enable grid-fill, so that intersecting loop-cut works as one would expect.
187 * Note though that it will break edge-slide in this specific case.
188 * See #31939. */
191 smoothness,
192 smooth_falloff,
193 true,
194 0.0f,
195 0.0f,
196 cuts,
197 seltype,
199 0,
200 true,
201 use_only_quads,
202 0);
203
204 /* When used in a macro the tessellation will be recalculated anyway,
205 * this is needed here because modifiers depend on updated tessellation, see #45920 */
207 params.calc_looptris = true;
208 params.calc_normals = false;
209 params.is_destructive = true;
210 EDBM_update(static_cast<Mesh *>(lcd->ob->data), &params);
211
212 if (is_single) {
213 /* de-select endpoints */
214 BM_vert_select_set(em->bm, v_eed_orig[0], false);
215 BM_vert_select_set(em->bm, v_eed_orig[1], false);
216
218 }
219 /* We can't slide multiple edges in vertex select mode, force edge select mode. Do this for
220 * all meshes in multi-object editmode so their selectmode is in sync for following
221 * operators. */
222 else if (is_macro && (cuts > 1) && (em->selectmode & SCE_SELECT_VERTEX)) {
224 }
225 /* Force edge slide to edge select mode in face select mode. Do this for all meshes in
226 * multi-object editmode so their selectmode is in sync for following operators. */
228 /* pass, the change will flush selection */
229 }
230 else {
231 /* else flush explicitly */
233 }
234 }
235 else {
236 /* XXX Is this piece of code ever used now? Simple loop select is now
237 * in editmesh_select.cc (around line 1000)... */
238 /* sets as active, useful for other tools */
239 if (em->selectmode & SCE_SELECT_VERTEX) {
240 /* low priority TODO: get vertex close to mouse. */
241 BM_select_history_store(em->bm, lcd->eed->v1);
242 }
243 if (em->selectmode & SCE_SELECT_EDGE) {
244 BM_select_history_store(em->bm, lcd->eed);
245 }
246
248
249 DEG_id_tag_update(static_cast<ID *>(lcd->ob->data), ID_RECALC_SELECT);
251 }
252
254 }
255}
256
257/* called when modal loop selection is done... */
258static void ringsel_exit(bContext * /*C*/, wmOperator *op)
259{
260 RingSelOpData *lcd = static_cast<RingSelOpData *>(op->customdata);
261
262 /* Type can be null in background mode. */
263 if (lcd->region->runtime->type) {
264 /* deactivate the extra drawing stuff in 3D-View */
266 }
267
269
271
272 MEM_delete(lcd);
273 op->customdata = nullptr;
274}
275
276/* called when modal loop selection gets set up... */
277static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
278{
279 Scene *scene = CTX_data_scene(C);
280
281 /* alloc new customdata */
282 RingSelOpData *lcd = MEM_new<RingSelOpData>(__func__);
283 op->customdata = lcd;
284 lcd->vc = em_setup_viewcontext(C);
285
287
288 /* assign the drawing handle for drawing preview line... */
289 lcd->region = CTX_wm_region(C);
290 /* Type can be null in background mode. */
291 if (lcd->region->runtime->type) {
294 }
296 /* Initialize once the cursor is over a mesh. */
297 lcd->ob = nullptr;
298 lcd->em = nullptr;
299 lcd->extend = do_cut ? false : RNA_boolean_get(op->ptr, "extend");
300 lcd->do_cut = do_cut;
301 lcd->cuts = RNA_int_get(op->ptr, "number_cuts");
302 lcd->smoothness = RNA_float_get(op->ptr, "smoothness");
303
304 initNumInput(&lcd->num);
305 lcd->num.idx_max = 1;
307 /* No specific flags for smoothness. */
308 lcd->num.unit_sys = scene->unit.system;
309 lcd->num.unit_type[0] = B_UNIT_NONE;
310 lcd->num.unit_type[1] = B_UNIT_NONE;
311
313
314 return 1;
315}
316
318{
319 /* this is just a wrapper around exit() */
320 ringsel_exit(C, op);
321}
322
324 uint base_index,
325 BMEdge *e,
326 const int previewlines)
327{
328 if (e != lcd->eed) {
329 lcd->eed = e;
330 lcd->ob = lcd->vc.obedit;
331 lcd->base_index = base_index;
332 lcd->em = lcd->vc.em;
333 ringsel_find_edge(lcd, previewlines);
334 }
335 else if (e == nullptr) {
336 lcd->ob = nullptr;
337 lcd->em = nullptr;
338 lcd->base_index = UINT_MAX;
339 }
340}
341
342static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines)
343{
344 struct {
345 Object *ob;
346 BMEdge *eed;
347 float dist;
348 int base_index;
349 } best{};
350 best.dist = ED_view3d_select_dist_px();
351
352 uint base_index;
354 &lcd->vc, &best.dist, nullptr, false, false, nullptr, lcd->bases, &base_index);
355
356 if (eed_test) {
357 best.ob = lcd->bases[base_index]->object;
358 best.eed = eed_test;
359 best.base_index = base_index;
360 }
361
362 if (best.eed) {
364 }
365
366 loopcut_update_edge(lcd, best.base_index, best.eed, previewlines);
367}
368
369/* called by both init() and exec() */
371{
372 /* Check whether both `rv3d` and `event` is present, this way we allow the loopcut operator to
373 * run non-interactively no matter whether the graphical UI is present or not (e.g. from scripts
374 * with UI running, or entirely in the background with `blender -b`). */
376 const bool is_interactive = (rv3d != nullptr) && (event != nullptr);
377
378 /* Use for redo - intentionally wrap int to uint. */
379 struct {
380 uint base_index;
381 uint e_index;
382 } exec_data{};
383 exec_data.base_index = uint(RNA_int_get(op->ptr, "object_index"));
384 exec_data.e_index = uint(RNA_int_get(op->ptr, "edge_index"));
385
386 const Scene *scene = CTX_data_scene(C);
387 ViewLayer *view_layer = CTX_data_view_layer(C);
388
390 scene, view_layer, CTX_wm_view3d(C));
391
392 if (is_interactive) {
393 for (Base *base : bases) {
394 Object *ob_iter = base->object;
397 {
399 op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display");
400 break;
401 }
402 }
403 }
404
405 if (is_interactive) {
407 }
408
409 /* for re-execution, check edge index is in range before we setup ringsel */
410 bool ok = true;
411 if (is_interactive == false) {
412 if (exec_data.base_index >= bases.size()) {
413 ok = false;
414 }
415 else {
416 Object *ob_iter = bases[exec_data.base_index]->object;
418 if (exec_data.e_index >= em->bm->totedge) {
419 ok = false;
420 }
421 }
422 }
423
424 if (!ok || !ringsel_init(C, op, true)) {
425 return OPERATOR_CANCELLED;
426 }
427
428 /* add a modal handler for this operator - handles loop selection */
429 if (is_interactive) {
432 }
433
434 RingSelOpData *lcd = static_cast<RingSelOpData *>(op->customdata);
435
436 lcd->bases = std::move(bases);
437 lcd->geom_cache.reinitialize(lcd->bases.size());
438
439 if (is_interactive) {
440 copy_v2_v2_int(lcd->vc.mval, event->mval);
441 loopcut_mouse_move(lcd, is_interactive ? 1 : 0);
442 }
443 else {
444
445 Object *ob_iter = lcd->bases[exec_data.base_index]->object;
447
448 BMEdge *e;
450 e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index);
451 loopcut_update_edge(lcd, exec_data.base_index, e, 0);
452 }
453
454#ifdef USE_LOOPSLIDE_HACK
455 /* for use in macro so we can restore, HACK */
456 {
457 ToolSettings *settings = scene->toolsettings;
458 const bool mesh_select_mode[3] = {
459 (settings->selectmode & SCE_SELECT_VERTEX) != 0,
460 (settings->selectmode & SCE_SELECT_EDGE) != 0,
461 (settings->selectmode & SCE_SELECT_FACE) != 0,
462 };
463
464 RNA_boolean_set_array(op->ptr, "mesh_select_mode_init", mesh_select_mode);
465 }
466#endif
467
468 if (is_interactive) {
469 char buf[UI_MAX_DRAW_STR];
470 char str_rep[NUM_STR_REP_LEN * 2];
471 if (hasNumInput(&lcd->num)) {
472 outputNumInput(&lcd->num, str_rep, scene->unit);
473 }
474 else {
475 BLI_snprintf_utf8(str_rep, NUM_STR_REP_LEN, "%d", int(lcd->cuts));
477 }
478 SNPRINTF_UTF8(buf, IFACE_("Cuts: %s, Smoothness: %s"), str_rep, str_rep + NUM_STR_REP_LEN);
480
482 status.item(IFACE_("Confirm"), ICON_MOUSE_LMB);
483 status.item(IFACE_("Cancel"), ICON_MOUSE_RMB);
484 status.item(IFACE_("Select Ring"), ICON_MOUSE_MOVE);
485 status.item("", ICON_MOUSE_MMB);
486 status.item(IFACE_("Number of Cuts"), ICON_EVENT_PAGEUP, ICON_EVENT_PAGEDOWN);
487 status.item(IFACE_("Smoothness"), ICON_EVENT_ALT, ICON_MOUSE_MMB);
489 }
490
491 ringsel_finish(C, op);
492 ringsel_exit(C, op);
493 return OPERATOR_FINISHED;
494}
495
497{
498 /* When accessed as a tool, get the active edge from the pre-selection gizmo. */
499 {
500 ARegion *region = CTX_wm_region(C);
501 wmGizmoMap *gzmap = region->runtime->gizmo_map;
502 wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap,
503 "VIEW3D_GGT_mesh_preselect_edgering") :
504 nullptr;
505 if ((gzgroup != nullptr) && gzgroup->gizmos.first) {
506 wmGizmo *gz = static_cast<wmGizmo *>(gzgroup->gizmos.first);
507 const int object_index = RNA_int_get(gz->ptr, "object_index");
508 const int edge_index = RNA_int_get(gz->ptr, "edge_index");
509
510 if (object_index != -1 && edge_index != -1) {
511 RNA_int_set(op->ptr, "object_index", object_index);
512 RNA_int_set(op->ptr, "edge_index", edge_index);
513 return loopcut_init(C, op, nullptr);
514 }
515 return OPERATOR_CANCELLED;
516 }
517 }
518
519 return loopcut_init(C, op, event);
520}
521
523{
524 return loopcut_init(C, op, nullptr);
525}
526
528{
529 /* finish */
531 ED_workspace_status_text(C, nullptr);
533
534 if (lcd->eed) {
535 /* set for redo */
537 RNA_int_set(op->ptr, "object_index", lcd->base_index);
538 RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed));
539
540 /* execute */
541 ringsel_finish(C, op);
542 ringsel_exit(C, op);
543 }
544 else {
545 ringcut_cancel(C, op);
546 return OPERATOR_CANCELLED;
547 }
548
549 return OPERATOR_FINISHED;
550}
551
553{
554 if (event->type == NDOF_MOTION) {
556 }
557
558 RingSelOpData *lcd = static_cast<RingSelOpData *>(op->customdata);
559 float cuts = lcd->cuts;
560 float smoothness = lcd->smoothness;
561 bool show_cuts = false;
562 const bool has_numinput = hasNumInput(&lcd->num);
563
564 lcd->vc = em_setup_viewcontext(C);
565 lcd->region = lcd->vc.region;
566
568
569 /* using the keyboard to input the number of cuts */
570 /* Modal numinput active, try to handle numeric inputs first... */
571 if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) {
572 float values[2] = {cuts, smoothness};
573 applyNumInput(&lcd->num, values);
574 cuts = values[0];
575 smoothness = values[1];
576 }
577 else {
578 bool handled = false;
579 switch (event->type) {
580 case EVT_RETKEY:
581 case EVT_PADENTER:
582 case LEFTMOUSE: /* confirm */ /* XXX hardcoded */
583 if (event->val == KM_PRESS) {
584 return loopcut_finish(lcd, C, op);
585 }
586
588 handled = true;
589 break;
590 case RIGHTMOUSE: /* abort */ /* XXX hardcoded */
592 ringsel_exit(C, op);
593 ED_workspace_status_text(C, nullptr);
595
596 return OPERATOR_CANCELLED;
597 case EVT_ESCKEY:
598 if (event->val == KM_RELEASE) {
599 /* cancel */
601 ED_workspace_status_text(C, nullptr);
603
604 ringcut_cancel(C, op);
605 return OPERATOR_CANCELLED;
606 }
607
609 handled = true;
610 break;
611 case MOUSEPAN:
612 if ((event->modifier & KM_ALT) == 0) {
613 cuts += 0.02f * (event->xy[1] - event->prev_xy[1]);
614 if (cuts < 1 && lcd->cuts >= 1) {
615 cuts = 1;
616 }
617 }
618 else {
619 smoothness += 0.002f * (event->xy[1] - event->prev_xy[1]);
620 }
621 handled = true;
622 break;
623 case EVT_PADPLUSKEY:
624 case EVT_PAGEUPKEY:
625 case WHEELUPMOUSE: /* change number of cuts */
626 if (event->val == KM_RELEASE) {
627 break;
628 }
629 if ((event->modifier & KM_ALT) == 0) {
630 cuts += 1;
631 }
632 else {
633 smoothness += 0.05f;
634 }
635 handled = true;
636 break;
637 case EVT_PADMINUS:
638 case EVT_PAGEDOWNKEY:
639 case WHEELDOWNMOUSE: /* change number of cuts */
640 if (event->val == KM_RELEASE) {
641 break;
642 }
643 if ((event->modifier & KM_ALT) == 0) {
644 cuts = max_ff(cuts - 1, 1);
645 }
646 else {
647 smoothness -= 0.05f;
648 }
649 handled = true;
650 break;
651 case MOUSEMOVE: {
652/* mouse moved somewhere to select another loop */
653
654/* This is normally disabled for all modal operators.
655 * This is an exception since mouse movement doesn't relate to numeric input.
656 *
657 * If numeric input changes we'll need to add this back see: D2973 */
658#if 0
659 if (!has_numinput)
660#endif
661 {
662 lcd->vc.mval[0] = event->mval[0];
663 lcd->vc.mval[1] = event->mval[1];
664 loopcut_mouse_move(lcd, int(lcd->cuts));
665
667 handled = true;
668 }
669 break;
670 }
671 default: {
672 break;
673 }
674 }
675
676 /* Modal numinput inactive, try to handle numeric inputs last... */
677 if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) {
678 float values[2] = {cuts, smoothness};
679 applyNumInput(&lcd->num, values);
680 cuts = values[0];
681 smoothness = values[1];
682 }
683 }
684
685 if (cuts != lcd->cuts) {
686 /* allow zero so you can backspace and type in a value
687 * otherwise 1 as minimum would make more sense */
688 lcd->cuts = clamp_f(cuts, 0, SUBD_CUTS_MAX);
689 RNA_int_set(op->ptr, "number_cuts", int(lcd->cuts));
690 ringsel_find_edge(lcd, int(lcd->cuts));
691 show_cuts = true;
693 }
694
695 if (smoothness != lcd->smoothness) {
697 RNA_float_set(op->ptr, "smoothness", lcd->smoothness);
698 show_cuts = true;
700 }
701
702 if (show_cuts) {
703 Scene *sce = CTX_data_scene(C);
704 char buf[UI_MAX_DRAW_STR];
705 char str_rep[NUM_STR_REP_LEN * 2];
706 if (hasNumInput(&lcd->num)) {
707 outputNumInput(&lcd->num, str_rep, sce->unit);
708 }
709 else {
710 BLI_snprintf_utf8(str_rep, NUM_STR_REP_LEN, "%d", int(lcd->cuts));
711 BLI_snprintf_utf8(str_rep + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%.2f", smoothness);
712 }
713 SNPRINTF_UTF8(buf, IFACE_("Cuts: %s, Smoothness: %s"), str_rep, str_rep + NUM_STR_REP_LEN);
715 }
716
717 /* keep going until the user confirms */
719}
720
721/* for bmesh this tool is in bmesh_select.c */
722#if 0
723
725{
726 /* description */
727 ot->name = "Edge Ring Select";
728 ot->idname = "MESH_OT_edgering_select";
729 ot->description = "Select an edge ring";
730
731 /* callbacks */
732 ot->invoke = ringsel_invoke;
734
735 /* flags */
737
738 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
739}
740
741#endif
742
744{
745 PropertyRNA *prop;
746
747 /* description */
748 ot->name = "Loop Cut";
749 ot->idname = "MESH_OT_loopcut";
750 ot->description = "Add a new loop between existing loops";
751
752 /* callbacks */
753 ot->invoke = ringcut_invoke;
754 ot->exec = loopcut_exec;
755 ot->modal = loopcut_modal;
756 ot->cancel = ringcut_cancel;
757 /* Note the #RegionView3D is needed for interactive use, the operator must check this. */
758 ot->poll = ED_operator_editmesh;
759
760 /* flags */
762
763 /* properties */
764 prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000000, "Number of Cuts", "", 1, 100);
765 /* avoid re-using last var because it can cause
766 * _very_ high poly meshes and annoy users (or worse crash) */
768
769 prop = RNA_def_float(ot->srna,
770 "smoothness",
771 0.0f,
772 -1e3f,
773 1e3f,
774 "Smoothness",
775 "Smoothness factor",
779
781
782 prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE);
785 RNA_def_property_ui_text(prop, "Falloff", "Falloff type of the feather");
787 BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */
788
789 /* For redo only. */
790 prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", 0, INT_MAX);
793 prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", 0, INT_MAX);
795
796#ifdef USE_LOOPSLIDE_HACK
797 prop = RNA_def_boolean_array(ot->srna, "mesh_select_mode_init", 3, nullptr, "", "");
799#endif
800}
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:61
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)
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
@ B_UNIT_NONE
Definition BKE_unit.hh:136
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 size_t size_t BLI_snprintf_utf8(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define SNPRINTF_UTF8(dst, format,...)
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)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_SELECT
Definition DNA_ID.h:1101
Object is a sort of wrapper for general info.
@ PROP_INVSQUARE
@ SCE_SELECT_FACE
@ SCE_SELECT_VERTEX
@ SCE_SELECT_EDGE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ OP_IS_MODAL_CURSOR_REGION
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)
bool EDBM_uvselect_clear(BMEditMesh *em)
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
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
void outputNumInput(NumInput *n, char *str, const UnitSettings &unit_settings)
Definition numinput.cc:88
bool hasNumInput(const NumInput *n)
Definition numinput.cc:171
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:851
bool ED_operator_editmesh_region_view3d(bContext *C)
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:1024
bool ED_operator_editmesh(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
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_gpu(const bContext *C)
void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
Read Guarded memory(de)allocation.
@ PROP_ENUM
Definition RNA_types.hh:166
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
@ PROP_NONE
Definition RNA_types.hh:233
#define C
Definition RandGen.cpp:29
#define UI_MAX_DRAW_STR
#define NC_GEOM
Definition WM_types.hh:393
@ KM_ALT
Definition WM_types.hh:280
@ KM_PRESS
Definition WM_types.hh:311
@ KM_RELEASE
Definition WM_types.hh:312
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_SELECT
Definition WM_types.hh:508
@ 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)
Initialize 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
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 wmOperatorStatus loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines)
static wmOperatorStatus loopcut_exec(bContext *C, wmOperator *op)
#define SUBD_SMOOTH_MAX
static wmOperatorStatus loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op)
static void ringcut_cancel(bContext *C, wmOperator *op)
static wmOperatorStatus ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
#define SUBD_CUTS_MAX
void MESH_OT_loopcut(wmOperatorType *ot)
static void ringsel_finish(bContext *C, wmOperator *op)
static void edgering_select(RingSelOpData *lcd)
static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines)
void MESH_OT_edgering_select(wmOperatorType *ot)
#define UINT_MAX
Definition hash_md5.cc:44
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
VecBase< float, 3 > float3
const int status
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:112
ARegionRuntimeHandle * runtime
BMVert * v1
BMVert * v2
short selectmode
int totedge
struct Object * object
Definition DNA_ID.h:414
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 ToolSettings * toolsettings
struct UnitSettings unit
ARegion * region
Definition ED_view3d.hh:77
int mval[2]
Definition ED_view3d.hh:82
Scene * scene
Definition ED_view3d.hh:73
BMEditMesh * em
Definition ED_view3d.hh:81
Object * obedit
Definition ED_view3d.hh:76
Depsgraph * depsgraph
Definition ED_view3d.hh:72
wmEventModifierFlag modifier
Definition WM_types.hh:774
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int mval[2]
Definition WM_types.hh:763
PointerRNA * ptr
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:4237
wmGizmoGroup * WM_gizmomap_group_find(wmGizmoMap *gzmap, const char *idname)
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)