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