Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / mesh / editmesh_loopcut.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2007 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Joseph Eagar, Joshua Leung
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/mesh/editmesh_loopcut.c
28  *  \ingroup edmesh
29  */
30
31 #include "DNA_object_types.h"
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_stack.h"
36 #include "BLI_string.h"
37 #include "BLI_math.h"
38
39 #include "BLT_translation.h"
40
41 #include "BKE_context.h"
42 #include "BKE_modifier.h"
43 #include "BKE_report.h"
44 #include "BKE_editmesh.h"
45 #include "BKE_DerivedMesh.h"
46 #include "BKE_unit.h"
47 #include "BKE_layer.h"
48
49 #include "GPU_immediate.h"
50 #include "GPU_matrix.h"
51
52 #include "UI_interface.h"
53
54 #include "ED_screen.h"
55 #include "ED_space_api.h"
56 #include "ED_view3d.h"
57 #include "ED_mesh.h"
58 #include "ED_numinput.h"
59
60 #include "RNA_access.h"
61 #include "RNA_define.h"
62 #include "RNA_enum_types.h"
63
64 #include "WM_api.h"
65 #include "WM_types.h"
66
67 #include "DEG_depsgraph.h"
68
69 #include "mesh_intern.h"  /* own include */
70
71 #define SUBD_SMOOTH_MAX 4.0f
72 #define SUBD_CUTS_MAX 500
73
74 /* ringsel operator */
75
76 /* struct for properties used while drawing */
77 typedef struct RingSelOpData {
78         ARegion *ar;        /* region that ringsel was activated in */
79         void *draw_handle;  /* for drawing preview loop */
80
81         float (*edges)[2][3];
82         int totedge;
83
84         float (*points)[3];
85         int totpoint;
86
87         ViewContext vc;
88
89         Object **objects;
90         uint     objects_len;
91
92         /* These values switch objects based on the object under the cursor. */
93         uint ob_index;
94         Object *ob;
95         BMEditMesh *em;
96         BMEdge *eed;
97
98         NumInput num;
99
100         bool extend;
101         bool do_cut;
102
103         float cuts;         /* cuts as float so smooth mouse pan works in small increments */
104         float smoothness;
105 } RingSelOpData;
106
107 /* modal loop selection drawing callback */
108 static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
109 {
110         View3D *v3d = CTX_wm_view3d(C);
111         RingSelOpData *lcd = arg;
112
113         if ((lcd->totedge > 0) || (lcd->totpoint > 0)) {
114                 if (v3d && v3d->zbuf)
115                         glDisable(GL_DEPTH_TEST);
116
117                 gpuPushMatrix();
118                 gpuMultMatrix(lcd->ob->obmat);
119
120                 unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
121
122                 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
123                 immUniformColor3ub(255, 0, 255);
124
125                 if (lcd->totedge > 0) {
126                         immBegin(GWN_PRIM_LINES, lcd->totedge * 2);
127
128                         for (int i = 0; i < lcd->totedge; i++) {
129                                 immVertex3fv(pos, lcd->edges[i][0]);
130                                 immVertex3fv(pos, lcd->edges[i][1]);
131                         }
132
133                         immEnd();
134                 }
135
136                 if (lcd->totpoint > 0) {
137                         glPointSize(3.0f);
138
139                         immBegin(GWN_PRIM_POINTS, lcd->totpoint);
140
141                         for (int i = 0; i < lcd->totpoint; i++) {
142                                 immVertex3fv(pos, lcd->points[i]);
143                         }
144
145                         immEnd();
146                 }
147
148                 immUnbindProgram();
149
150                 gpuPopMatrix();
151
152                 if (v3d && v3d->zbuf)
153                         glEnable(GL_DEPTH_TEST);
154         }
155 }
156
157 /* given two opposite edges in a face, finds the ordering of their vertices so
158  * that cut preview lines won't cross each other */
159 static void edgering_find_order(BMEdge *lasteed, BMEdge *eed,
160                                 BMVert *lastv1, BMVert *v[2][2])
161 {
162         BMIter liter;
163         BMLoop *l, *l2;
164         int rev;
165
166         l = eed->l;
167
168         /* find correct order for v[1] */
169         if (!(BM_edge_in_face(eed, l->f) && BM_edge_in_face(lasteed, l->f))) {
170                 BM_ITER_ELEM (l, &liter, l, BM_LOOPS_OF_LOOP) {
171                         if (BM_edge_in_face(eed, l->f) && BM_edge_in_face(lasteed, l->f))
172                                 break;
173                 }
174         }
175
176         /* this should never happen */
177         if (!l) {
178                 v[0][0] = eed->v1;
179                 v[0][1] = eed->v2;
180                 v[1][0] = lasteed->v1;
181                 v[1][1] = lasteed->v2;
182                 return;
183         }
184
185         l2 = BM_loop_other_edge_loop(l, eed->v1);
186         rev = (l2 == l->prev);
187         while (l2->v != lasteed->v1 && l2->v != lasteed->v2) {
188                 l2 = rev ? l2->prev : l2->next;
189         }
190
191         if (l2->v == lastv1) {
192                 v[0][0] = eed->v1;
193                 v[0][1] = eed->v2;
194         }
195         else {
196                 v[0][0] = eed->v2;
197                 v[0][1] = eed->v1;
198         }
199 }
200
201 static void edgering_vcos_get(DerivedMesh *dm, BMVert *v[2][2], float r_cos[2][2][3])
202 {
203         if (dm) {
204                 int j, k;
205                 for (j = 0; j < 2; j++) {
206                         for (k = 0; k < 2; k++) {
207                                 dm->getVertCo(dm, BM_elem_index_get(v[j][k]), r_cos[j][k]);
208                         }
209                 }
210         }
211         else {
212                 int j, k;
213                 for (j = 0; j < 2; j++) {
214                         for (k = 0; k < 2; k++) {
215                                 copy_v3_v3(r_cos[j][k], v[j][k]->co);
216                         }
217                 }
218         }
219 }
220
221 static void edgering_vcos_get_pair(DerivedMesh *dm, BMVert *v[2], float r_cos[2][3])
222 {
223         if (dm) {
224                 int j;
225                 for (j = 0; j < 2; j++) {
226                         dm->getVertCo(dm, BM_elem_index_get(v[j]), r_cos[j]);
227                 }
228         }
229         else {
230                 int j;
231                 for (j = 0; j < 2; j++) {
232                         copy_v3_v3(r_cos[j], v[j]->co);
233                 }
234         }
235 }
236
237 static void edgering_preview_free(RingSelOpData *lcd)
238 {
239         MEM_SAFE_FREE(lcd->edges);
240         lcd->totedge = 0;
241
242         MEM_SAFE_FREE(lcd->points);
243         lcd->totpoint = 0;
244 }
245
246 static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, const int previewlines)
247 {
248         BMesh *bm = lcd->em->bm;
249         BMWalker walker;
250         BMEdge *eed_start = lcd->eed;
251         BMEdge *eed, *eed_last;
252         BMVert *v[2][2] = {{NULL}}, *v_last;
253         float (*edges)[2][3] = NULL;
254         BLI_Stack *edge_stack;
255
256         int i, tot = 0;
257
258         BMW_init(&walker, bm, BMW_EDGERING,
259                  BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
260                  BMW_FLAG_TEST_HIDDEN,
261                  BMW_NIL_LAY);
262
263
264         edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
265
266         eed_last = NULL;
267         for (eed = eed_last = BMW_begin(&walker, lcd->eed); eed; eed = BMW_step(&walker)) {
268                 BLI_stack_push(edge_stack, &eed);
269         }
270         BMW_end(&walker);
271
272
273         eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
274
275         edges = MEM_mallocN(
276                 (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines, __func__);
277
278         v_last   = NULL;
279         eed_last = NULL;
280
281         while (!BLI_stack_is_empty(edge_stack)) {
282                 BLI_stack_pop(edge_stack, &eed);
283
284                 if (eed_last) {
285                         if (v_last) {
286                                 v[1][0] = v[0][0];
287                                 v[1][1] = v[0][1];
288                         }
289                         else {
290                                 v[1][0] = eed_last->v1;
291                                 v[1][1] = eed_last->v2;
292                                 v_last  = eed_last->v1;
293                         }
294
295                         edgering_find_order(eed_last, eed, v_last, v);
296                         v_last = v[0][0];
297
298                         for (i = 1; i <= previewlines; i++) {
299                                 const float fac = (i / ((float)previewlines + 1));
300                                 float v_cos[2][2][3];
301
302                                 edgering_vcos_get(dm, v, v_cos);
303
304                                 interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
305                                 interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
306                                 tot++;
307                         }
308                 }
309                 eed_last = eed;
310         }
311
312         if ((eed_last != eed_start) &&
313 #ifdef BMW_EDGERING_NGON
314             BM_edge_share_face_check(eed_last, eed_start)
315 #else
316             BM_edge_share_quad_check(eed_last, eed_start)
317 #endif
318             )
319         {
320                 v[1][0] = v[0][0];
321                 v[1][1] = v[0][1];
322
323                 edgering_find_order(eed_last, eed_start, v_last, v);
324
325                 for (i = 1; i <= previewlines; i++) {
326                         const float fac = (i / ((float)previewlines + 1));
327                         float v_cos[2][2][3];
328
329                         if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) {
330                                 continue;
331                         }
332
333                         edgering_vcos_get(dm, v, v_cos);
334
335                         interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
336                         interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
337                         tot++;
338                 }
339         }
340
341         BLI_stack_free(edge_stack);
342
343         lcd->edges = edges;
344         lcd->totedge = tot;
345 }
346
347 static void edgering_preview_calc_points(RingSelOpData *lcd, DerivedMesh *dm, const int previewlines)
348 {
349         float v_cos[2][3];
350         float (*points)[3];
351         int i, tot = 0;
352
353         if (dm) {
354                 BM_mesh_elem_table_ensure(lcd->em->bm, BM_VERT);
355         }
356
357         points = MEM_mallocN(sizeof(*lcd->points) * previewlines, __func__);
358
359         edgering_vcos_get_pair(dm, &lcd->eed->v1, v_cos);
360
361         for (i = 1; i <= previewlines; i++) {
362                 const float fac = (i / ((float)previewlines + 1));
363                 interp_v3_v3v3(points[tot], v_cos[0], v_cos[1], fac);
364                 tot++;
365         }
366
367         lcd->points = points;
368         lcd->totpoint = previewlines;
369 }
370
371 static void edgering_preview_calc(RingSelOpData *lcd, const int previewlines)
372 {
373         DerivedMesh *dm;
374
375         BLI_assert(lcd->eed != NULL);
376
377         edgering_preview_free(lcd);
378
379         dm = EDBM_mesh_deform_dm_get(lcd->em);
380         if (dm) {
381                 BM_mesh_elem_table_ensure(lcd->em->bm, BM_VERT);
382         }
383
384         if (BM_edge_is_wire(lcd->eed)) {
385                 edgering_preview_calc_points(lcd, dm, previewlines);
386         }
387         else {
388                 edgering_preview_calc_edges(lcd, dm, previewlines);
389         }
390 }
391
392 static void edgering_select(RingSelOpData *lcd)
393 {
394         if (!lcd->eed) {
395                 return;
396         }
397
398         if (!lcd->extend) {
399                 for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) {
400                         Object *ob_iter = lcd->objects[ob_index];
401                         BMEditMesh *em = BKE_editmesh_from_object(ob_iter);
402                         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
403                         WM_main_add_notifier(NC_GEOM | ND_SELECT, ob_iter->data);
404                 }
405         }
406
407         BMEditMesh *em = lcd->em;
408         BMEdge *eed_start = lcd->eed;
409         BMWalker walker;
410         BMEdge *eed;
411         BMW_init(&walker, em->bm, BMW_EDGERING,
412                  BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
413                  BMW_FLAG_TEST_HIDDEN,
414                  BMW_NIL_LAY);
415
416         for (eed = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
417                 BM_edge_select_set(em->bm, eed, true);
418         }
419         BMW_end(&walker);
420 }
421
422 static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines)
423 {
424         if (lcd->eed) {
425                 edgering_preview_calc(lcd, previewlines);
426         }
427         else {
428                 edgering_preview_free(lcd);
429         }
430 }
431
432 static void ringsel_finish(bContext *C, wmOperator *op)
433 {
434         RingSelOpData *lcd = op->customdata;
435         const int cuts = RNA_int_get(op->ptr, "number_cuts");
436         const float smoothness = RNA_float_get(op->ptr, "smoothness");
437         const int smooth_falloff = RNA_enum_get(op->ptr, "falloff");
438 #ifdef BMW_EDGERING_NGON
439         const bool use_only_quads = false;
440 #else
441         const bool use_only_quads = false;
442 #endif
443
444         if (lcd->eed) {
445                 BMEditMesh *em = lcd->em;
446                 BMVert *v_eed_orig[2] = {lcd->eed->v1, lcd->eed->v2};
447
448                 edgering_select(lcd);
449
450                 if (lcd->do_cut) {
451                         const bool is_macro = (op->opm != NULL);
452                         /* a single edge (rare, but better support) */
453                         const bool is_single = (BM_edge_is_wire(lcd->eed));
454                         const int seltype = is_single ? SUBDIV_SELECT_INNER : SUBDIV_SELECT_LOOPCUT;
455
456                         /* Enable gridfill, so that intersecting loopcut works as one would expect.
457                          * Note though that it will break edgeslide in this specific case.
458                          * See [#31939]. */
459                         BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
460                                            smoothness, smooth_falloff, true,
461                                            0.0f, 0.0f,
462                                            cuts, seltype, SUBD_CORNER_PATH, 0, true,
463                                            use_only_quads, 0);
464
465                         /* when used in a macro the tessfaces will be recalculated anyway,
466                          * this is needed here because modifiers depend on updated tessellation, see T45920 */
467                         EDBM_update_generic(em, true, true);
468
469                         if (is_single) {
470                                 /* de-select endpoints */
471                                 BM_vert_select_set(em->bm, v_eed_orig[0], false);
472                                 BM_vert_select_set(em->bm, v_eed_orig[1], false);
473
474                                 EDBM_selectmode_flush_ex(lcd->em, SCE_SELECT_VERTEX);
475                         }
476                         /* we cant slide multiple edges in vertex select mode */
477                         else if (is_macro && (cuts > 1) && (em->selectmode & SCE_SELECT_VERTEX)) {
478                                 EDBM_selectmode_disable(lcd->vc.scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
479                         }
480                         /* force edge slide to edge select mode in in face select mode */
481                         else if (EDBM_selectmode_disable(lcd->vc.scene, em, SCE_SELECT_FACE, SCE_SELECT_EDGE)) {
482                                 /* pass, the change will flush selection */
483                         }
484                         else {
485                                 /* else flush explicitly */
486                                 EDBM_selectmode_flush(lcd->em);
487                         }
488                 }
489                 else {
490                         /* XXX Is this piece of code ever used now? Simple loop select is now
491                          *     in editmesh_select.c (around line 1000)... */
492                         /* sets as active, useful for other tools */
493                         if (em->selectmode & SCE_SELECT_VERTEX)
494                                 BM_select_history_store(em->bm, lcd->eed->v1);  /* low priority TODO, get vertrex close to mouse */
495                         if (em->selectmode & SCE_SELECT_EDGE)
496                                 BM_select_history_store(em->bm, lcd->eed);
497
498                         EDBM_selectmode_flush(lcd->em);
499                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, lcd->ob->data);
500                 }
501         }
502 }
503
504 /* called when modal loop selection is done... */
505 static void ringsel_exit(bContext *UNUSED(C), wmOperator *op)
506 {
507         RingSelOpData *lcd = op->customdata;
508
509         /* deactivate the extra drawing stuff in 3D-View */
510         ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle);
511
512         edgering_preview_free(lcd);
513
514         MEM_freeN(lcd->objects);
515
516         ED_region_tag_redraw(lcd->ar);
517
518         /* free the custom data */
519         MEM_freeN(lcd);
520         op->customdata = NULL;
521 }
522
523
524 /* called when modal loop selection gets set up... */
525 static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
526 {
527         RingSelOpData *lcd;
528         Scene *scene = CTX_data_scene(C);
529
530         /* alloc new customdata */
531         lcd = op->customdata = MEM_callocN(sizeof(RingSelOpData), "ringsel Modal Op Data");
532
533         em_setup_viewcontext(C, &lcd->vc);
534
535         /* assign the drawing handle for drawing preview line... */
536         lcd->ar = CTX_wm_region(C);
537         lcd->draw_handle = ED_region_draw_cb_activate(lcd->ar->type, ringsel_draw, lcd, REGION_DRAW_POST_VIEW);
538         /* Initialize once the cursor is over a mesh. */
539         lcd->ob = NULL;
540         lcd->em = NULL;
541         lcd->extend = do_cut ? false : RNA_boolean_get(op->ptr, "extend");
542         lcd->do_cut = do_cut;
543         lcd->cuts = RNA_int_get(op->ptr, "number_cuts");
544         lcd->smoothness = RNA_float_get(op->ptr, "smoothness");
545
546         initNumInput(&lcd->num);
547         lcd->num.idx_max = 1;
548         lcd->num.val_flag[0] |= NUM_NO_NEGATIVE | NUM_NO_FRACTION;
549         /* No specific flags for smoothness. */
550         lcd->num.unit_sys = scene->unit.system;
551         lcd->num.unit_type[0] = B_UNIT_NONE;
552         lcd->num.unit_type[1] = B_UNIT_NONE;
553
554         ED_region_tag_redraw(lcd->ar);
555
556         return 1;
557 }
558
559 static void ringcut_cancel(bContext *C, wmOperator *op)
560 {
561         /* this is just a wrapper around exit() */
562         ringsel_exit(C, op);
563 }
564
565 static void loopcut_update_edge(RingSelOpData *lcd, uint ob_index, BMEdge *e, const int previewlines)
566 {
567         if (e != lcd->eed) {
568                 lcd->eed = e;
569                 lcd->ob = lcd->vc.obedit;
570                 lcd->ob_index = ob_index;
571                 lcd->em = lcd->vc.em;
572                 ringsel_find_edge(lcd, previewlines);
573         }
574         else if (e == NULL) {
575                 lcd->ob = NULL;
576                 lcd->em = NULL;
577                 lcd->ob_index = UINT_MAX;
578         }
579 }
580
581 static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines)
582 {
583         struct {
584                 Object *ob;
585                 BMEdge *eed;
586                 float dist;
587                 int ob_index;
588         } best = {
589                 .dist = ED_view3d_select_dist_px(),
590         };
591
592         for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) {
593                 Object *ob_iter = lcd->objects[ob_index];
594                 ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter);
595                 BMEdge *eed_test = EDBM_edge_find_nearest_ex(&lcd->vc, &best.dist, NULL, false, false, NULL);
596                 if (eed_test) {
597                         best.ob = ob_iter;
598                         best.eed = eed_test;
599                         best.ob_index = ob_index;
600                 }
601         }
602
603         if (best.eed) {
604                 ED_view3d_viewcontext_init_object(&lcd->vc, best.ob);
605         }
606
607         loopcut_update_edge(lcd, best.ob_index, best.eed, previewlines);
608 }
609
610 /* called by both init() and exec() */
611 static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
612 {
613         const bool is_interactive = (event != NULL);
614
615         /* Use for redo - intentionally wrap int to uint. */
616         const struct {
617                 uint ob_index;
618                 uint e_index;
619         } exec_data = {
620                 .ob_index = (uint)RNA_int_get(op->ptr, "object_index"),
621                 .e_index = (uint)RNA_int_get(op->ptr, "edge_index"),
622         };
623
624         ViewLayer *view_layer = CTX_data_view_layer(C);
625
626         uint objects_len;
627         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode(view_layer, &objects_len);
628
629         if (is_interactive) {
630                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
631                         Object *ob_iter = objects[ob_index];
632                         if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) {
633                                 BKE_report(op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display");
634                                 break;
635                         }
636                 }
637         }
638
639         view3d_operator_needs_opengl(C);
640
641         /* for re-execution, check edge index is in range before we setup ringsel */
642         bool ok = true;
643         if (is_interactive == false) {
644                 if (exec_data.ob_index >= objects_len) {
645                         return OPERATOR_CANCELLED;
646                         ok = false;
647                 }
648                 else {
649                         Object *ob_iter = objects[exec_data.ob_index];
650                         BMEditMesh *em = BKE_editmesh_from_object(ob_iter);
651                         if (exec_data.e_index >= em->bm->totedge) {
652                                 ok = false;
653                         }
654                 }
655         }
656
657         if (!ok || !ringsel_init(C, op, true)) {
658                 MEM_freeN(objects);
659                 return OPERATOR_CANCELLED;
660         }
661
662         /* add a modal handler for this operator - handles loop selection */
663         if (is_interactive) {
664                 op->flag |= OP_IS_MODAL_CURSOR_REGION;
665                 WM_event_add_modal_handler(C, op);
666         }
667
668         RingSelOpData *lcd = op->customdata;
669
670         lcd->objects = objects;
671         lcd->objects_len = objects_len;
672
673         if (is_interactive) {
674                 copy_v2_v2_int(lcd->vc.mval, event->mval);
675                 loopcut_mouse_move(lcd, is_interactive ? 1 : 0);
676         }
677         else {
678
679                 Object *ob_iter = objects[exec_data.ob_index];
680                 ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter);
681
682                 BMEdge *e;
683                 BM_mesh_elem_table_ensure(lcd->vc.em->bm, BM_EDGE);
684                 e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index);
685                 loopcut_update_edge(lcd, exec_data.ob_index, e, 0);
686         }
687
688 #ifdef USE_LOOPSLIDE_HACK
689         /* for use in macro so we can restore, HACK */
690         {
691                 Scene *scene = CTX_data_scene(C);
692                 ToolSettings *settings = scene->toolsettings;
693                 const int mesh_select_mode[3] = {
694                     (settings->selectmode & SCE_SELECT_VERTEX) != 0,
695                     (settings->selectmode & SCE_SELECT_EDGE)   != 0,
696                     (settings->selectmode & SCE_SELECT_FACE)   != 0,
697                 };
698
699                 RNA_boolean_set_array(op->ptr, "mesh_select_mode_init", mesh_select_mode);
700         }
701 #endif
702
703         if (is_interactive) {
704                 ScrArea *sa = CTX_wm_area(C);
705                 ED_area_headerprint(sa, IFACE_("Select a ring to be cut, use mouse-wheel or page-up/down for number of cuts, "
706                                                "hold Alt for smooth"));
707                 return OPERATOR_RUNNING_MODAL;
708         }
709         else {
710                 ringsel_finish(C, op);
711                 ringsel_exit(C, op);
712                 return OPERATOR_FINISHED;
713         }
714 }
715
716 static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event)
717 {
718         return loopcut_init(C, op, event);
719 }
720
721 static int loopcut_exec(bContext *C, wmOperator *op)
722 {
723         return loopcut_init(C, op, NULL);
724 }
725
726 static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op)
727 {
728         /* finish */
729         ED_region_tag_redraw(lcd->ar);
730         ED_area_headerprint(CTX_wm_area(C), NULL);
731
732         if (lcd->eed) {
733                 /* set for redo */
734                 BM_mesh_elem_index_ensure(lcd->em->bm, BM_EDGE);
735                 RNA_int_set(op->ptr, "object_index", lcd->ob_index);
736                 RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed));
737
738                 /* execute */
739                 ringsel_finish(C, op);
740                 ringsel_exit(C, op);
741         }
742         else {
743                 ringcut_cancel(C, op);
744                 return OPERATOR_CANCELLED;
745         }
746
747         return OPERATOR_FINISHED;
748 }
749
750 static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
751 {
752         RingSelOpData *lcd = op->customdata;
753         float cuts = lcd->cuts;
754         float smoothness = lcd->smoothness;
755         bool show_cuts = false;
756         const bool has_numinput = hasNumInput(&lcd->num);
757
758         em_setup_viewcontext(C, &lcd->vc);
759         lcd->ar = lcd->vc.ar;
760
761         view3d_operator_needs_opengl(C);
762
763         /* using the keyboard to input the number of cuts */
764         /* Modal numinput active, try to handle numeric inputs first... */
765         if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) {
766                 float values[2] = {cuts, smoothness};
767                 applyNumInput(&lcd->num, values);
768                 cuts = values[0];
769                 smoothness = values[1];
770         }
771         else {
772                 bool handled = false;
773                 switch (event->type) {
774                         case RETKEY:
775                         case PADENTER:
776                         case LEFTMOUSE: /* confirm */ // XXX hardcoded
777                                 if (event->val == KM_PRESS)
778                                         return loopcut_finish(lcd, C, op);
779
780                                 ED_region_tag_redraw(lcd->ar);
781                                 handled = true;
782                                 break;
783                         case RIGHTMOUSE: /* abort */ // XXX hardcoded
784                                 ED_region_tag_redraw(lcd->ar);
785                                 ringsel_exit(C, op);
786                                 ED_area_headerprint(CTX_wm_area(C), NULL);
787
788                                 return OPERATOR_CANCELLED;
789                         case ESCKEY:
790                                 if (event->val == KM_RELEASE) {
791                                         /* cancel */
792                                         ED_region_tag_redraw(lcd->ar);
793                                         ED_area_headerprint(CTX_wm_area(C), NULL);
794
795                                         ringcut_cancel(C, op);
796                                         return OPERATOR_CANCELLED;
797                                 }
798
799                                 ED_region_tag_redraw(lcd->ar);
800                                 handled = true;
801                                 break;
802                         case MOUSEPAN:
803                                 if (event->alt == 0) {
804                                         cuts += 0.02f * (event->y - event->prevy);
805                                         if (cuts < 1 && lcd->cuts >= 1)
806                                                 cuts = 1;
807                                 }
808                                 else {
809                                         smoothness += 0.002f * (event->y - event->prevy);
810                                 }
811                                 handled = true;
812                                 break;
813                         case PADPLUSKEY:
814                         case PAGEUPKEY:
815                         case WHEELUPMOUSE:  /* change number of cuts */
816                                 if (event->val == KM_RELEASE)
817                                         break;
818                                 if (event->alt == 0) {
819                                         cuts += 1;
820                                 }
821                                 else {
822                                         smoothness += 0.05f;
823                                 }
824                                 handled = true;
825                                 break;
826                         case PADMINUS:
827                         case PAGEDOWNKEY:
828                         case WHEELDOWNMOUSE:  /* change number of cuts */
829                                 if (event->val == KM_RELEASE)
830                                         break;
831                                 if (event->alt == 0) {
832                                         cuts = max_ff(cuts - 1, 1);
833                                 }
834                                 else {
835                                         smoothness -= 0.05f;
836                                 }
837                                 handled = true;
838                                 break;
839                         case MOUSEMOVE:  /* mouse moved somewhere to select another loop */
840
841                                 /* This is normally disabled for all modal operators.
842                                  * This is an exception since mouse movement doesn't relate to numeric input.
843                                  *
844                                  * If numeric input changes we'll need to add this back see: D2973 */
845 #if 0
846                                 if (!has_numinput)
847 #endif
848                                 {
849                                         lcd->vc.mval[0] = event->mval[0];
850                                         lcd->vc.mval[1] = event->mval[1];
851                                         loopcut_mouse_move(lcd, (int)lcd->cuts);
852
853                                         ED_region_tag_redraw(lcd->ar);
854                                         handled = true;
855                                 }
856                                 break;
857                 }
858
859                 /* Modal numinput inactive, try to handle numeric inputs last... */
860                 if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) {
861                         float values[2] = {cuts, smoothness};
862                         applyNumInput(&lcd->num, values);
863                         cuts = values[0];
864                         smoothness = values[1];
865                 }
866         }
867
868         if (cuts != lcd->cuts) {
869                 /* allow zero so you can backspace and type in a value
870                  * otherwise 1 as minimum would make more sense */
871                 lcd->cuts = CLAMPIS(cuts, 0, SUBD_CUTS_MAX);
872                 RNA_int_set(op->ptr, "number_cuts", (int)lcd->cuts);
873                 ringsel_find_edge(lcd, (int)lcd->cuts);
874                 show_cuts = true;
875                 ED_region_tag_redraw(lcd->ar);
876         }
877
878         if (smoothness != lcd->smoothness) {
879                 lcd->smoothness = CLAMPIS(smoothness, -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
880                 RNA_float_set(op->ptr, "smoothness", lcd->smoothness);
881                 show_cuts = true;
882                 ED_region_tag_redraw(lcd->ar);
883         }
884
885         if (show_cuts) {
886                 Scene *sce = CTX_data_scene(C);
887                 char buf[UI_MAX_DRAW_STR];
888                 char str_rep[NUM_STR_REP_LEN * 2];
889                 if (hasNumInput(&lcd->num)) {
890                         outputNumInput(&lcd->num, str_rep, &sce->unit);
891                 }
892                 else {
893                         BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", (int)lcd->cuts);
894                         BLI_snprintf(str_rep + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%.2f", smoothness);
895                 }
896                 BLI_snprintf(buf, sizeof(buf), IFACE_("Number of Cuts: %s, Smooth: %s (Alt)"),
897                              str_rep, str_rep + NUM_STR_REP_LEN);
898                 ED_area_headerprint(CTX_wm_area(C), buf);
899         }
900
901         /* keep going until the user confirms */
902         return OPERATOR_RUNNING_MODAL;
903 }
904
905 /* for bmesh this tool is in bmesh_select.c */
906 #if 0
907
908 void MESH_OT_edgering_select(wmOperatorType *ot)
909 {
910         /* description */
911         ot->name = "Edge Ring Select";
912         ot->idname = "MESH_OT_edgering_select";
913         ot->description = "Select an edge ring";
914
915         /* callbacks */
916         ot->invoke = ringsel_invoke;
917         ot->poll = ED_operator_editmesh_region_view3d;
918
919         /* flags */
920         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
921
922         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
923 }
924
925 #endif
926
927 void MESH_OT_loopcut(wmOperatorType *ot)
928 {
929         PropertyRNA *prop;
930
931         /* description */
932         ot->name = "Loop Cut";
933         ot->idname = "MESH_OT_loopcut";
934         ot->description = "Add a new loop between existing loops";
935
936         /* callbacks */
937         ot->invoke = ringcut_invoke;
938         ot->exec = loopcut_exec;
939         ot->modal = loopcut_modal;
940         ot->cancel = ringcut_cancel;
941         ot->poll = ED_operator_editmesh_region_view3d;
942
943         /* flags */
944         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
945
946         /* properties */
947         prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000000, "Number of Cuts", "", 1, 100);
948         /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
949         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
950
951         prop = RNA_def_float(ot->srna, "smoothness", 0.0f, -1e3f, 1e3f,
952                              "Smoothness", "Smoothness factor", -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
953         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
954
955         WM_operatortype_props_advanced_begin(ot);
956
957         prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE);
958         RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items);
959         RNA_def_property_enum_default(prop, PROP_INVSQUARE);
960         RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather");
961         RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
962
963         /* For redo only. */
964         prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", 0, INT_MAX);
965         RNA_def_property_flag(prop, PROP_HIDDEN);
966         prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", 0, INT_MAX);
967         RNA_def_property_flag(prop, PROP_HIDDEN);
968
969 #ifdef USE_LOOPSLIDE_HACK
970         prop = RNA_def_boolean_array(ot->srna, "mesh_select_mode_init", 3, NULL, "", "");
971         RNA_def_property_flag(prop, PROP_HIDDEN);
972 #endif
973 }