Orientation for 3D cursor
[blender.git] / source / blender / editors / mesh / editmesh_polybuild.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  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file blender/editors/mesh/editmesh_polybuild.c
22  *  \ingroup edmesh
23  *
24  * Tools to implement polygon building tool,
25  * an experimental tool for quickly constructing/manipulating faces.
26  */
27
28 #include "DNA_object_types.h"
29
30 #include "BLI_math.h"
31
32 #include "BKE_context.h"
33 #include "BKE_report.h"
34 #include "BKE_editmesh.h"
35 #include "BKE_mesh.h"
36
37 #include "WM_types.h"
38
39 #include "ED_mesh.h"
40 #include "ED_screen.h"
41 #include "ED_transform.h"
42 #include "ED_view3d.h"
43
44 #include "bmesh.h"
45
46 #include "mesh_intern.h"  /* own include */
47
48 #include "RNA_access.h"
49 #include "RNA_define.h"
50
51 #include "WM_api.h"
52
53 /* -------------------------------------------------------------------- */
54 /** \name Local Utilities
55  * \{ */
56
57 static void edbm_selectmode_ensure(Scene *scene, BMEditMesh *em, short selectmode)
58 {
59         if ((scene->toolsettings->selectmode & selectmode) == 0) {
60                 scene->toolsettings->selectmode |= selectmode;
61                 em->selectmode = scene->toolsettings->selectmode;
62                 EDBM_selectmode_set(em);
63         }
64 }
65
66 /** \} */
67
68 /* -------------------------------------------------------------------- */
69 /** \name Face At Cursor
70  * \{ */
71
72 static int edbm_polybuild_face_at_cursor_invoke(
73         bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
74 {
75         ViewContext vc;
76         float center[3];
77         bool changed = false;
78
79         em_setup_viewcontext(C, &vc);
80         Object *obedit = CTX_data_edit_object(C);
81         BMEditMesh *em = BKE_editmesh_from_object(obedit);
82         BMesh *bm = em->bm;
83         BMElem *ele_act = BM_mesh_active_elem_get(bm);
84
85         invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
86         ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
87
88         edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
89
90         if (ele_act == NULL || ele_act->head.htype == BM_FACE) {
91                 /* Just add vert */
92                 copy_v3_v3(center, ED_view3d_cursor3d_get(vc.scene, vc.v3d)->location);
93                 mul_v3_m4v3(center, vc.obedit->obmat, center);
94                 ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
95                 mul_m4_v3(vc.obedit->imat, center);
96
97                 BMVert *v_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
98                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
99                 BM_vert_select_set(bm, v_new, true);
100                 changed = true;
101         }
102         else if (ele_act->head.htype == BM_EDGE) {
103                 BMEdge *e_act = (BMEdge *)ele_act;
104                 BMFace *f_reference = e_act->l ? e_act->l->f : NULL;
105
106                 mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co);
107                 mul_m4_v3(vc.obedit->obmat, center);
108                 ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
109                 mul_m4_v3(vc.obedit->imat, center);
110
111                 BMVert *v_tri[3];
112                 v_tri[0] = e_act->v1;
113                 v_tri[1] = e_act->v2;
114                 v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
115                 if (e_act->l && e_act->l->v == v_tri[0]) {
116                         SWAP(BMVert *, v_tri[0], v_tri[1]);
117                 }
118                 // BMFace *f_new =
119                 BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
120
121                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
122                 BM_vert_select_set(bm, v_tri[2], true);
123                 changed = true;
124         }
125         else if (ele_act->head.htype == BM_VERT) {
126                 BMVert *v_act = (BMVert *)ele_act;
127                 BMEdge *e_pair[2] = {NULL};
128
129                 if (v_act->e != NULL) {
130                         for (uint allow_wire = 0; allow_wire < 2 && (e_pair[1] == NULL); allow_wire++) {
131                                 int i = 0;
132                                 BMEdge *e_iter = v_act->e;
133                                 do {
134                                         if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) &&
135                                             (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter)))
136                                         {
137                                                 if (i == 2) {
138                                                         e_pair[0] = e_pair[1] = NULL;
139                                                         break;
140                                                 }
141                                                 e_pair[i++] = e_iter;
142                                         }
143                                 } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_act)) != v_act->e);
144                         }
145                 }
146
147                 if (e_pair[1] != NULL) {
148                         /* Quad from edge pair. */
149                         if (BM_edge_calc_length_squared(e_pair[0]) <
150                             BM_edge_calc_length_squared(e_pair[1]))
151                         {
152                                 SWAP(BMEdge *, e_pair[0], e_pair[1]);
153                         }
154
155                         BMFace *f_reference = e_pair[0]->l ? e_pair[0]->l->f : NULL;
156
157                         mul_v3_m4v3(center, vc.obedit->obmat, v_act->co);
158                         ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
159                         mul_m4_v3(vc.obedit->imat, center);
160
161                         BMVert *v_quad[4];
162                         v_quad[0] = v_act;
163                         v_quad[1] = BM_edge_other_vert(e_pair[0], v_act);
164                         v_quad[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
165                         v_quad[3] = BM_edge_other_vert(e_pair[1], v_act);
166                         if (e_pair[0]->l && e_pair[0]->l->v == v_quad[0]) {
167                                 SWAP(BMVert *, v_quad[1], v_quad[3]);
168                         }
169                         // BMFace *f_new =
170                         BM_face_create_verts(bm, v_quad, 4, f_reference, BM_CREATE_NOP, true);
171
172                         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
173                         BM_vert_select_set(bm, v_quad[2], true);
174                         changed = true;
175                 }
176                 else {
177                         /* Just add edge */
178                         mul_m4_v3(vc.obedit->obmat, center);
179                         ED_view3d_win_to_3d_int(vc.v3d, vc.ar, v_act->co, event->mval, center);
180                         mul_m4_v3(vc.obedit->imat, center);
181
182                         BMVert *v_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
183
184                         BM_edge_create(bm, v_act, v_new, NULL, BM_CREATE_NOP);
185
186                         BM_vert_select_set(bm, v_new, true);
187                 }
188         }
189
190         if (changed) {
191                 BM_select_history_clear(bm);
192
193                 EDBM_mesh_normals_update(em);
194                 EDBM_update_generic(em, true, true);
195
196                 WM_event_add_mousemove(C);
197
198                 return OPERATOR_FINISHED;
199         }
200         else {
201                 return OPERATOR_CANCELLED;
202         }
203 }
204
205 void MESH_OT_polybuild_face_at_cursor(wmOperatorType *ot)
206 {
207         /* identifiers */
208         ot->name = "Poly Build Face At Cursor";
209         ot->idname = "MESH_OT_polybuild_face_at_cursor";
210         ot->description = "";
211
212         /* api callbacks */
213         ot->invoke = edbm_polybuild_face_at_cursor_invoke;
214         ot->poll = EDBM_view3d_poll;
215
216         /* flags */
217         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
218
219         /* to give to transform */
220         Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
221 }
222
223 /** \} */
224
225 /* -------------------------------------------------------------------- */
226 /** \name Split At Cursor
227  * \{ */
228
229 static int edbm_polybuild_split_at_cursor_invoke(
230         bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
231 {
232         ViewContext vc;
233         float center[3];
234         bool changed = false;
235
236         em_setup_viewcontext(C, &vc);
237         Object *obedit = CTX_data_edit_object(C);
238         BMEditMesh *em = BKE_editmesh_from_object(obedit);
239         BMesh *bm = em->bm;
240
241         invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
242         ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
243
244         edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
245
246         BMElem *ele_act = BM_mesh_active_elem_get(bm);
247
248         if (ele_act == NULL || ele_act->head.hflag == BM_FACE) {
249                 return OPERATOR_PASS_THROUGH;
250         }
251         else if (ele_act->head.htype == BM_EDGE) {
252                 BMEdge *e_act = (BMEdge *)ele_act;
253                 mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co);
254                 mul_m4_v3(vc.obedit->obmat, center);
255                 ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
256                 mul_m4_v3(vc.obedit->imat, center);
257
258                 const float fac = line_point_factor_v3(center, e_act->v1->co, e_act->v2->co);
259                 BMVert *v_new = BM_edge_split(bm, e_act, e_act->v1, NULL, CLAMPIS(fac, 0.0f, 1.0f));
260                 copy_v3_v3(v_new->co, center);
261
262                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
263                 BM_vert_select_set(bm, v_new, true);
264                 changed = true;
265         }
266         else if (ele_act->head.htype == BM_VERT) {
267                 /* Just do nothing, allow dragging. */
268                 return OPERATOR_FINISHED;
269         }
270
271         if (changed) {
272                 BM_select_history_clear(bm);
273
274                 EDBM_mesh_normals_update(em);
275                 EDBM_update_generic(em, true, true);
276
277                 WM_event_add_mousemove(C);
278
279                 return OPERATOR_FINISHED;
280         }
281         else {
282                 return OPERATOR_CANCELLED;
283         }
284 }
285
286 void MESH_OT_polybuild_split_at_cursor(wmOperatorType *ot)
287 {
288         /* identifiers */
289         ot->name = "Poly Build Split At Cursor";
290         ot->idname = "MESH_OT_polybuild_split_at_cursor";
291         ot->description = "";
292
293         /* api callbacks */
294         ot->invoke = edbm_polybuild_split_at_cursor_invoke;
295         ot->poll = EDBM_view3d_poll;
296
297         /* flags */
298         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
299
300         /* to give to transform */
301         Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
302 }
303
304 /** \} */
305
306
307 /* -------------------------------------------------------------------- */
308 /** \name Dissolve At Cursor
309  *
310  * \{ */
311
312 static int edbm_polybuild_dissolve_at_cursor_invoke(
313         bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
314 {
315         ViewContext vc;
316         em_setup_viewcontext(C, &vc);
317         bool changed = false;
318
319         Object *obedit = CTX_data_edit_object(C);
320         BMEditMesh *em = BKE_editmesh_from_object(obedit);
321         BMesh *bm = em->bm;
322         BMVert *v_act = BM_mesh_active_vert_get(bm);
323         BMEdge *e_act = BM_mesh_active_edge_get(bm);
324
325         invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
326         ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
327
328         edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
329
330
331         if (e_act) {
332                 BMLoop *l_a, *l_b;
333                 if (BM_edge_loop_pair(e_act, &l_a, &l_b)) {
334                         BMFace *f_new = BM_faces_join_pair(bm, l_a, l_b, true);
335                         if (f_new) {
336                                 changed = true;
337                         }
338                 }
339         }
340         else if (v_act) {
341                 if (BM_vert_is_edge_pair(v_act)) {
342                         BM_edge_collapse(
343                                 bm, v_act->e, v_act,
344                                 true, true);
345                 }
346                 else {
347                         /* too involved to do inline */
348                         if (!EDBM_op_callf(em, op,
349                                            "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
350                                            BM_ELEM_SELECT, false, true))
351                         {
352                                 return OPERATOR_CANCELLED;
353                         }
354                 }
355                 changed = true;
356         }
357
358         if (changed) {
359                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
360
361                 BM_select_history_clear(bm);
362
363                 EDBM_mesh_normals_update(em);
364                 EDBM_update_generic(em, true, true);
365
366                 WM_event_add_mousemove(C);
367
368                 return OPERATOR_FINISHED;
369         }
370         else {
371                 return OPERATOR_CANCELLED;
372         }
373 }
374
375 void MESH_OT_polybuild_dissolve_at_cursor(wmOperatorType *ot)
376 {
377         /* identifiers */
378         ot->name = "Poly Build Dissolve At Cursor";
379         ot->idname = "MESH_OT_polybuild_dissolve_at_cursor";
380         ot->description = "";
381
382         /* api callbacks */
383         ot->invoke = edbm_polybuild_dissolve_at_cursor_invoke;
384         ot->poll = EDBM_view3d_poll;
385
386         /* flags */
387         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
388 }
389
390 /** \} */
391
392 /* -------------------------------------------------------------------- */
393 /** \name Cursor Manipulator
394  *
395  * \note This may need its own file, for now not.
396  * \{ */
397
398 static BMElem *edbm_hover_preselect(
399         bContext *C,
400         const int mval[2],
401         bool use_boundary)
402 {
403         ViewContext vc;
404
405         em_setup_viewcontext(C, &vc);
406         Object *obedit = CTX_data_edit_object(C);
407         BMEditMesh *em = BKE_editmesh_from_object(obedit);
408         BMesh *bm = em->bm;
409
410         invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
411         ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
412
413         const float mval_fl[2] = {UNPACK2(mval)};
414         float ray_origin[3], ray_direction[3];
415
416         BMElem *ele_best = NULL;
417
418         if (ED_view3d_win_to_ray(
419                 CTX_data_depsgraph(C),
420                 vc.ar, vc.v3d, mval_fl,
421                 ray_origin, ray_direction, true))
422         {
423                 BMEdge *e;
424
425                 BMIter eiter;
426                 float dist_sq_best = FLT_MAX;
427
428                 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
429                         if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) &&
430                             (!use_boundary || BM_edge_is_boundary(e)))
431                         {
432                                 float dist_sq_test;
433                                 float point[3];
434                                 float depth;
435 #if 0
436                                 dist_sq_test = dist_squared_ray_to_seg_v3(
437                                         ray_origin, ray_direction,
438                                         e->v1->co,  e->v2->co,
439                                         point, &depth);
440 #else
441                                 mid_v3_v3v3(point, e->v1->co,  e->v2->co);
442                                 dist_sq_test = dist_squared_to_ray_v3(
443                                         ray_origin, ray_direction,
444                                         point, &depth);
445 #endif
446
447                                 if (dist_sq_test < dist_sq_best) {
448                                         dist_sq_best = dist_sq_test;
449                                         ele_best = (BMElem *)e;
450                                 }
451
452                                 dist_sq_test = dist_squared_to_ray_v3(
453                                         ray_origin, ray_direction,
454                                         e->v1->co, &depth);
455                                 if (dist_sq_test < dist_sq_best) {
456                                         dist_sq_best = dist_sq_test;
457                                         ele_best = (BMElem *)e->v1;
458                                 }
459                                 dist_sq_test = dist_squared_to_ray_v3(
460                                         ray_origin, ray_direction,
461                                         e->v2->co, &depth);
462                                 if (dist_sq_test < dist_sq_best) {
463                                         dist_sq_best = dist_sq_test;
464                                         ele_best = (BMElem *)e->v2;
465                                 }
466                         }
467                 }
468         }
469         return ele_best;
470 }
471
472 /*
473  * Developer note: this is not advocating pre-selection highlighting.
474  * This is just a quick way to test how a tool for interactively editing polygons may work. */
475 static int edbm_polybuild_hover_invoke(
476         bContext *C, wmOperator *op, const wmEvent *event)
477 {
478         const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
479         ViewContext vc;
480
481         em_setup_viewcontext(C, &vc);
482
483         /* Vertex selection is needed */
484         if ((vc.scene->toolsettings->selectmode & SCE_SELECT_VERTEX) == 0) {
485                 return OPERATOR_PASS_THROUGH;
486         }
487
488         /* Don't overwrite click-drag events. */
489         if (use_boundary == false) {
490                 /* pass */
491         }
492         else if (vc.win->tweak ||
493                  (vc.win->eventstate->check_click &&
494                   vc.win->eventstate->prevval == KM_PRESS &&
495                   ISMOUSE(vc.win->eventstate->prevtype)))
496         {
497                 return OPERATOR_PASS_THROUGH;
498         }
499
500         Object *obedit = CTX_data_edit_object(C);
501         BMEditMesh *em = BKE_editmesh_from_object(obedit);
502         BMesh *bm = em->bm;
503         BMElem *ele_active = BM_mesh_active_elem_get(bm);
504         BMElem *ele_hover = edbm_hover_preselect(C, event->mval, use_boundary);
505
506         if (ele_hover && (ele_hover != ele_active)) {
507                 if (event->shift == 0) {
508                         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
509                         BM_select_history_clear(bm);
510                 }
511                 BM_elem_select_set(bm, ele_hover, true);
512                 BM_select_history_store(em->bm, ele_hover);
513                 BKE_mesh_batch_cache_dirty(obedit->data, BKE_MESH_BATCH_DIRTY_SELECT);
514
515                 ED_region_tag_redraw(vc.ar);
516
517                 return OPERATOR_FINISHED;
518         }
519         else {
520                 return OPERATOR_CANCELLED;
521         }
522 }
523
524 void MESH_OT_polybuild_hover(wmOperatorType *ot)
525 {
526         /* identifiers */
527         ot->name = "Poly Build Hover";
528         ot->idname = "MESH_OT_polybuild_hover";
529         ot->description = "";
530
531         /* api callbacks */
532         ot->invoke = edbm_polybuild_hover_invoke;
533         ot->poll = EDBM_view3d_poll;
534
535         /* flags */
536         ot->flag = OPTYPE_INTERNAL;
537
538         /* properties */
539         RNA_def_boolean(ot->srna, "use_boundary", false, "Boundary", "Select only boundary geometry");
540 }
541
542 /** \} */