Blender V4.3
editmesh_extrude.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2004 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#include "DNA_object_types.h"
11
12#include "BLI_listbase.h"
13#include "BLI_math_matrix.h"
14#include "BLI_math_rotation.h"
15#include "BLI_math_vector.h"
16
17#include "BKE_context.hh"
18#include "BKE_editmesh.hh"
19#include "BKE_layer.hh"
20#include "BKE_object_types.hh"
21#include "BKE_report.hh"
22
23#include "RNA_access.hh"
24#include "RNA_define.hh"
25
26#include "WM_api.hh"
27#include "WM_types.hh"
28
29#include "ED_mesh.hh"
30#include "ED_screen.hh"
31#include "ED_transform.hh"
32#include "ED_view3d.hh"
33
34#include "MEM_guardedalloc.h"
35
36#include "mesh_intern.hh" /* own include */
37
38using blender::Vector;
39
40/* -------------------------------------------------------------------- */
45 Object *obedit, BMEditMesh *em, const char hflag, BMOperator *op, BMOpSlot *slot_edges_exclude)
46{
47 BMesh *bm = em->bm;
48
49 /* If a mirror modifier with clipping is on, we need to adjust some
50 * of the cases above to handle edges on the line of symmetry.
51 */
52 LISTBASE_FOREACH (ModifierData *, md, &obedit->modifiers) {
53 if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
55
56 if (mmd->flag & MOD_MIR_CLIPPING) {
57 BMIter iter;
58 BMEdge *edge;
59
60 float mtx[4][4];
61 if (mmd->mirror_ob) {
62 float imtx[4][4];
63 invert_m4_m4(imtx, mmd->mirror_ob->object_to_world().ptr());
64 mul_m4_m4m4(mtx, imtx, obedit->object_to_world().ptr());
65 }
66
67 BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
68 if (BM_elem_flag_test(edge, hflag) && BM_edge_is_boundary(edge) &&
69 BM_elem_flag_test(edge->l->f, hflag))
70 {
71 float co1[3], co2[3];
72
73 copy_v3_v3(co1, edge->v1->co);
74 copy_v3_v3(co2, edge->v2->co);
75
76 if (mmd->mirror_ob) {
77 mul_v3_m4v3(co1, mtx, co1);
78 mul_v3_m4v3(co2, mtx, co2);
79 }
80
81 if (mmd->flag & MOD_MIR_AXIS_X) {
82 if ((fabsf(co1[0]) < mmd->tolerance) && (fabsf(co2[0]) < mmd->tolerance)) {
83 BMO_slot_map_empty_insert(op, slot_edges_exclude, edge);
84 }
85 }
86 if (mmd->flag & MOD_MIR_AXIS_Y) {
87 if ((fabsf(co1[1]) < mmd->tolerance) && (fabsf(co2[1]) < mmd->tolerance)) {
88 BMO_slot_map_empty_insert(op, slot_edges_exclude, edge);
89 }
90 }
91 if (mmd->flag & MOD_MIR_AXIS_Z) {
92 if ((fabsf(co1[2]) < mmd->tolerance) && (fabsf(co2[2]) < mmd->tolerance)) {
93 BMO_slot_map_empty_insert(op, slot_edges_exclude, edge);
94 }
95 }
96 }
97 }
98 }
99 }
100 }
101}
102
103/* individual face extrude */
104/* will use vertex normals for extrusion directions, so *nor is unaffected */
105static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag)
106{
107 BMOIter siter;
108 BMIter liter;
109 BMFace *f;
110 BMLoop *l;
111 BMOperator bmop;
112
114 em, &bmop, op, "extrude_discrete_faces faces=%hf use_select_history=%b", hflag, true);
115
116 /* deselect original verts */
118
119 BMO_op_exec(em->bm, &bmop);
120
121 BMO_ITER (f, &siter, bmop.slots_out, "faces.out", BM_FACE) {
122 BM_face_select_set(em->bm, f, true);
123
124 /* set face vertex normals to face normal */
125 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
126 copy_v3_v3(l->v->no, f->no);
127 }
128 }
129
130 if (!EDBM_op_finish(em, &bmop, op, true)) {
131 return false;
132 }
133
134 return true;
135}
136
138 wmOperator *op,
139 const char hflag,
140 const bool use_normal_flip)
141{
142 BMesh *bm = em->bm;
143 BMOperator bmop;
144
145 EDBM_op_init(em,
146 &bmop,
147 op,
148 "extrude_edge_only edges=%he use_normal_flip=%b use_select_history=%b",
149 hflag,
150 use_normal_flip,
151 true);
152
153 /* deselect original verts */
157
158 BMO_op_exec(em->bm, &bmop);
160 em->bm, bmop.slots_out, "geom.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true);
161
162 if (!EDBM_op_finish(em, &bmop, op, true)) {
163 return false;
164 }
165
166 return true;
167}
168
169/* extrudes individual vertices */
170static bool edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag)
171{
172 BMOperator bmop;
173
174 EDBM_op_init(em, &bmop, op, "extrude_vert_indiv verts=%hv use_select_history=%b", hflag, true);
175
176 /* deselect original verts */
178
179 BMO_op_exec(em->bm, &bmop);
180 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true);
181
182 if (!EDBM_op_finish(em, &bmop, op, true)) {
183 return false;
184 }
185
186 return true;
187}
188
190{
191 char htype = BM_ALL_NOLOOP;
192
193 if (em->selectmode & SCE_SELECT_VERTEX) {
194 /* pass */
195 }
196 else if (em->selectmode & SCE_SELECT_EDGE) {
197 htype &= ~BM_VERT;
198 }
199 else {
200 htype &= ~(BM_VERT | BM_EDGE);
201 }
202
203 if (em->bm->totedgesel == 0) {
204 htype &= ~(BM_EDGE | BM_FACE);
205 }
206 else if (em->bm->totfacesel == 0) {
207 htype &= ~BM_FACE;
208 }
209
210 return htype;
211}
212
213static bool edbm_extrude_ex(Object *obedit,
214 BMEditMesh *em,
215 char htype,
216 const char hflag,
217 const bool use_normal_flip,
218 const bool use_dissolve_ortho_edges,
219 const bool use_mirror,
220 const bool use_select_history)
221{
222 BMesh *bm = em->bm;
223 BMOIter siter;
224 BMOperator extop;
225 BMElem *ele;
226
227 /* needed to remove the faces left behind */
228 if (htype & BM_FACE) {
229 htype |= BM_EDGE;
230 }
231
232 BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region");
233 BMO_slot_bool_set(extop.slots_in, "use_normal_flip", use_normal_flip);
234 BMO_slot_bool_set(extop.slots_in, "use_dissolve_ortho_edges", use_dissolve_ortho_edges);
235 BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history);
236 BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, hflag);
237
238 if (use_mirror) {
239 BMOpSlot *slot_edges_exclude;
240 slot_edges_exclude = BMO_slot_get(extop.slots_in, "edges_exclude");
241
242 edbm_extrude_edge_exclude_mirror(obedit, em, hflag, &extop, slot_edges_exclude);
243 }
244
248
249 BMO_op_exec(bm, &extop);
250
251 BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) {
252 BM_elem_select_set(bm, ele, true);
253 }
254
255 BMO_op_finish(bm, &extop);
256
257 return true;
258}
259
262/* -------------------------------------------------------------------- */
267{
268
269 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset");
270 const int steps = RNA_int_get(op->ptr, "steps");
271 const float scale_offset = RNA_float_get(op->ptr, "scale_offset");
272 float offset[3];
273
274 if (!RNA_property_is_set(op->ptr, prop)) {
276 if (rv3d != nullptr) {
277 normalize_v3_v3(offset, rv3d->persinv[2]);
278 }
279 else {
280 const float up[3] = {0, 0, 1};
281 copy_v3_v3(offset, up);
282 }
283 RNA_property_float_set_array(op->ptr, prop, offset);
284 }
285 else {
286 RNA_property_float_get_array(op->ptr, prop, offset);
287 }
288
289 mul_v3_fl(offset, scale_offset);
290
291 const Scene *scene = CTX_data_scene(C);
292 ViewLayer *view_layer = CTX_data_view_layer(C);
294 scene, view_layer, CTX_wm_view3d(C));
295
296 for (Object *obedit : objects) {
297 float offset_local[3], tmat[3][3];
298
300
301 copy_m3_m4(tmat, obedit->object_to_world().ptr());
302 invert_m3(tmat);
303 mul_v3_m3v3(offset_local, tmat, offset);
304
305 for (int a = 0; a < steps; a++) {
306 edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false, true);
308 em->bm, BMO_FLAG_DEFAULTS, "translate vec=%v verts=%hv", offset_local, BM_ELEM_SELECT);
309 }
310
312 params.calc_looptris = true;
313 params.calc_normals = true;
314 params.is_destructive = true;
315 EDBM_update(static_cast<Mesh *>(obedit->data), &params);
316 }
317
318 return OPERATOR_FINISHED;
319}
320
322{
323 /* identifiers */
324 ot->name = "Extrude Repeat";
325 ot->description = "Extrude selected vertices, edges or faces repeatedly";
326 ot->idname = "MESH_OT_extrude_repeat";
327
328 /* api callbacks */
331
332 /* flags */
334
335 /* props */
336 RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180);
338 "offset",
339 3,
340 nullptr,
341 -100000,
342 100000,
343 "Offset",
344 "Offset vector",
345 -1000.0f,
346 1000.0f);
348 RNA_def_float(ot->srna, "scale_offset", 1.0f, 0.0f, 1e12f, "Scale Offset", "", 0.0f, 100.0f);
349}
350
353/* -------------------------------------------------------------------- */
358static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
359{
360 const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip");
361 const bool use_dissolve_ortho_edges = RNA_boolean_get(op->ptr, "use_dissolve_ortho_edges");
362 const char htype = edbm_extrude_htype_from_em_select(em);
363 enum { NONE = 0, ELEM_FLAG, VERT_ONLY, EDGE_ONLY } nr;
364 bool changed = false;
365
366 if (em->selectmode & SCE_SELECT_VERTEX) {
367 if (em->bm->totvertsel == 0) {
368 nr = NONE;
369 }
370 else if (em->bm->totvertsel == 1) {
371 nr = VERT_ONLY;
372 }
373 else if (em->bm->totedgesel == 0) {
374 nr = VERT_ONLY;
375 }
376 else {
377 nr = ELEM_FLAG;
378 }
379 }
380 else if (em->selectmode & SCE_SELECT_EDGE) {
381 if (em->bm->totedgesel == 0) {
382 nr = NONE;
383 }
384 else if (em->bm->totfacesel == 0) {
385 nr = EDGE_ONLY;
386 }
387 else {
388 nr = ELEM_FLAG;
389 }
390 }
391 else {
392 if (em->bm->totfacesel == 0) {
393 nr = NONE;
394 }
395 else {
396 nr = ELEM_FLAG;
397 }
398 }
399
400 switch (nr) {
401 case NONE:
402 return false;
403 case ELEM_FLAG:
404 changed = edbm_extrude_ex(obedit,
405 em,
406 htype,
408 use_normal_flip,
409 use_dissolve_ortho_edges,
410 true,
411 true);
412 break;
413 case VERT_ONLY:
414 changed = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
415 break;
416 case EDGE_ONLY:
417 changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip);
418 break;
419 }
420
421 if (changed) {
422 return true;
423 }
424
425 BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
426 return false;
427}
428
429/* extrude without transform */
431{
432 const Scene *scene = CTX_data_scene(C);
433 ViewLayer *view_layer = CTX_data_view_layer(C);
435 scene, view_layer, CTX_wm_view3d(C));
436
437 for (Object *obedit : objects) {
439 if (em->bm->totvertsel == 0) {
440 continue;
441 }
442
443 if (!edbm_extrude_mesh(obedit, em, op)) {
444 continue;
445 }
446 /* This normally happens when pushing undo but modal operators
447 * like this one don't push undo data until after modal mode is done. */
449 params.calc_looptris = true;
450 params.calc_normals = true;
451 params.is_destructive = true;
452 EDBM_update(static_cast<Mesh *>(obedit->data), &params);
453 }
454 return OPERATOR_FINISHED;
455}
456
458{
459 /* identifiers */
460 ot->name = "Extrude Region";
461 ot->idname = "MESH_OT_extrude_region";
462 ot->description = "Extrude region of faces";
463
464 /* api callbacks */
465 // ot->invoke = mesh_extrude_region_invoke;
468
469 /* flags */
471
472 RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
473 RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", "");
475}
476
479/* -------------------------------------------------------------------- */
485/* extrude without transform */
487{
488 const Scene *scene = CTX_data_scene(C);
489 ViewLayer *view_layer = CTX_data_view_layer(C);
491 scene, view_layer, CTX_wm_view3d(C));
492
493 for (Object *obedit : objects) {
495 if (em->bm->totvertsel == 0) {
496 continue;
497 }
498
499 edbm_extrude_mesh(obedit, em, op);
500
501 /* This normally happens when pushing undo but modal operators
502 * like this one don't push undo data until after modal mode is done. */
504 params.calc_looptris = true;
505 params.calc_normals = true;
506 params.is_destructive = true;
507 EDBM_update(static_cast<Mesh *>(obedit->data), &params);
508 }
509 return OPERATOR_FINISHED;
510}
511
513{
514 /* identifiers */
515 ot->name = "Extrude Context";
516 ot->idname = "MESH_OT_extrude_context";
517 ot->description = "Extrude selection";
518
519 /* api callbacks */
522
523 /* flags */
525
526 RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
527 RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", "");
529}
530
533/* -------------------------------------------------------------------- */
538{
539 const Scene *scene = CTX_data_scene(C);
540 ViewLayer *view_layer = CTX_data_view_layer(C);
542 scene, view_layer, CTX_wm_view3d(C));
543
544 for (Object *obedit : objects) {
546 if (em->bm->totvertsel == 0) {
547 continue;
548 }
549
551
553 params.calc_looptris = true;
554 params.calc_normals = false;
555 params.is_destructive = true;
556 EDBM_update(static_cast<Mesh *>(obedit->data), &params);
557 }
558
559 return OPERATOR_FINISHED;
560}
561
563{
564 /* identifiers */
565 ot->name = "Extrude Only Vertices";
566 ot->idname = "MESH_OT_extrude_verts_indiv";
567 ot->description = "Extrude individual vertices only";
568
569 /* api callbacks */
572
573 /* flags */
575
576 /* to give to transform */
578}
579
582/* -------------------------------------------------------------------- */
587{
588 const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip");
589 const Scene *scene = CTX_data_scene(C);
590 ViewLayer *view_layer = CTX_data_view_layer(C);
592 scene, view_layer, CTX_wm_view3d(C));
593
594 for (Object *obedit : objects) {
596 if (em->bm->totedgesel == 0) {
597 continue;
598 }
599
600 edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip);
601
603 params.calc_looptris = true;
604 params.calc_normals = false;
605 params.is_destructive = true;
606 EDBM_update(static_cast<Mesh *>(obedit->data), &params);
607 }
608
609 return OPERATOR_FINISHED;
610}
611
613{
614 /* identifiers */
615 ot->name = "Extrude Only Edges";
616 ot->idname = "MESH_OT_extrude_edges_indiv";
617 ot->description = "Extrude individual edges only";
618
619 /* api callbacks */
622
623 /* flags */
625
626 /* to give to transform */
627 RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
629}
630
633/* -------------------------------------------------------------------- */
638{
639 const Scene *scene = CTX_data_scene(C);
640 ViewLayer *view_layer = CTX_data_view_layer(C);
642 scene, view_layer, CTX_wm_view3d(C));
643
644 for (Object *obedit : objects) {
646 if (em->bm->totfacesel == 0) {
647 continue;
648 }
649
651
653 params.calc_looptris = true;
654 params.calc_normals = false;
655 params.is_destructive = true;
656 EDBM_update(static_cast<Mesh *>(obedit->data), &params);
657 }
658
659 return OPERATOR_FINISHED;
660}
661
663{
664 /* identifiers */
665 ot->name = "Extrude Individual Faces";
666 ot->idname = "MESH_OT_extrude_faces_indiv";
667 ot->description = "Extrude individual faces only";
668
669 /* api callbacks */
672
673 /* flags */
675
677}
678
681/* -------------------------------------------------------------------- */
688{
690 BMVert *v1;
691 BMIter iter;
692 float center[3];
693 uint verts_len;
694
696 const Object *object_active = vc.obact;
697
698 const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source");
699 const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
702
703 /* First calculate the center of transformation. */
704 zero_v3(center);
705 verts_len = 0;
706
708 vc.scene, vc.view_layer, vc.v3d);
709 for (Object *obedit : objects) {
711 const int local_verts_len = vc.em->bm->totvertsel;
712
713 if (vc.em->bm->totvertsel == 0) {
714 continue;
715 }
716
717 float local_center[3];
718 zero_v3(local_center);
719
720 BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) {
722 add_v3_v3(local_center, v1->co);
723 }
724 }
725
726 mul_v3_fl(local_center, 1.0f / float(local_verts_len));
727 mul_m4_v3(vc.obedit->object_to_world().ptr(), local_center);
728 mul_v3_fl(local_center, float(local_verts_len));
729
730 add_v3_v3(center, local_center);
731 verts_len += local_verts_len;
732 }
733
734 if (verts_len != 0) {
735 mul_v3_fl(center, 1.0f / float(verts_len));
736 }
737
738 /* Then we process the meshes. */
739 for (Object *obedit : objects) {
741
742 if (verts_len != 0) {
743 if (vc.em->bm->totvertsel == 0) {
744 continue;
745 }
746 }
747 else if (obedit != object_active) {
748 continue;
749 }
750
751 invert_m4_m4(vc.obedit->runtime->world_to_object.ptr(), vc.obedit->object_to_world().ptr());
753
754 float local_center[3];
755 mul_v3_m4v3(local_center, vc.obedit->world_to_object().ptr(), center);
756
757 /* call extrude? */
758 if (verts_len != 0) {
759 const char extrude_htype = edbm_extrude_htype_from_em_select(vc.em);
760 BMEdge *eed;
761 float mat[3][3];
762 float vec[3], ofs[3];
763 float nor[3] = {0.0, 0.0, 0.0};
764
765 /* 2D normal calc */
766 const float mval_f[2] = {float(event->mval[0]), float(event->mval[1])};
767
768 /* check for edges that are half selected, use for rotation */
769 bool done = false;
770 BM_ITER_MESH (eed, &iter, vc.em->bm, BM_EDGES_OF_MESH) {
772 float co1[2], co2[2];
773
778 {
779 /* 2D rotate by 90d while adding.
780 * (x, y) = (y, -x)
781 *
782 * Accumulate the screen-space normal in 2D,
783 * with screen-space edge length weighting the result. */
784 if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) {
785 nor[0] += (co1[1] - co2[1]);
786 nor[1] += -(co1[0] - co2[0]);
787 }
788 else {
789 nor[0] += (co2[1] - co1[1]);
790 nor[1] += -(co2[0] - co1[0]);
791 }
792 done = true;
793 }
794 }
795 }
796
797 if (done) {
798 float view_vec[3], cross[3];
799
800 /* convert the 2D normal into 3D */
801 mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* World-space. */
802 mul_mat3_m4_v3(vc.obedit->world_to_object().ptr(), nor); /* Local-space. */
803
804 /* correct the normal to be aligned on the view plane */
805 mul_v3_mat3_m4v3(view_vec, vc.obedit->world_to_object().ptr(), vc.rv3d->viewinv[2]);
806 cross_v3_v3v3(cross, nor, view_vec);
807 cross_v3_v3v3(nor, view_vec, cross);
809 }
810
811 /* center */
812 copy_v3_v3(ofs, local_center);
813
814 mul_m4_v3(vc.obedit->object_to_world().ptr(), ofs); /* view space */
815 ED_view3d_win_to_3d_int(vc.v3d, vc.region, ofs, event->mval, ofs);
816 mul_m4_v3(vc.obedit->world_to_object().ptr(), ofs); /* back in object space */
817
818 sub_v3_v3(ofs, local_center);
819
820 /* calculate rotation */
821 unit_m3(mat);
822 if (done) {
823 float angle;
824
825 normalize_v3_v3(vec, ofs);
826
827 angle = angle_normalized_v3v3(vec, nor);
828
829 if (angle != 0.0f) {
830 float axis[3];
831
832 cross_v3_v3v3(axis, nor, vec);
833
834 /* halve the rotation if its applied twice */
835 if (rot_src) {
836 angle *= 0.5f;
837 }
838
839 axis_angle_to_mat3(mat, axis, angle);
840 }
841 }
842
843 if (rot_src) {
845 vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, local_center, mat);
846
847 /* Also project the source, for retopology workflow. */
848 if (use_proj) {
850 }
851 }
852
853 edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, false, true, true);
855 vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, local_center, mat);
856 EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v", BM_ELEM_SELECT, ofs);
857 }
858 else {
859 /* This only runs for the active object. */
860 const float *cursor = vc.scene->cursor.location;
861 BMOperator bmop;
862 BMOIter oiter;
863
864 copy_v3_v3(local_center, cursor);
865 ED_view3d_win_to_3d_int(vc.v3d, vc.region, local_center, event->mval, local_center);
866
867 mul_m4_v3(vc.obedit->world_to_object().ptr(), local_center); /* back in object space */
868
869 EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", local_center);
870 BMO_op_exec(vc.em->bm, &bmop);
871
872 BMO_ITER (v1, &oiter, bmop.slots_out, "vert.out", BM_VERT) {
873 BM_vert_select_set(vc.em->bm, v1, true);
874 }
875
876 if (!EDBM_op_finish(vc.em, &bmop, op, true)) {
877 continue;
878 }
879 }
880
881 if (use_proj) {
883 }
884
885 /* This normally happens when pushing undo but modal operators
886 * like this one don't push undo data until after modal mode is done. */
888 params.calc_looptris = true;
889 params.calc_normals = true;
890 params.is_destructive = true;
891 EDBM_update(static_cast<Mesh *>(vc.obedit->data), &params);
892
893 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
894 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
895 }
896
897 /* Support dragging to move after extrude, see: #114282. */
898 const int retval = OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
900}
901
903{
904 /* identifiers */
905 ot->name = "Extrude to Cursor or Add";
906 ot->idname = "MESH_OT_dupli_extrude_cursor";
907 ot->description =
908 "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor";
909
910 /* api callbacks */
913
914 /* flags */
916
918 "rotate_source",
919 true,
920 "Rotate Source",
921 "Rotate initial selection giving better shape");
922}
923
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:63
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_edit_mode_unique_data(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define LISTBASE_FOREACH(type, var, list)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void unit_m3(float m[3][3])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m3(float mat[3][3])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
void axis_angle_to_mat3(float R[3][3], const float axis[3], float angle)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
unsigned int uint
@ eModifierMode_Realtime
@ eModifierType_Mirror
@ MOD_MIR_AXIS_Z
@ MOD_MIR_CLIPPING
@ MOD_MIR_AXIS_X
@ MOD_MIR_AXIS_Y
Object is a sort of wrapper for general info.
@ SCE_SNAP
@ SCE_SELECT_VERTEX
@ SCE_SELECT_EDGE
@ SCE_SNAP_TO_FACE
@ SCE_SNAP_INDIVIDUAL_PROJECT
@ OPERATOR_PASS_THROUGH
void EDBM_flag_disable_all(BMEditMesh *em, char hflag)
void EDBM_update(Mesh *mesh, const EDBMUpdate_Params *params)
void EDBM_project_snap_verts(bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
ViewContext em_setup_viewcontext(bContext *C)
bool ED_operator_editmesh_region_view3d(bContext *C)
bool ED_operator_editmesh(bContext *C)
#define P_NO_DEFAULTS
void Transform_Properties(wmOperatorType *ot, int flags)
#define P_MIRROR_DUMMY
@ V3D_PROJ_TEST_NOP
Definition ED_view3d.hh:266
eV3DProjStatus ED_view3d_project_float_object(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void ED_view3d_win_to_3d_int(const View3D *v3d, const ARegion *region, const float depth_pt[3], const int mval[2], float r_out[3])
void ED_view3d_init_mats_rv3d(const Object *ob, RegionView3D *rv3d)
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:243
void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:198
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
#define ND_SELECT
Definition WM_types.hh:474
#define BM_ALL_NOLOOP
@ BM_ELEM_SELECT
#define BM_elem_flag_test(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
#define BM_SELECT_HISTORY_BACKUP(bm)
#define BM_SELECT_HISTORY_RESTORE(bm)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
BMO_FLAG_BUFFER.
void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
BMO_FLAG_BUFFER.
void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag)
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
void BMO_op_init(BMesh *bm, BMOperator *op, int flag, const char *opname)
BMESH OPSTACK INIT OP.
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_FLAG_DEFAULTS
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, bool i)
BLI_INLINE void BMO_slot_map_empty_insert(BMOperator *op, BMOpSlot *slot, const void *element)
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
const Depsgraph * depsgraph
#define fabsf(x)
void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
static int edbm_extrude_context_exec(bContext *C, wmOperator *op)
static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
bool edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, const bool use_normal_flip)
static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag)
static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void MESH_OT_extrude_context(wmOperatorType *ot)
static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
static bool edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag)
static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
static char edbm_extrude_htype_from_em_select(BMEditMesh *em)
static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
static bool edbm_extrude_ex(Object *obedit, BMEditMesh *em, char htype, const char hflag, const bool use_normal_flip, const bool use_dissolve_ortho_edges, const bool use_mirror, const bool use_select_history)
void MESH_OT_extrude_region(wmOperatorType *ot)
void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
static void edbm_extrude_edge_exclude_mirror(Object *obedit, BMEditMesh *em, const char hflag, BMOperator *op, BMOpSlot *slot_edges_exclude)
void MESH_OT_extrude_repeat(wmOperatorType *ot)
void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt,...)
bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt,...)
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
draw_view in_light_buf[] float
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float cross(const float2 a, const float2 b)
Frequency::GEOMETRY nor[]
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
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)
PropertyRNA * RNA_def_float_vector_xyz(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
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_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)
static const int steps
@ NONE
BMVert * v1
BMVert * v2
short selectmode
float no[3]
struct BMVert * v
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
float no[3]
int totfacesel
int totvertsel
int totedgesel
struct Object * mirror_ob
ObjectRuntimeHandle * runtime
ListBase modifiers
float persinv[4][4]
float viewinv[4][4]
struct ToolSettings * toolsettings
View3DCursor cursor
RegionView3D * rv3d
Definition ED_view3d.hh:76
ARegion * region
Definition ED_view3d.hh:73
Scene * scene
Definition ED_view3d.hh:69
BMEditMesh * em
Definition ED_view3d.hh:77
ViewLayer * view_layer
Definition ED_view3d.hh:70
View3D * v3d
Definition ED_view3d.hh:74
Object * obact
Definition ED_view3d.hh:71
Object * obedit
Definition ED_view3d.hh:72
int mval[2]
Definition WM_types.hh:728
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(* 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
struct ReportList * reports
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125
int WM_operator_flag_only_pass_through_on_press(int retval, const wmEvent *event)