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