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