fix own error with updating edge tagging (seams didnt work)
[blender.git] / source / blender / editors / mesh / editmesh_path.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) 2004 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/mesh/editmesh_path.c
29  *  \ingroup edmesh
30  */
31
32 #include "DNA_scene_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_mesh_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "DNA_windowmanager_types.h"
37
38 #include "BLI_math.h"
39 #include "BLI_linklist.h"
40
41 #include "BKE_context.h"
42 #include "BKE_editmesh.h"
43 #include "BKE_report.h"
44
45 #include "ED_mesh.h"
46 #include "ED_screen.h"
47 #include "ED_uvedit.h"
48 #include "ED_view3d.h"
49
50 #include "RNA_access.h"
51 #include "RNA_define.h"
52
53 #include "WM_types.h"
54
55 #include "mesh_intern.h"  /* own include */
56
57 struct UserData {
58         BMesh *bm;
59         Mesh  *me;
60         Scene *scene;
61 };
62
63 /* -------------------------------------------------------------------- */
64 /* Vert Path */
65
66 /* callbacks */
67 static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v))
68 {
69         return !BM_elem_flag_test(v, BM_ELEM_HIDDEN);
70 }
71 static bool verttag_test_cb(BMVert *v, void *UNUSED(user_data_v))
72 {
73         return BM_elem_flag_test_bool(v, BM_ELEM_SELECT);
74 }
75 static void verttag_set_cb(BMVert *v, bool val, void *user_data_v)
76 {
77         struct UserData *user_data = user_data_v;
78         BM_vert_select_set(user_data->bm, v, val);
79 }
80
81 static bool mouse_mesh_shortest_path_vert(ViewContext *vc)
82 {
83         /* unlike edge/face versions, this uses a bmesh operator */
84
85         BMEditMesh *em = vc->em;
86         BMesh *bm = em->bm;
87         BMVert *v_dst;
88         float dist = 75.0f;
89         const bool use_length = true;
90
91         v_dst = EDBM_vert_find_nearest(vc, &dist, false, false);
92         if (v_dst) {
93                 struct UserData user_data = {bm, vc->obedit->data, vc->scene};
94                 LinkNode *path = NULL;
95                 BMVert *v_act = BM_mesh_active_vert_get(bm);
96
97                 if (v_act && (v_act != v_dst)) {
98                         if ((path = BM_mesh_calc_path_vert(bm, v_act, v_dst, use_length,
99                                                            &user_data, verttag_filter_cb)))
100                         {
101                                 BM_select_history_remove(bm, v_act);
102                         }
103                 }
104
105                 if (path) {
106                         /* toggle the flag */
107                         bool all_set = true;
108                         LinkNode *node;
109
110                         node = path;
111                         do {
112                                 if (!verttag_test_cb((BMVert *)node->link, &user_data)) {
113                                         all_set = false;
114                                         break;
115                                 }
116                         } while ((node = node->next));
117
118                         node = path;
119                         do {
120                                 verttag_set_cb((BMVert *)node->link, !all_set, &user_data);
121                         } while ((node = node->next));
122
123                         BLI_linklist_free(path, NULL);
124                 }
125                 else {
126                         const bool is_act = !verttag_test_cb(v_dst, &user_data);
127                         verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */
128                 }
129
130                 EDBM_selectmode_flush(em);
131
132                 /* even if this is selected it may not be in the selection list */
133                 if (BM_elem_flag_test(v_dst, BM_ELEM_SELECT) == 0)
134                         BM_select_history_remove(bm, v_dst);
135                 else
136                         BM_select_history_store(bm, v_dst);
137
138                 EDBM_update_generic(em, false, false);
139
140                 return true;
141         }
142         else {
143                 return false;
144         }
145 }
146
147
148
149 /* -------------------------------------------------------------------- */
150 /* Edge Path */
151
152 /* callbacks */
153 static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
154 {
155         return !BM_elem_flag_test(e, BM_ELEM_HIDDEN);
156 }
157 static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
158 {
159         struct UserData *user_data = user_data_v;
160         Scene *scene = user_data->scene;
161         BMesh *bm = user_data->bm;
162
163         switch (scene->toolsettings->edge_mode) {
164                 case EDGE_MODE_SELECT:
165                         return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false;
166                 case EDGE_MODE_TAG_SEAM:
167                         return BM_elem_flag_test(e, BM_ELEM_SEAM) ? true : false;
168                 case EDGE_MODE_TAG_SHARP:
169                         return BM_elem_flag_test(e, BM_ELEM_SMOOTH) ? false : true;
170                 case EDGE_MODE_TAG_CREASE:
171                         return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? true : false;
172                 case EDGE_MODE_TAG_BEVEL:
173                         return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? true : false;
174 #ifdef WITH_FREESTYLE
175                 case EDGE_MODE_TAG_FREESTYLE:
176                         {
177                                 FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE);
178                                 return (!fed) ? FALSE : (fed->flag & FREESTYLE_EDGE_MARK) ? true : false;
179                         }
180                         break;
181 #endif
182         }
183         return 0;
184 }
185 static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
186 {
187         struct UserData *user_data = user_data_v;
188         Scene *scene = user_data->scene;
189         BMesh *bm = user_data->bm;
190
191         switch (scene->toolsettings->edge_mode) {
192                 case EDGE_MODE_SELECT:
193                         BM_edge_select_set(bm, e, val);
194                         break;
195                 case EDGE_MODE_TAG_SEAM:
196                         BM_elem_flag_set(e, BM_ELEM_SEAM, val);
197                         break;
198                 case EDGE_MODE_TAG_SHARP:
199                         BM_elem_flag_set(e, BM_ELEM_SMOOTH, !val);
200                         break;
201                 case EDGE_MODE_TAG_CREASE:
202                         BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f);
203                         break;
204                 case EDGE_MODE_TAG_BEVEL:
205                         BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f);
206                         break;
207 #ifdef WITH_FREESTYLE
208                 case EDGE_MODE_TAG_FREESTYLE:
209                 {
210                         FreestyleEdge *fed;
211                         fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE);
212                         if (!val)
213                                 fed->flag &= ~FREESTYLE_EDGE_MARK;
214                         else
215                                 fed->flag |= FREESTYLE_EDGE_MARK;
216                         break;
217                 }
218 #endif
219         }
220 }
221
222 static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me)
223 {
224         BMesh *bm = me->edit_btmesh->bm;
225
226         switch (scene->toolsettings->edge_mode) {
227                 case EDGE_MODE_TAG_CREASE:
228                         BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
229                         break;
230                 case EDGE_MODE_TAG_BEVEL:
231                         BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
232                         break;
233 #ifdef WITH_FREESTYLE
234                 case EDGE_MODE_TAG_FREESTYLE:
235                         if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
236                                 BM_data_layer_add(bm, &bm->edata, CD_FREESTYLE_EDGE);
237                         }
238                         break;
239 #endif
240                 default:
241                         break;
242         }
243 }
244
245 /* mesh shortest path select, uses prev-selected edge */
246
247 /* since you want to create paths with multiple selects, it doesn't have extend option */
248 static bool mouse_mesh_shortest_path_edge(ViewContext *vc)
249 {
250         BMEditMesh *em = vc->em;
251         BMesh *bm = em->bm;
252         BMEdge *e_dst;
253         float dist = 75.0f;
254         const bool use_length = true;
255
256         e_dst = EDBM_edge_find_nearest(vc, &dist);
257         if (e_dst) {
258                 const char edge_mode = vc->scene->toolsettings->edge_mode;
259                 struct UserData user_data = {bm, vc->obedit->data, vc->scene};
260                 LinkNode *path = NULL;
261                 Mesh *me = vc->obedit->data;
262                 BMEdge *e_act = BM_mesh_active_edge_get(bm);
263
264                 edgetag_ensure_cd_flag(vc->scene, em->ob->data);
265
266                 if (e_act && (e_act != e_dst)) {
267                         if ((path = BM_mesh_calc_path_edge(bm, e_act, e_dst, use_length,
268                                                            &user_data, edgetag_filter_cb)))
269                         {
270                                 BM_select_history_remove(bm, e_act);
271                         }
272                 }
273
274                 if (path) {
275                         /* toggle the flag */
276                         bool all_set = true;
277                         LinkNode *node;
278
279                         node = path;
280                         do {
281                                 if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) {
282                                         all_set = false;
283                                         break;
284                                 }
285                         } while ((node = node->next));
286
287                         node = path;
288                         do {
289                                 edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data);
290                         } while ((node = node->next));
291
292                         BLI_linklist_free(path, NULL);
293                 }
294                 else {
295                         const bool is_act = !edgetag_test_cb(e_dst, &user_data);
296                         edgetag_ensure_cd_flag(vc->scene, vc->obedit->data);
297                         edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
298                 }
299
300                 if (edge_mode != EDGE_MODE_SELECT) {
301                         /* simple rules - last edge is _always_ active and selected */
302                         if (e_act)
303                                 BM_edge_select_set(bm, e_act, false);
304                         BM_edge_select_set(bm, e_dst, true);
305                         BM_select_history_store(bm, e_dst);
306                 }
307
308                 EDBM_selectmode_flush(em);
309
310                 /* even if this is selected it may not be in the selection list */
311                 if (edge_mode == EDGE_MODE_SELECT) {
312                         if (edgetag_test_cb(e_dst, &user_data) == 0)
313                                 BM_select_history_remove(bm, e_dst);
314                         else
315                                 BM_select_history_store(bm, e_dst);
316                 }
317
318                 /* force drawmode for mesh */
319                 switch (edge_mode) {
320
321                         case EDGE_MODE_TAG_SEAM:
322                                 me->drawflag |= ME_DRAWSEAMS;
323                                 ED_uvedit_live_unwrap(vc->scene, vc->obedit);
324                                 break;
325                         case EDGE_MODE_TAG_SHARP:
326                                 me->drawflag |= ME_DRAWSHARP;
327                                 break;
328                         case EDGE_MODE_TAG_CREASE:
329                                 me->drawflag |= ME_DRAWCREASES;
330                                 break;
331                         case EDGE_MODE_TAG_BEVEL:
332                                 me->drawflag |= ME_DRAWBWEIGHTS;
333                                 break;
334 #ifdef WITH_FREESTYLE
335                         case EDGE_MODE_TAG_FREESTYLE:
336                                 me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
337                                 break;
338 #endif
339                 }
340
341                 EDBM_update_generic(em, false, false);
342
343                 return true;
344         }
345         else {
346                 return false;
347         }
348 }
349
350
351
352 /* -------------------------------------------------------------------- */
353 /* Face Path */
354
355 /* callbacks */
356 static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v))
357 {
358         return !BM_elem_flag_test(f, BM_ELEM_HIDDEN);
359 }
360 //static bool facetag_test_cb(Scene *UNUSED(scene), BMesh *UNUSED(bm), BMFace *f)
361 static bool facetag_test_cb(BMFace *f, void *UNUSED(user_data_v))
362 {
363         return BM_elem_flag_test_bool(f, BM_ELEM_SELECT);
364 }
365 //static void facetag_set_cb(BMesh *bm, Scene *UNUSED(scene), BMFace *f, const bool val)
366 static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
367 {
368         struct UserData *user_data = user_data_v;
369         BM_face_select_set(user_data->bm, f, val);
370 }
371
372 static bool mouse_mesh_shortest_path_face(ViewContext *vc)
373 {
374         BMEditMesh *em = vc->em;
375         BMesh *bm = em->bm;
376         BMFace *f_dst;
377         float dist = 75.0f;
378         const bool use_length = true;
379
380         f_dst = EDBM_face_find_nearest(vc, &dist);
381         if (f_dst) {
382                 struct UserData user_data = {bm, vc->obedit->data, vc->scene};
383                 LinkNode *path = NULL;
384                 BMFace *f_act = BM_mesh_active_face_get(bm, false, true);
385
386                 if (f_act) {
387                         if (f_act != f_dst) {
388                                 if ((path = BM_mesh_calc_path_face(bm, f_act, f_dst, use_length,
389                                                                    &user_data, facetag_filter_cb)))
390                                 {
391                                         BM_select_history_remove(bm, f_act);
392                                 }
393                         }
394                 }
395
396                 if (path) {
397                         /* toggle the flag */
398                         bool all_set = true;
399                         LinkNode *node;
400
401                         node = path;
402                         do {
403                                 if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
404                                         all_set = false;
405                                         break;
406                                 }
407                         } while ((node = node->next));
408
409                         node = path;
410                         do {
411                                 facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
412                         } while ((node = node->next));
413
414                         BLI_linklist_free(path, NULL);
415                 }
416                 else {
417                         const bool is_act = !facetag_test_cb(f_dst, &user_data);
418                         facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
419                 }
420
421                 EDBM_selectmode_flush(em);
422
423                 /* even if this is selected it may not be in the selection list */
424                 if (facetag_test_cb(f_dst, &user_data) == 0)
425                         BM_select_history_remove(bm, f_dst);
426                 else
427                         BM_select_history_store(bm, f_dst);
428
429                 BM_mesh_active_face_set(bm, f_dst);
430
431                 EDBM_update_generic(em, false, false);
432
433                 return true;
434         }
435         else {
436                 return false;
437         }
438 }
439
440
441
442 /* -------------------------------------------------------------------- */
443 /* Main Operator for vert/edge/face tag */
444
445 static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
446 {
447         ViewContext vc;
448         BMEditMesh *em;
449
450         view3d_operator_needs_opengl(C);
451
452         em_setup_viewcontext(C, &vc);
453         copy_v2_v2_int(vc.mval, event->mval);
454         em = vc.em;
455
456         if (em->selectmode & SCE_SELECT_VERTEX) {
457                 if (mouse_mesh_shortest_path_vert(&vc)) {
458                         return OPERATOR_FINISHED;
459                 }
460                 else {
461                         return OPERATOR_PASS_THROUGH;
462                 }
463         }
464         else if (em->selectmode & SCE_SELECT_EDGE) {
465                 if (mouse_mesh_shortest_path_edge(&vc)) {
466                         return OPERATOR_FINISHED;
467                 }
468                 else {
469                         return OPERATOR_PASS_THROUGH;
470                 }
471         }
472         else if (em->selectmode & SCE_SELECT_FACE) {
473                 if (mouse_mesh_shortest_path_face(&vc)) {
474                         return OPERATOR_FINISHED;
475                 }
476                 else {
477                         return OPERATOR_PASS_THROUGH;
478                 }
479         }
480
481         return OPERATOR_PASS_THROUGH;
482 }
483
484 void MESH_OT_shortest_path_pick(wmOperatorType *ot)
485 {
486         /* identifiers */
487         ot->name = "Pick Shortest Path";
488         ot->idname = "MESH_OT_shortest_path_pick";
489         ot->description = "Select shortest path between two selections";
490
491         /* api callbacks */
492         ot->invoke = edbm_shortest_path_pick_invoke;
493         ot->poll = ED_operator_editmesh_region_view3d;
494
495         /* flags */
496         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
497
498         /* properties */
499         RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
500 }
501
502
503
504 /* -------------------------------------------------------------------- */
505 /* Select path between existing selection */
506
507 static bool ele_filter_visible_cb(BMElem *ele, void *UNUSED(user_data))
508 {
509         return !BM_elem_flag_test(ele, BM_ELEM_HIDDEN);
510 }
511
512 static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
513 {
514         Object *ob = CTX_data_edit_object(C);
515         BMEditMesh *em = BKE_editmesh_from_object(ob);
516         BMesh *bm = em->bm;
517         BMIter iter;
518         BMEditSelection *ese_src, *ese_dst;
519         BMElem *ele_src = NULL, *ele_dst = NULL, *ele;
520
521         const bool use_length = RNA_boolean_get(op->ptr, "use_length");
522
523         /* first try to find vertices in edit selection */
524         ese_src = bm->selected.last;
525         if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype  == ese_dst->htype)) {
526                 ele_src = ese_src->ele;
527                 ele_dst = ese_dst->ele;
528         }
529         else {
530                 /* if selection history isn't available, find two selected elements */
531                 ele_src = ele_dst = NULL;
532                 if ((em->selectmode & SCE_SELECT_VERTEX) && (bm->totvertsel >= 2)) {
533                         BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
534                                 if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
535                                         if      (ele_src == NULL) ele_src = ele;
536                                         else if (ele_dst == NULL) ele_dst = ele;
537                                         else                      break;
538                                 }
539                         }
540                 }
541
542                 if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_EDGE) && (bm->totedgesel >= 2)) {
543                         ele_src = NULL;
544                         BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
545                                 if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
546                                         if      (ele_src == NULL) ele_src = ele;
547                                         else if (ele_dst == NULL) ele_dst = ele;
548                                         else                      break;
549                                 }
550                         }
551                 }
552
553                 if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_FACE) && (bm->totfacesel >= 2)) {
554                         ele_src = NULL;
555                         BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
556                                 if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
557                                         if      (ele_src == NULL) ele_src = ele;
558                                         else if (ele_dst == NULL) ele_dst = ele;
559                                         else                      break;
560                                 }
561                         }
562                 }
563         }
564
565         if (ele_src && ele_dst) {
566                 LinkNode *path = NULL;
567                 switch (ele_src->head.htype) {
568                         case BM_VERT:
569                                 path = BM_mesh_calc_path_vert(
570                                            bm, (BMVert *)ele_src, (BMVert *)ele_dst, use_length,
571                                            NULL, (bool (*)(BMVert *, void *))ele_filter_visible_cb);
572                                 break;
573                         case BM_EDGE:
574                                 path = BM_mesh_calc_path_edge(
575                                            bm, (BMEdge *)ele_src, (BMEdge *)ele_dst, use_length,
576                                            NULL, (bool (*)(BMEdge *, void *))ele_filter_visible_cb);
577                                 break;
578                         case BM_FACE:
579                                 path = BM_mesh_calc_path_face(
580                                            bm, (BMFace *)ele_src, (BMFace *)ele_dst, use_length,
581                                            NULL, (bool (*)(BMFace *, void *))ele_filter_visible_cb);
582                                 break;
583                 }
584
585                 if (path) {
586                         LinkNode *node = path;
587
588                         do {
589                                 BM_elem_select_set(bm, node->link, true);
590                         } while ((node = node->next));
591
592                         BLI_linklist_free(path, NULL);
593                 }
594                 else {
595                         BKE_report(op->reports, RPT_WARNING, "Path can't be found");
596                         return OPERATOR_CANCELLED;
597                 }
598
599                 EDBM_selectmode_flush(em);
600                 EDBM_update_generic(em, false, false);
601
602                 return OPERATOR_FINISHED;
603         }
604         else {
605                 BKE_report(op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected");
606                 return OPERATOR_CANCELLED;
607         }
608 }
609
610 void MESH_OT_shortest_path_select(wmOperatorType *ot)
611 {
612         /* identifiers */
613         ot->name = "Select Shortest Path";
614         ot->idname = "MESH_OT_shortest_path_select";
615         ot->description = "Selected vertex path between two vertices";
616
617         /* api callbacks */
618         ot->exec = edbm_shortest_path_select_exec;
619         ot->poll = ED_operator_editmesh;
620
621         /* flags */
622         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
623
624         /* properties */
625         RNA_def_boolean(ot->srna, "use_length", true, "Length", "Use length when measuring distance");
626 }