Recent spinlock commit made scheduling unsafe for threading
[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
820 /* --- macro wrapped funcs --- */
821 bool _bm_select_history_check(BMesh *bm, const BMHeader *ele)
822 {
823         return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != NULL);
824 }
825
826 bool _bm_select_history_remove(BMesh *bm, BMHeader *ele)
827 {
828         BMEditSelection *ese = BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele));
829         if (ese) {
830                 BLI_freelinkN(&bm->selected, ese);
831                 return true;
832         }
833         else {
834                 return false;
835         }
836 }
837
838 void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele)
839 {
840         BMEditSelection *ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection");
841         ese->htype = ele->htype;
842         ese->ele = (BMElem *)ele;
843         BLI_addtail(&(bm->selected), ese);
844 }
845
846 void _bm_select_history_store(BMesh *bm, BMHeader *ele)
847 {
848         if (!BM_select_history_check(bm, (BMElem *)ele)) {
849                 BM_select_history_store_notest(bm, (BMElem *)ele);
850         }
851 }
852 /* --- end macro wrapped funcs --- */
853
854
855 void BM_select_history_clear(BMesh *bm)
856 {
857         BLI_freelistN(&bm->selected);
858         bm->selected.first = bm->selected.last = NULL;
859 }
860
861
862 void BM_select_history_validate(BMesh *bm)
863 {
864         BMEditSelection *ese, *nextese;
865
866         ese = bm->selected.first;
867
868         while (ese) {
869                 nextese = ese->next;
870                 if (!BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
871                         BLI_freelinkN(&(bm->selected), ese);
872                 }
873                 ese = nextese;
874         }
875 }
876
877 /* utility function */
878 bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
879 {
880         BMEditSelection *ese_last = bm->selected.last;
881         BMFace *efa = BM_mesh_active_face_get(bm, false, false);
882
883         ese->next = ese->prev = NULL;
884
885         if (ese_last) {
886                 if (ese_last->htype == BM_FACE) { /* if there is an active face, use it over the last selected face */
887                         if (efa) {
888                                 ese->ele = (BMElem *)efa;
889                         }
890                         else {
891                                 ese->ele = ese_last->ele;
892                         }
893                         ese->htype = BM_FACE;
894                 }
895                 else {
896                         ese->ele =   ese_last->ele;
897                         ese->htype = ese_last->htype;
898                 }
899         }
900         else if (efa) { /* no */
901                 ese->ele   = (BMElem *)efa;
902                 ese->htype = BM_FACE;
903         }
904         else {
905                 ese->ele = NULL;
906                 return false;
907         }
908
909         return true;
910 }
911
912 void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hflag,
913                                      const bool respecthide, const char hflag_test)
914 {
915         const char iter_types[3] = {BM_VERTS_OF_MESH,
916                                     BM_EDGES_OF_MESH,
917                                     BM_FACES_OF_MESH};
918
919         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
920
921         int i;
922
923         BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
924
925         if (hflag & BM_ELEM_SELECT) {
926                 BM_select_history_clear(bm);
927         }
928
929         if ((htype == (BM_VERT | BM_EDGE | BM_FACE)) &&
930             (hflag == BM_ELEM_SELECT) &&
931             (respecthide == false) &&
932             (hflag_test == 0))
933         {
934                 /* fast path for deselect all, avoid topology loops
935                  * since we know all will be de-selected anyway. */
936
937 #pragma omp parallel for schedule(dynamic) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
938                 for (i = 0; i < 3; i++) {
939                         BMIter iter;
940                         BMElem *ele;
941
942                         ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
943                         for ( ; ele; ele = BM_iter_step(&iter)) {
944                                 BM_elem_flag_disable(ele, BM_ELEM_SELECT);
945                         }
946                 }
947
948                 bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
949         }
950         else {
951                 for (i = 0; i < 3; i++) {
952                         BMIter iter;
953                         BMElem *ele;
954
955                         if (htype & flag_types[i]) {
956                                 ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
957                                 for ( ; ele; ele = BM_iter_step(&iter)) {
958
959                                         if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
960                                                 continue;
961                                         }
962                                         if (hflag_test && !BM_elem_flag_test(ele, hflag_test)) {
963                                                 continue;
964                                         }
965
966                                         if (hflag & BM_ELEM_SELECT) {
967                                                 BM_elem_select_set(bm, ele, false);
968                                         }
969                                         BM_elem_flag_disable(ele, hflag);
970                                 }
971                         }
972                 }
973         }
974 }
975
976 void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag,
977                                     const bool respecthide, const char hflag_test)
978 {
979         const char iter_types[3] = {BM_VERTS_OF_MESH,
980                                     BM_EDGES_OF_MESH,
981                                     BM_FACES_OF_MESH};
982
983         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
984
985         /* use the nosel version when setting so under no
986          * condition may a hidden face become selected.
987          * Applying other flags to hidden faces is OK. */
988         const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
989
990         BMIter iter;
991         BMElem *ele;
992         int i;
993
994         BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
995
996         if (hflag & BM_ELEM_SELECT) {
997                 BM_select_history_clear(bm);
998         }
999
1000         /* note, better not attempt a fast path for selection as done with de-select
1001          * because hidden geometry and different selection modes can give different results,
1002          * we could of course check for no hidden faces and then use quicker method but its not worth it. */
1003
1004         for (i = 0; i < 3; i++) {
1005                 if (htype & flag_types[i]) {
1006                         ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1007                         for ( ; ele; ele = BM_iter_step(&iter)) {
1008
1009                                 if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
1010                                         continue;
1011                                 }
1012                                 if (hflag_test && !BM_elem_flag_test(ele, hflag_test)) {
1013                                         continue;
1014                                 }
1015
1016                                 if (hflag & BM_ELEM_SELECT) {
1017                                         BM_elem_select_set(bm, ele, true);
1018                                 }
1019                                 BM_elem_flag_enable(ele, hflag_nosel);
1020                         }
1021                 }
1022         }
1023 }
1024
1025 void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag,
1026                                     const bool respecthide)
1027 {
1028         /* call with 0 hflag_test */
1029         BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, 0);
1030 }
1031
1032 void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag,
1033                                    const bool respecthide)
1034 {
1035         /* call with 0 hflag_test */
1036         BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, 0);
1037 }
1038
1039 /***************** Mesh Hiding stuff *********** */
1040
1041 static void vert_flush_hide_set(BMVert *v)
1042 {
1043         BMIter iter;
1044         BMEdge *e;
1045         bool hide = true;
1046
1047         BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
1048                 hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN);
1049         }
1050
1051         BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
1052 }
1053
1054 static void edge_flush_hide(BMEdge *e)
1055 {
1056         BMIter iter;
1057         BMFace *f;
1058         bool hide = true;
1059
1060         BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
1061                 hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN);
1062         }
1063
1064         BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
1065 }
1066
1067 void BM_vert_hide_set(BMVert *v, const bool hide)
1068 {
1069         /* vert hiding: vert + surrounding edges and faces */
1070         BMIter iter, fiter;
1071         BMEdge *e;
1072         BMFace *f;
1073
1074         BLI_assert(v->head.htype == BM_VERT);
1075
1076         BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
1077
1078         BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
1079                 BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
1080
1081                 BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
1082                         BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
1083                 }
1084         }
1085 }
1086
1087 void BM_edge_hide_set(BMEdge *e, const bool hide)
1088 {
1089         BMIter iter;
1090         BMFace *f;
1091         /* BMVert *v; */
1092
1093         BLI_assert(e->head.htype == BM_EDGE);
1094
1095         /* edge hiding: faces around the edge */
1096         BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
1097                 BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
1098         }
1099         
1100         BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
1101
1102         /* hide vertices if necessary */
1103         vert_flush_hide_set(e->v1);
1104         vert_flush_hide_set(e->v2);
1105 }
1106
1107 void BM_face_hide_set(BMFace *f, const bool hide)
1108 {
1109         BMIter iter;
1110         BMLoop *l;
1111
1112         BLI_assert(f->head.htype == BM_FACE);
1113
1114         BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
1115
1116         BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
1117                 edge_flush_hide(l->e);
1118         }
1119
1120         BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
1121                 vert_flush_hide_set(l->v);
1122         }
1123 }
1124
1125 void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide)
1126 {
1127         /* Follow convention of always deselecting before
1128          * hiding an element */
1129         switch (head->htype) {
1130                 case BM_VERT:
1131                         if (hide) BM_vert_select_set(bm, (BMVert *)head, false);
1132                         BM_vert_hide_set((BMVert *)head, hide);
1133                         break;
1134                 case BM_EDGE:
1135                         if (hide) BM_edge_select_set(bm, (BMEdge *)head, false);
1136                         BM_edge_hide_set((BMEdge *)head, hide);
1137                         break;
1138                 case BM_FACE:
1139                         if (hide) BM_face_select_set(bm, (BMFace *)head, false);
1140                         BM_face_hide_set((BMFace *)head, hide);
1141                         break;
1142                 default:
1143                         BMESH_ASSERT(0);
1144                         break;
1145         }
1146 }