10a03050d4bbe666148f0ccf960679ccd4f38b7d
[blender.git] / source / blender / bmesh / intern / bmesh_marking.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  * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/intern/bmesh_marking.c
24  *  \ingroup bmesh
25  *
26  * Selection routines for bmesh structures.
27  * This is actually all old code ripped from
28  * editmesh_lib.c and slightly modified to work
29  * for bmesh's. This also means that it has some
30  * of the same problems.... something that
31  * that should be addressed eventually.
32  */
33
34 #include <stddef.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_scene_types.h"
39
40 #include "BLI_math.h"
41 #include "BLI_listbase.h"
42
43 #include "bmesh.h"
44 #include "bmesh_structure.h"
45
46 static void recount_totsels(BMesh *bm)
47 {
48         const char iter_types[3] = {BM_VERTS_OF_MESH,
49                                     BM_EDGES_OF_MESH,
50                                     BM_FACES_OF_MESH};
51         int *tots[3];
52         int i;
53
54         /* recount (tot * sel) variables */
55         bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
56         tots[0] = &bm->totvertsel;
57         tots[1] = &bm->totedgesel;
58         tots[2] = &bm->totfacesel;
59
60         for (i = 0; i < 3; i++) {
61                 BMIter iter;
62                 BMElem *ele;
63                 int count = 0;
64
65                 BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
66                         if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) count += 1;
67                 }
68                 *tots[i] = count;
69         }
70 }
71
72 /** \name BMesh helper functions for selection & hide flushing.
73  * \{ */
74
75 static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
76 {
77         const BMEdge *e_iter = e_first;
78
79         /* start by stepping over the current edge */
80         while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
81                 if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
82                         return true;
83                 }
84         }
85         return false;
86 }
87
88 #if 0
89 static bool bm_vert_is_edge_select_any(const BMVert *v)
90 {
91         if (v->e) {
92                 const BMEdge *e_iter, *e_first;
93                 e_iter = e_first = v->e;
94                 do {
95                         if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
96                                 return true;
97                         }
98                 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
99         }
100         return false;
101 }
102 #endif
103
104 static bool bm_vert_is_edge_visible_any(const BMVert *v)
105 {
106         if (v->e) {
107                 const BMEdge *e_iter, *e_first;
108                 e_iter = e_first = v->e;
109                 do {
110                         if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
111                                 return true;
112                         }
113                 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
114         }
115         return false;
116 }
117
118 static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
119 {
120         const BMLoop *l_iter = l_first;
121
122         /* start by stepping over the current face */
123         while ((l_iter = l_iter->radial_next) != l_first) {
124                 if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
125                         return true;
126                 }
127         }
128         return false;
129 }
130
131 #if 0
132 static bool bm_edge_is_face_select_any(const BMEdge *e)
133 {
134         if (e->l) {
135                 const BMLoop *l_iter, *l_first;
136                 l_iter = l_first = e->l;
137                 do {
138                         if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
139                                 return true;
140                         }
141                 } while ((l_iter = l_iter->radial_next) != l_first);
142         }
143         return false;
144 }
145 #endif
146
147 static bool bm_edge_is_face_visible_any(const BMEdge *e)
148 {
149         if (e->l) {
150                 const BMLoop *l_iter, *l_first;
151                 l_iter = l_first = e->l;
152                 do {
153                         if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
154                                 return true;
155                         }
156                 } while ((l_iter = l_iter->radial_next) != l_first);
157         }
158         return false;
159 }
160
161 /** \} */
162
163 /**
164  * \brief Select Mode Clean
165  *
166  * Remove isolated selected elements when in a mode doesn't support them.
167  * eg: in edge-mode a selected vertex must be connected to a selected edge.
168  *
169  * \note this could be made apart of #BM_mesh_select_mode_flush_ex
170  */
171 void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
172 {
173         if (selectmode & SCE_SELECT_VERTEX) {
174                 /* pass */
175         }
176         else if (selectmode & SCE_SELECT_EDGE) {
177                 BMIter iter;
178
179                 if (bm->totvertsel) {
180                         BMVert *v;
181                         BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
182                                 BM_elem_flag_disable(v, BM_ELEM_SELECT);
183                         }
184                         bm->totvertsel = 0;
185                 }
186
187                 if (bm->totedgesel) {
188                         BMEdge *e;
189                         BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
190                                 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
191                                         BM_vert_select_set(bm, e->v1, true);
192                                         BM_vert_select_set(bm, e->v2, true);
193                                 }
194                         }
195                 }
196         }
197         else if (selectmode & SCE_SELECT_FACE) {
198                 BMIter iter;
199
200                 if (bm->totvertsel) {
201                         BMVert *v;
202                         BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
203                                 BM_elem_flag_disable(v, BM_ELEM_SELECT);
204                         }
205                         bm->totvertsel = 0;
206                 }
207
208                 if (bm->totedgesel) {
209                         BMEdge *e;
210                         BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
211                                 BM_elem_flag_disable(e, BM_ELEM_SELECT);
212                         }
213                         bm->totedgesel = 0;
214                 }
215
216                 if (bm->totfacesel) {
217                         BMFace *f;
218                         BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
219                                 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
220                                         BMLoop *l_iter, *l_first;
221                                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
222                                         do {
223                                                 BM_edge_select_set(bm, l_iter->e, true);
224                                         } while ((l_iter = l_iter->next) != l_first);
225                                 }
226                         }
227                 }
228         }
229 }
230
231 void BM_mesh_select_mode_clean(BMesh *bm)
232 {
233         BM_mesh_select_mode_clean_ex(bm, bm->selectmode);
234 }
235
236 /**
237  * \brief Select Mode Flush
238  *
239  * Makes sure to flush selections 'upwards'
240  * (ie: all verts of an edge selects the edge and so on).
241  * This should only be called by system and not tool authors.
242  */
243 void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
244 {
245         BMEdge *e;
246         BMLoop *l_iter;
247         BMLoop *l_first;
248         BMFace *f;
249
250         BMIter eiter;
251         BMIter fiter;
252
253         if (selectmode & SCE_SELECT_VERTEX) {
254                 /* both loops only set edge/face flags and read off verts */
255                 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
256                         if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
257                             BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
258                             !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
259                         {
260                                 BM_elem_flag_enable(e, BM_ELEM_SELECT);
261                         }
262                         else {
263                                 BM_elem_flag_disable(e, BM_ELEM_SELECT);
264                         }
265                 }
266                 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
267                         bool ok = true;
268                         if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
269                                 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
270                                 do {
271                                         if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
272                                                 ok = false;
273                                                 break;
274                                         }
275                                 } while ((l_iter = l_iter->next) != l_first);
276                         }
277                         else {
278                                 ok = false;
279                         }
280
281                         BM_elem_flag_set(f, BM_ELEM_SELECT, ok);
282                 }
283         }
284         else if (selectmode & SCE_SELECT_EDGE) {
285                 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
286                         bool ok = true;
287                         if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
288                                 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
289                                 do {
290                                         if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
291                                                 ok = false;
292                                                 break;
293                                         }
294                                 } while ((l_iter = l_iter->next) != l_first);
295                         }
296                         else {
297                                 ok = false;
298                         }
299
300                         BM_elem_flag_set(f, BM_ELEM_SELECT, ok);
301                 }
302         }
303
304         /* Remove any deselected elements from the BMEditSelection */
305         BM_select_history_validate(bm);
306
307         recount_totsels(bm);
308 }
309
310 void BM_mesh_select_mode_flush(BMesh *bm)
311 {
312         BM_mesh_select_mode_flush_ex(bm, bm->selectmode);
313 }
314
315 /**
316  * mode independent flushing up/down
317  */
318 void BM_mesh_deselect_flush(BMesh *bm)
319 {
320         BMIter eiter;
321         BMEdge *e;
322
323         BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
324                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
325                         if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
326                                 if (!BM_elem_flag_test(e->v1, BM_ELEM_SELECT) ||
327                                     !BM_elem_flag_test(e->v2, BM_ELEM_SELECT))
328                                 {
329                                         BM_elem_flag_disable(e, BM_ELEM_SELECT);
330                                 }
331                         }
332
333                         if (e->l && !BM_elem_flag_test(e, BM_ELEM_SELECT)) {
334                                 BMLoop *l_iter;
335                                 BMLoop *l_first;
336
337                                 l_iter = l_first = e->l;
338                                 do {
339                                         BM_elem_flag_disable(l_iter->f, BM_ELEM_SELECT);
340                                 } while ((l_iter = l_iter->radial_next) != l_first);
341                         }
342                 }
343         }
344
345         /* Remove any deselected elements from the BMEditSelection */
346         BM_select_history_validate(bm);
347
348         recount_totsels(bm);
349 }
350
351
352 /**
353  * mode independent flushing up/down
354  */
355 void BM_mesh_select_flush(BMesh *bm)
356 {
357         BMEdge *e;
358         BMLoop *l_iter;
359         BMLoop *l_first;
360         BMFace *f;
361
362         BMIter eiter;
363         BMIter fiter;
364
365         bool ok;
366
367         BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
368                 if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
369                     BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
370                     !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
371                 {
372                         BM_elem_flag_enable(e, BM_ELEM_SELECT);
373                 }
374         }
375         BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
376                 ok = true;
377                 if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
378                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
379                         do {
380                                 if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
381                                         ok = false;
382                                         break;
383                                 }
384                         } while ((l_iter = l_iter->next) != l_first);
385                 }
386                 else {
387                         ok = false;
388                 }
389
390                 if (ok) {
391                         BM_elem_flag_enable(f, BM_ELEM_SELECT);
392                 }
393         }
394
395         recount_totsels(bm);
396 }
397
398 /**
399  * \brief Select Vert
400  *
401  * Changes selection state of a single vertex
402  * in a mesh
403  */
404 void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
405 {
406         BLI_assert(v->head.htype == BM_VERT);
407
408         if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
409                 return;
410         }
411
412         if (select) {
413                 if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) {
414                         BM_elem_flag_enable(v, BM_ELEM_SELECT);
415                         bm->totvertsel += 1;
416                 }
417         }
418         else {
419                 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
420                         bm->totvertsel -= 1;
421                         BM_elem_flag_disable(v, BM_ELEM_SELECT);
422                 }
423         }
424 }
425
426 /**
427  * \brief Select Edge
428  *
429  * Changes selection state of a single edge in a mesh.
430  */
431 void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
432 {
433         BLI_assert(e->head.htype == BM_EDGE);
434
435         if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
436                 return;
437         }
438
439         if (select) {
440                 if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
441                         BM_elem_flag_enable(e, BM_ELEM_SELECT);
442                         bm->totedgesel += 1;
443                 }
444                 BM_vert_select_set(bm, e->v1, true);
445                 BM_vert_select_set(bm, e->v2, true);
446         }
447         else {
448                 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
449                         BM_elem_flag_disable(e, BM_ELEM_SELECT);
450                         bm->totedgesel -= 1;
451                 }
452
453                 if ((bm->selectmode & SCE_SELECT_VERTEX) == 0) {
454                         int i;
455
456                         /* check if the vert is used by a selected edge */
457                         for (i = 0; i < 2; i++) {
458                                 BMVert *v = *((&e->v1) + i);
459                                 if (bm_vert_is_edge_select_any_other(v, e) == false) {
460                                         BM_vert_select_set(bm, v, false);
461                                 }
462                         }
463                 }
464                 else {
465                         BM_vert_select_set(bm, e->v1, false);
466                         BM_vert_select_set(bm, e->v2, false);
467                 }
468
469         }
470 }
471
472 /**
473  * \brief Select Face
474  *
475  * Changes selection state of a single
476  * face in a mesh.
477  */
478 void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
479 {
480         BMLoop *l_iter;
481         BMLoop *l_first;
482
483         BLI_assert(f->head.htype == BM_FACE);
484
485         if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
486                 return;
487         }
488
489         if (select) {
490                 if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
491                         BM_elem_flag_enable(f, BM_ELEM_SELECT);
492                         bm->totfacesel += 1;
493                 }
494
495                 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
496                 do {
497                         BM_vert_select_set(bm, l_iter->v, true);
498                         BM_edge_select_set(bm, l_iter->e, true);
499                 } while ((l_iter = l_iter->next) != l_first);
500         }
501         else {
502
503                 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
504                         BM_elem_flag_disable(f, BM_ELEM_SELECT);
505                         bm->totfacesel -= 1;
506                 }
507                 /**
508                  * \note This allows a temporarily invalid state - where for eg
509                  * an edge bay be de-selected, but an adjacent face remains selected.
510                  *
511                  * Rely on #BM_mesh_select_mode_flush to correct these cases.
512                  *
513                  * \note flushing based on mode, see T46494
514                  */
515                 if (bm->selectmode & SCE_SELECT_VERTEX) {
516                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
517                         do {
518                                 BM_vert_select_set(bm, l_iter->v, false);
519                                 BM_edge_select_set_noflush(bm, l_iter->e, false);
520                         } while ((l_iter = l_iter->next) != l_first);
521                 }
522                 else {
523                         /**
524                          * \note use #BM_edge_select_set_noflush,
525                          * vertex flushing is handled last.
526                          */
527                         if (bm->selectmode & SCE_SELECT_EDGE) {
528                                 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
529                                 do {
530                                         BM_edge_select_set_noflush(bm, l_iter->e, false);
531                                 } while ((l_iter = l_iter->next) != l_first);
532                         }
533                         else {
534                                 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
535                                 do {
536                                         if (bm_edge_is_face_select_any_other(l_iter) == false) {
537                                                 BM_edge_select_set_noflush(bm, l_iter->e, false);
538                                         }
539                                 } while ((l_iter = l_iter->next) != l_first);
540                         }
541
542                         /* flush down to verts */
543                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
544                         do {
545                                 if (bm_vert_is_edge_select_any_other(l_iter->v, l_iter->e) == false) {
546                                         BM_vert_select_set(bm, l_iter->v, false);
547                                 }
548                         } while ((l_iter = l_iter->next) != l_first);
549                 }
550         }
551 }
552
553 /** \name Non flushing versions element selection.
554  * \{ */
555
556 void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, const bool select)
557 {
558         BLI_assert(e->head.htype == BM_EDGE);
559
560         if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
561                 return;
562         }
563
564         if (select) {
565                 if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
566                         BM_elem_flag_enable(e, BM_ELEM_SELECT);
567                         bm->totedgesel += 1;
568                 }
569         }
570         else {
571                 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
572                         BM_elem_flag_disable(e, BM_ELEM_SELECT);
573                         bm->totedgesel -= 1;
574                 }
575         }
576 }
577
578 void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select)
579 {
580         BLI_assert(f->head.htype == BM_FACE);
581
582         if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
583                 return;
584         }
585
586         if (select) {
587                 if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
588                         BM_elem_flag_enable(f, BM_ELEM_SELECT);
589                         bm->totfacesel += 1;
590                 }
591         }
592         else {
593                 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
594                         BM_elem_flag_disable(f, BM_ELEM_SELECT);
595                         bm->totfacesel -= 1;
596                 }
597         }
598 }
599
600 /** \} */
601
602 /**
603  * Select Mode Set
604  *
605  * Sets the selection mode for the bmesh,
606  * updating the selection state.
607  */
608 void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
609 {
610         BMIter iter;
611         BMElem *ele;
612
613         bm->selectmode = selectmode;
614
615         if (bm->selectmode & SCE_SELECT_VERTEX) {
616                 /* disabled because selection flushing handles these */
617 #if 0
618                 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
619                         BM_elem_flag_disable(ele, BM_ELEM_SELECT);
620                 }
621                 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
622                         BM_elem_flag_disable(ele, BM_ELEM_SELECT);
623                 }
624 #endif
625                 BM_mesh_select_mode_flush(bm);
626         }
627         else if (bm->selectmode & SCE_SELECT_EDGE) {
628                 /* disabled because selection flushing handles these */
629 #if 0
630                 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
631                         BM_elem_flag_disable(ele, BM_ELEM_SELECT);
632                 }
633 #endif
634
635                 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
636                         if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
637                                 BM_edge_select_set(bm, (BMEdge *)ele, true);
638                         }
639                 }
640                 BM_mesh_select_mode_flush(bm);
641         }
642         else if (bm->selectmode & SCE_SELECT_FACE) {
643                 /* disabled because selection flushing handles these */
644 #if 0
645                 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
646                         BM_elem_flag_disable(ele, BM_ELEM_SELECT);
647                 }
648 #endif
649                 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
650                         if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
651                                 BM_face_select_set(bm, (BMFace *)ele, true);
652                         }
653                 }
654                 BM_mesh_select_mode_flush(bm);
655         }
656 }
657
658 /**
659  * counts number of elements with flag enabled/disabled
660  */
661 static int bm_mesh_flag_count(
662         BMesh *bm, const char htype, const char hflag,
663         const bool respecthide, const bool test_for_enabled)
664 {
665         BMElem *ele;
666         BMIter iter;
667         int tot = 0;
668
669         BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
670
671         if (htype & BM_VERT) {
672                 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
673                         if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) continue;
674                         if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) tot++;
675                 }
676         }
677         if (htype & BM_EDGE) {
678                 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
679                         if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) continue;
680                         if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) tot++;
681                 }
682         }
683         if (htype & BM_FACE) {
684                 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
685                         if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) continue;
686                         if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) tot++;
687                 }
688         }
689
690         return tot;
691 }
692
693 int BM_mesh_elem_hflag_count_enabled(BMesh *bm, const char htype, const char hflag, const bool respecthide)
694 {
695         return bm_mesh_flag_count(bm, htype, hflag, respecthide, true);
696 }
697
698 int BM_mesh_elem_hflag_count_disabled(BMesh *bm, const char htype, const char hflag, const bool respecthide)
699 {
700         return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
701 }
702
703 /**
704  * \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
705  * \note by design, this will not touch the editselection history stuff
706  */
707 void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
708 {
709         switch (ele->head.htype) {
710                 case BM_VERT:
711                         BM_vert_select_set(bm, (BMVert *)ele, select);
712                         break;
713                 case BM_EDGE:
714                         BM_edge_select_set(bm, (BMEdge *)ele, select);
715                         break;
716                 case BM_FACE:
717                         BM_face_select_set(bm, (BMFace *)ele, select);
718                         break;
719                 default:
720                         BLI_assert(0);
721                         break;
722         }
723 }
724
725 /* this replaces the active flag used in uv/face mode */
726 void BM_mesh_active_face_set(BMesh *bm, BMFace *efa)
727 {
728         bm->act_face = efa;
729 }
730
731 BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
732 {
733         if (bm->act_face && (!is_selected || BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT))) {
734                 return bm->act_face;
735         }
736         else if (is_sloppy) {
737                 BMIter iter;
738                 BMFace *f = NULL;
739                 BMEditSelection *ese;
740
741                 /* Find the latest non-hidden face from the BMEditSelection */
742                 ese = bm->selected.last;
743                 for ( ; ese; ese = ese->prev) {
744                         if (ese->htype == BM_FACE) {
745                                 f = (BMFace *)ese->ele;
746
747                                 if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
748                                         f = NULL;
749                                 }
750                                 else if (is_selected && !BM_elem_flag_test(f, BM_ELEM_SELECT)) {
751                                         f = NULL;
752                                 }
753                                 else {
754                                         break;
755                                 }
756                         }
757                 }
758                 /* Last attempt: try to find any selected face */
759                 if (f == NULL) {
760                         BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
761                                 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
762                                         break;
763                                 }
764                         }
765                 }
766                 return f; /* can still be null */
767         }
768         return NULL;
769 }
770
771 BMEdge *BM_mesh_active_edge_get(BMesh *bm)
772 {
773         if (bm->selected.last) {
774                 BMEditSelection *ese = bm->selected.last;
775
776                 if (ese && ese->htype == BM_EDGE) {
777                         return (BMEdge *)ese->ele;
778                 }
779         }
780
781         return NULL;
782 }
783
784 BMVert *BM_mesh_active_vert_get(BMesh *bm)
785 {
786         if (bm->selected.last) {
787                 BMEditSelection *ese = bm->selected.last;
788
789                 if (ese && ese->htype == BM_VERT) {
790                         return (BMVert *)ese->ele;
791                 }
792         }
793
794         return NULL;
795 }
796
797 BMElem *BM_mesh_active_elem_get(BMesh *bm)
798 {
799         if (bm->selected.last) {
800                 BMEditSelection *ese = bm->selected.last;
801
802                 if (ese) {
803                         return ese->ele;
804                 }
805         }
806
807         return NULL;
808 }
809
810 /**
811  * Generic way to get data from an EditSelection type
812  * These functions were written to be used by the Modifier widget
813  * when in Rotate about active mode, but can be used anywhere.
814  *
815  * - #BM_editselection_center
816  * - #BM_editselection_normal
817  * - #BM_editselection_plane
818  */
819 void BM_editselection_center(BMEditSelection *ese, float r_center[3])
820 {
821         if (ese->htype == BM_VERT) {
822                 BMVert *eve = (BMVert *)ese->ele;
823                 copy_v3_v3(r_center, eve->co);
824         }
825         else if (ese->htype == BM_EDGE) {
826                 BMEdge *eed = (BMEdge *)ese->ele;
827                 mid_v3_v3v3(r_center, eed->v1->co, eed->v2->co);
828         }
829         else if (ese->htype == BM_FACE) {
830                 BMFace *efa = (BMFace *)ese->ele;
831                 BM_face_calc_center_mean(efa, r_center);
832         }
833 }
834
835 void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
836 {
837         if (ese->htype == BM_VERT) {
838                 BMVert *eve = (BMVert *)ese->ele;
839                 copy_v3_v3(r_normal, eve->no);
840         }
841         else if (ese->htype == BM_EDGE) {
842                 BMEdge *eed = (BMEdge *)ese->ele;
843                 float plane[3]; /* need a plane to correct the normal */
844                 float vec[3]; /* temp vec storage */
845
846                 add_v3_v3v3(r_normal, eed->v1->no, eed->v2->no);
847                 sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
848
849                 /* the 2 vertex normals will be close but not at rightangles to the edge
850                  * for rotate about edge we want them to be at right angles, so we need to
851                  * do some extra calculation to correct the vert normals,
852                  * we need the plane for this */
853                 cross_v3_v3v3(vec, r_normal, plane);
854                 cross_v3_v3v3(r_normal, plane, vec);
855                 normalize_v3(r_normal);
856
857         }
858         else if (ese->htype == BM_FACE) {
859                 BMFace *efa = (BMFace *)ese->ele;
860                 copy_v3_v3(r_normal, efa->no);
861         }
862 }
863
864 /* Calculate a plane that is rightangles to the edge/vert/faces normal
865  * also make the plane run along an axis that is related to the geometry,
866  * because this is used for the manipulators Y axis. */
867 void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
868 {
869         if (ese->htype == BM_VERT) {
870                 BMVert *eve = (BMVert *)ese->ele;
871                 float vec[3] = {0.0f, 0.0f, 0.0f};
872
873                 if (ese->prev) { /* use previously selected data to make a useful vertex plane */
874                         BM_editselection_center(ese->prev, vec);
875                         sub_v3_v3v3(r_plane, vec, eve->co);
876                 }
877                 else {
878                         /* make a fake  plane thats at rightangles to the normal
879                          * we cant make a crossvec from a vec thats the same as the vec
880                          * unlikely but possible, so make sure if the normal is (0, 0, 1)
881                          * that vec isn't the same or in the same direction even. */
882                         if      (eve->no[0] < 0.5f) vec[0] = 1.0f;
883                         else if (eve->no[1] < 0.5f) vec[1] = 1.0f;
884                         else                        vec[2] = 1.0f;
885                         cross_v3_v3v3(r_plane, eve->no, vec);
886                 }
887                 normalize_v3(r_plane);
888         }
889         else if (ese->htype == BM_EDGE) {
890                 BMEdge *eed = (BMEdge *)ese->ele;
891
892                 if (BM_edge_is_boundary(eed)) {
893                         sub_v3_v3v3(r_plane, eed->l->v->co, eed->l->next->v->co);
894                 }
895                 else {
896                         /* the plane is simple, it runs along the edge
897                          * however selecting different edges can swap the direction of the y axis.
898                          * this makes it less likely for the y axis of the manipulator
899                          * (running along the edge).. to flip less often.
900                          * at least its more predictable */
901                         if (eed->v2->co[1] > eed->v1->co[1]) {  /* check which to do first */
902                                 sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co);
903                         }
904                         else {
905                                 sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
906                         }
907                 }
908
909                 normalize_v3(r_plane);
910         }
911         else if (ese->htype == BM_FACE) {
912                 BMFace *efa = (BMFace *)ese->ele;
913                 BM_face_calc_tangent_auto(efa, r_plane);
914         }
915 }
916
917 static BMEditSelection *bm_select_history_create(BMHeader *ele)
918 {
919         BMEditSelection *ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection");
920         ese->htype = ele->htype;
921         ese->ele = (BMElem *)ele;
922         return ese;
923 }
924
925 /* --- macro wrapped funcs --- */
926 bool _bm_select_history_check(BMesh *bm, const BMHeader *ele)
927 {
928         return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != NULL);
929 }
930
931 bool _bm_select_history_remove(BMesh *bm, BMHeader *ele)
932 {
933         BMEditSelection *ese = BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele));
934         if (ese) {
935                 BLI_freelinkN(&bm->selected, ese);
936                 return true;
937         }
938         else {
939                 return false;
940         }
941 }
942
943 void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele)
944 {
945         BMEditSelection *ese = bm_select_history_create(ele);
946         BLI_addtail(&(bm->selected), ese);
947 }
948
949 void _bm_select_history_store_head_notest(BMesh *bm, BMHeader *ele)
950 {
951         BMEditSelection *ese = bm_select_history_create(ele);
952         BLI_addhead(&(bm->selected), ese);
953 }
954
955 void _bm_select_history_store(BMesh *bm, BMHeader *ele)
956 {
957         if (!BM_select_history_check(bm, (BMElem *)ele)) {
958                 BM_select_history_store_notest(bm, (BMElem *)ele);
959         }
960 }
961
962 void _bm_select_history_store_head(BMesh *bm, BMHeader *ele)
963 {
964         if (!BM_select_history_check(bm, (BMElem *)ele)) {
965                 BM_select_history_store_head_notest(bm, (BMElem *)ele);
966         }
967 }
968
969 void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele)
970 {
971         BMEditSelection *ese = bm_select_history_create(ele);
972         BLI_insertlinkafter(&(bm->selected), ese_ref, ese);
973 }
974
975 void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele)
976 {
977         if (!BM_select_history_check(bm, (BMElem *)ele)) {
978                 BM_select_history_store_after_notest(bm, ese_ref, (BMElem *)ele);
979         }
980 }
981 /* --- end macro wrapped funcs --- */
982
983
984 void BM_select_history_clear(BMesh *bm)
985 {
986         BLI_freelistN(&bm->selected);
987 }
988
989
990 void BM_select_history_validate(BMesh *bm)
991 {
992         BMEditSelection *ese, *ese_next;
993
994         for (ese = bm->selected.first; ese; ese = ese_next) {
995                 ese_next = ese->next;
996                 if (!BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
997                         BLI_freelinkN(&(bm->selected), ese);
998                 }
999         }
1000 }
1001
1002 /**
1003  * Get the active mesh element (with active-face fallback).
1004  */
1005 bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
1006 {
1007         BMEditSelection *ese_last = bm->selected.last;
1008         BMFace *efa = BM_mesh_active_face_get(bm, false, false);
1009
1010         ese->next = ese->prev = NULL;
1011
1012         if (ese_last) {
1013                 if (ese_last->htype == BM_FACE) { /* if there is an active face, use it over the last selected face */
1014                         if (efa) {
1015                                 ese->ele = (BMElem *)efa;
1016                         }
1017                         else {
1018                                 ese->ele = ese_last->ele;
1019                         }
1020                         ese->htype = BM_FACE;
1021                 }
1022                 else {
1023                         ese->ele =   ese_last->ele;
1024                         ese->htype = ese_last->htype;
1025                 }
1026         }
1027         else if (efa) {
1028                 /* no edit-selection, fallback to active face */
1029                 ese->ele   = (BMElem *)efa;
1030                 ese->htype = BM_FACE;
1031         }
1032         else {
1033                 ese->ele = NULL;
1034                 return false;
1035         }
1036
1037         return true;
1038 }
1039
1040 /**
1041  * Return a map from BMVert/Edge/Face -> BMEditSelection
1042  */
1043 GHash *BM_select_history_map_create(BMesh *bm)
1044 {
1045         BMEditSelection *ese;
1046         GHash *map;
1047
1048         if (BLI_listbase_is_empty(&bm->selected)) {
1049                 return NULL;
1050         }
1051
1052         map = BLI_ghash_ptr_new(__func__);
1053
1054         for (ese = bm->selected.first; ese; ese = ese->next) {
1055                 BLI_ghash_insert(map, ese->ele, ese);
1056         }
1057
1058         return map;
1059 }
1060
1061 void BM_mesh_elem_hflag_disable_test(
1062         BMesh *bm, const char htype, const char hflag,
1063         const bool respecthide, const bool overwrite, const char hflag_test)
1064 {
1065         const char iter_types[3] = {BM_VERTS_OF_MESH,
1066                                     BM_EDGES_OF_MESH,
1067                                     BM_FACES_OF_MESH};
1068
1069         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1070
1071         const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1072
1073         int i;
1074
1075         BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1076
1077         if (hflag & BM_ELEM_SELECT) {
1078                 BM_select_history_clear(bm);
1079         }
1080
1081         if ((htype == (BM_VERT | BM_EDGE | BM_FACE)) &&
1082             (hflag == BM_ELEM_SELECT) &&
1083             (respecthide == false) &&
1084             (hflag_test == 0))
1085         {
1086                 /* fast path for deselect all, avoid topology loops
1087                  * since we know all will be de-selected anyway. */
1088                 for (i = 0; i < 3; i++) {
1089                         BMIter iter;
1090                         BMElem *ele;
1091
1092                         ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1093                         for ( ; ele; ele = BM_iter_step(&iter)) {
1094                                 BM_elem_flag_disable(ele, BM_ELEM_SELECT);
1095                         }
1096                 }
1097
1098                 bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
1099         }
1100         else {
1101                 for (i = 0; i < 3; i++) {
1102                         BMIter iter;
1103                         BMElem *ele;
1104
1105                         if (htype & flag_types[i]) {
1106                                 ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1107                                 for ( ; ele; ele = BM_iter_step(&iter)) {
1108
1109                                         if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1110                                                 /* pass */
1111                                         }
1112                                         else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1113                                                 if (hflag & BM_ELEM_SELECT) {
1114                                                         BM_elem_select_set(bm, ele, false);
1115                                                 }
1116                                                 BM_elem_flag_disable(ele, hflag);
1117                                         }
1118                                         else if (overwrite) {
1119                                                 /* no match! */
1120                                                 if (hflag & BM_ELEM_SELECT) {
1121                                                         BM_elem_select_set(bm, ele, true);
1122                                                 }
1123                                                 BM_elem_flag_enable(ele, hflag_nosel);
1124                                         }
1125                                 }
1126                         }
1127                 }
1128         }
1129 }
1130
1131 void BM_mesh_elem_hflag_enable_test(
1132         BMesh *bm, const char htype, const char hflag,
1133         const bool respecthide, const bool overwrite, const char hflag_test)
1134 {
1135         const char iter_types[3] = {BM_VERTS_OF_MESH,
1136                                     BM_EDGES_OF_MESH,
1137                                     BM_FACES_OF_MESH};
1138
1139         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1140
1141         /* use the nosel version when setting so under no
1142          * condition may a hidden face become selected.
1143          * Applying other flags to hidden faces is OK. */
1144         const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1145
1146         BMIter iter;
1147         BMElem *ele;
1148         int i;
1149
1150         BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1151
1152         if (hflag & BM_ELEM_SELECT) {
1153                 BM_select_history_clear(bm);
1154         }
1155
1156         /* note, better not attempt a fast path for selection as done with de-select
1157          * because hidden geometry and different selection modes can give different results,
1158          * we could of course check for no hidden faces and then use quicker method but its not worth it. */
1159
1160         for (i = 0; i < 3; i++) {
1161                 if (htype & flag_types[i]) {
1162                         ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1163                         for ( ; ele; ele = BM_iter_step(&iter)) {
1164
1165                                 if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1166                                         /* pass */
1167                                 }
1168                                 else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1169                                         /* match! */
1170                                         if (hflag & BM_ELEM_SELECT) {
1171                                                 BM_elem_select_set(bm, ele, true);
1172                                         }
1173                                         BM_elem_flag_enable(ele, hflag_nosel);
1174                                 }
1175                                 else if (overwrite) {
1176                                         /* no match! */
1177                                         if (hflag & BM_ELEM_SELECT) {
1178                                                 BM_elem_select_set(bm, ele, false);
1179                                         }
1180                                         BM_elem_flag_disable(ele, hflag);
1181                                 }
1182                         }
1183                 }
1184         }
1185 }
1186
1187 void BM_mesh_elem_hflag_disable_all(
1188         BMesh *bm, const char htype, const char hflag,
1189         const bool respecthide)
1190 {
1191         /* call with 0 hflag_test */
1192         BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, false, 0);
1193 }
1194
1195 void BM_mesh_elem_hflag_enable_all(
1196         BMesh *bm, const char htype, const char hflag,
1197         const bool respecthide)
1198 {
1199         /* call with 0 hflag_test */
1200         BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, false, 0);
1201 }
1202
1203 /***************** Mesh Hiding stuff *********** */
1204
1205 /**
1206  * Hide unless any connected elements are visible.
1207  * Run this after hiding a connected edge or face.
1208  */
1209 static void vert_flush_hide_set(BMVert *v)
1210 {
1211         BM_elem_flag_set(v, BM_ELEM_HIDDEN, !bm_vert_is_edge_visible_any(v));
1212 }
1213
1214 /**
1215  * Hide unless any connected elements are visible.
1216  * Run this after hiding a connected face.
1217  */
1218 static void edge_flush_hide_set(BMEdge *e)
1219 {
1220         BM_elem_flag_set(e, BM_ELEM_HIDDEN, !bm_edge_is_face_visible_any(e));
1221 }
1222
1223 void BM_vert_hide_set(BMVert *v, const bool hide)
1224 {
1225         /* vert hiding: vert + surrounding edges and faces */
1226         BLI_assert(v->head.htype == BM_VERT);
1227         if (hide) {
1228                 BLI_assert(!BM_elem_flag_test(v, BM_ELEM_SELECT));
1229         }
1230
1231         BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
1232
1233         if (v->e) {
1234                 BMEdge *e_iter, *e_first;
1235                 e_iter = e_first = v->e;
1236                 do {
1237                         BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide);
1238                         if (e_iter->l) {
1239                                 const BMLoop *l_radial_iter, *l_radial_first;
1240                                 l_radial_iter = l_radial_first = e_iter->l;
1241                                 do {
1242                                         BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide);
1243                                 } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
1244                         }
1245                 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
1246         }
1247 }
1248
1249 void BM_edge_hide_set(BMEdge *e, const bool hide)
1250 {
1251         BLI_assert(e->head.htype == BM_EDGE);
1252         if (hide) {
1253                 BLI_assert(!BM_elem_flag_test(e, BM_ELEM_SELECT));
1254         }
1255
1256         /* edge hiding: faces around the edge */
1257         if (e->l) {
1258                 const BMLoop *l_iter, *l_first;
1259                 l_iter = l_first = e->l;
1260                 do {
1261                         BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide);
1262                 } while ((l_iter = l_iter->radial_next) != l_first);
1263         }
1264
1265         BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
1266
1267         /* hide vertices if necessary */
1268         if (hide) {
1269                 vert_flush_hide_set(e->v1);
1270                 vert_flush_hide_set(e->v2);
1271         }
1272         else {
1273                 BM_elem_flag_disable(e->v1, BM_ELEM_HIDDEN);
1274                 BM_elem_flag_disable(e->v2, BM_ELEM_HIDDEN);
1275         }
1276 }
1277
1278 void BM_face_hide_set(BMFace *f, const bool hide)
1279 {
1280         BLI_assert(f->head.htype == BM_FACE);
1281         if (hide) {
1282                 BLI_assert(!BM_elem_flag_test(f, BM_ELEM_SELECT));
1283         }
1284
1285         BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
1286
1287         if (hide) {
1288                 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1289                 BMLoop *l_iter;
1290
1291                 l_iter = l_first;
1292                 do {
1293                         edge_flush_hide_set(l_iter->e);
1294                 } while ((l_iter = l_iter->next) != l_first);
1295
1296                 l_iter = l_first;
1297                 do {
1298                         vert_flush_hide_set(l_iter->v);
1299                 } while ((l_iter = l_iter->next) != l_first);
1300         }
1301         else {
1302                 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1303                 BMLoop *l_iter;
1304
1305                 l_iter = l_first;
1306                 do {
1307                         BM_elem_flag_disable(l_iter->e, BM_ELEM_HIDDEN);
1308                         BM_elem_flag_disable(l_iter->v, BM_ELEM_HIDDEN);
1309                 } while ((l_iter = l_iter->next) != l_first);
1310         }
1311 }
1312
1313 void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide)
1314 {
1315         /* Follow convention of always deselecting before
1316          * hiding an element */
1317         switch (head->htype) {
1318                 case BM_VERT:
1319                         if (hide) BM_vert_select_set(bm, (BMVert *)head, false);
1320                         BM_vert_hide_set((BMVert *)head, hide);
1321                         break;
1322                 case BM_EDGE:
1323                         if (hide) BM_edge_select_set(bm, (BMEdge *)head, false);
1324                         BM_edge_hide_set((BMEdge *)head, hide);
1325                         break;
1326                 case BM_FACE:
1327                         if (hide) BM_face_select_set(bm, (BMFace *)head, false);
1328                         BM_face_hide_set((BMFace *)head, hide);
1329                         break;
1330                 default:
1331                         BMESH_ASSERT(0);
1332                         break;
1333         }
1334 }