code cleanup: change C naming convention (so py and C api match), eg:
[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, BMHeader *head, int select)
500 {
501         switch (head->htype) {
502                 case BM_VERT:
503                         BM_vert_select_set(bm, (BMVert *)head, select);
504                         break;
505                 case BM_EDGE:
506                         BM_edge_select_set(bm, (BMEdge *)head, select);
507                         break;
508                 case BM_FACE:
509                         BM_face_select_set(bm, (BMFace *)head, 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(float r_center[3], BMEditSelection *ese)
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(float r_normal[3], BMEditSelection *ese)
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 /* ref - editmesh_lib.cL:EM_editselection_plane() */
616
617 /* Calculate a plane that is rightangles to the edge/vert/faces normal
618  * also make the plane run along an axis that is related to the geometry,
619  * because this is used for the manipulators Y axis. */
620 void BM_editselection_plane(BMesh *bm, float r_plane[3], BMEditSelection *ese)
621 {
622         if (ese->htype == BM_VERT) {
623                 BMVert *eve = (BMVert *)ese->ele;
624                 float vec[3] = {0.0f, 0.0f, 0.0f};
625                 
626                 if (ese->prev) { /* use previously selected data to make a useful vertex plane */
627                         BM_editselection_center(vec, ese->prev);
628                         sub_v3_v3v3(r_plane, vec, eve->co);
629                 }
630                 else {
631                         /* make a fake  plane thats at rightangles to the normal
632                          * we cant make a crossvec from a vec thats the same as the vec
633                          * unlikely but possible, so make sure if the normal is (0, 0, 1)
634                          * that vec isn't the same or in the same direction even. */
635                         if      (eve->no[0] < 0.5f) vec[0] = 1.0f;
636                         else if (eve->no[1] < 0.5f) vec[1] = 1.0f;
637                         else                        vec[2] = 1.0f;
638                         cross_v3_v3v3(r_plane, eve->no, vec);
639                 }
640         }
641         else if (ese->htype == BM_EDGE) {
642                 BMEdge *eed = (BMEdge *)ese->ele;
643
644                 /* the plane is simple, it runs along the edge
645                  * however selecting different edges can swap the direction of the y axis.
646                  * this makes it less likely for the y axis of the manipulator
647                  * (running along the edge).. to flip less often.
648                  * at least its more predictable */
649                 if (eed->v2->co[1] > eed->v1->co[1]) {  /* check which to do first */
650                         sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co);
651                 }
652                 else {
653                         sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
654                 }
655                 
656         }
657         else if (ese->htype == BM_FACE) {
658                 BMFace *efa = (BMFace *)ese->ele;
659                 float vec[3] = {0.0f, 0.0f, 0.0f};
660                 
661                 /* for now, use face normal */
662
663                 /* make a fake plane thats at rightangles to the normal
664                  * we cant make a crossvec from a vec thats the same as the vec
665                  * unlikely but possible, so make sure if the normal is (0, 0, 1)
666                  * that vec isn't the same or in the same direction even. */
667                 if (efa->len < 3) {
668                         /* crappy fallback method */
669                         if      (efa->no[0] < 0.5f)     vec[0] = 1.0f;
670                         else if (efa->no[1] < 0.5f)     vec[1] = 1.0f;
671                         else                        vec[2] = 1.0f;
672                         cross_v3_v3v3(r_plane, efa->no, vec);
673                 }
674                 else {
675                         BMVert *verts[4] = {NULL};
676
677                         BM_iter_as_array(bm, BM_VERTS_OF_FACE, efa, (void **)verts, 4);
678
679                         if (efa->len == 4) {
680                                 float vecA[3], vecB[3];
681                                 sub_v3_v3v3(vecA, verts[3]->co, verts[2]->co);
682                                 sub_v3_v3v3(vecB, verts[0]->co, verts[1]->co);
683                                 add_v3_v3v3(r_plane, vecA, vecB);
684
685                                 sub_v3_v3v3(vecA, verts[0]->co, verts[3]->co);
686                                 sub_v3_v3v3(vecB, verts[1]->co, verts[2]->co);
687                                 add_v3_v3v3(vec, vecA, vecB);
688                                 /* use the biggest edge length */
689                                 if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) {
690                                         copy_v3_v3(r_plane, vec);
691                                 }
692                         }
693                         else {
694                                 /* BMESH_TODO (not urgent, use longest ngon edge for alignment) */
695
696                                 /* start with v1-2 */
697                                 sub_v3_v3v3(r_plane, verts[0]->co, verts[1]->co);
698
699                                 /* test the edge between v2-3, use if longer */
700                                 sub_v3_v3v3(vec, verts[1]->co, verts[2]->co);
701                                 if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec))
702                                         copy_v3_v3(r_plane, vec);
703
704                                 /* test the edge between v1-3, use if longer */
705                                 sub_v3_v3v3(vec, verts[2]->co, verts[0]->co);
706                                 if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) {
707                                         copy_v3_v3(r_plane, vec);
708                                 }
709                         }
710
711                 }
712         }
713         normalize_v3(r_plane);
714 }
715
716 int BM_select_history_check(BMesh *bm, const BMElem *ele)
717 {
718         BMEditSelection *ese;
719         
720         for (ese = bm->selected.first; ese; ese = ese->next) {
721                 if (ese->ele == ele) {
722                         return TRUE;
723                 }
724         }
725         
726         return FALSE;
727 }
728
729 int BM_select_history_remove(BMesh *bm, BMElem *ele)
730 {
731         BMEditSelection *ese;
732         for (ese = bm->selected.first; ese; ese = ese->next) {
733                 if (ese->ele == ele) {
734                         BLI_freelinkN(&(bm->selected), ese);
735                         return TRUE;
736                 }
737         }
738
739         return FALSE;
740 }
741
742 void BM_select_history_clear(BMesh *bm)
743 {
744         BLI_freelistN(&bm->selected);
745         bm->selected.first = bm->selected.last = NULL;
746 }
747
748 void BM_select_history_store_notest(BMesh *bm, BMElem *ele)
749 {
750         BMEditSelection *ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection");
751         ese->htype = ((BMHeader *)ele)->htype;
752         ese->ele = ele;
753         BLI_addtail(&(bm->selected), ese);
754 }
755
756 void BM_select_history_store(BMesh *bm, BMElem *ele)
757 {
758         if (!BM_select_history_check(bm, ele)) {
759                 BM_select_history_store_notest(bm, ele);
760         }
761 }
762
763 void BM_select_history_validate(BMesh *bm)
764 {
765         BMEditSelection *ese, *nextese;
766
767         ese = bm->selected.first;
768
769         while (ese) {
770                 nextese = ese->next;
771                 if (!BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
772                         BLI_freelinkN(&(bm->selected), ese);
773                 }
774                 ese = nextese;
775         }
776 }
777
778 void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hflag,
779                                      int respecthide, const char hflag_test)
780 {
781         const char iter_types[3] = {BM_VERTS_OF_MESH,
782                                     BM_EDGES_OF_MESH,
783                                     BM_FACES_OF_MESH};
784
785         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
786
787         BMIter iter;
788         BMElem *ele;
789         int i;
790
791         if (hflag & BM_ELEM_SELECT) {
792                 BM_select_history_clear(bm);
793         }
794
795         if ((htype == (BM_VERT | BM_EDGE | BM_FACE)) &&
796             (hflag == BM_ELEM_SELECT) &&
797             (respecthide == FALSE) &&
798             (hflag_test == 0))
799         {
800                 /* fast path for deselect all, avoid topology loops
801                  * since we know all will be de-selected anyway. */
802                 for (i = 0; i < 3; i++) {
803                         ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
804                         for ( ; ele; ele = BM_iter_step(&iter)) {
805                                 BM_elem_flag_disable(ele, BM_ELEM_SELECT);
806                         }
807                 }
808                 bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
809         }
810         else {
811                 for (i = 0; i < 3; i++) {
812                         if (htype & flag_types[i]) {
813                                 ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
814                                 for ( ; ele; ele = BM_iter_step(&iter)) {
815
816                                         if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
817                                                 continue;
818                                         }
819                                         if (hflag_test && !BM_elem_flag_test(ele, hflag_test)) {
820                                                 continue;
821                                         }
822
823                                         if (hflag & BM_ELEM_SELECT) {
824                                                 BM_elem_select_set(bm, ele, FALSE);
825                                         }
826                                         BM_elem_flag_disable(ele, hflag);
827                                 }
828                         }
829                 }
830         }
831 }
832
833 void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag,
834                                     int respecthide, const char hflag_test)
835 {
836         const char iter_types[3] = {BM_VERTS_OF_MESH,
837                                     BM_EDGES_OF_MESH,
838                                     BM_FACES_OF_MESH};
839
840         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
841
842         /* use the nosel version when setting so under no
843          * condition may a hidden face become selected.
844          * Applying other flags to hidden faces is OK. */
845         const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
846
847         BMIter iter;
848         BMElem *ele;
849         int i;
850
851         if (hflag & BM_ELEM_SELECT) {
852                 BM_select_history_clear(bm);
853         }
854
855         /* note, better not attempt a fast path for selection as done with de-select
856          * because hidden geometry and different selection modes can give different results,
857          * we could of course check for no hiddent faces and then use quicker method but its not worth it. */
858
859         for (i = 0; i < 3; i++) {
860                 if (htype & flag_types[i]) {
861                         ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
862                         for ( ; ele; ele = BM_iter_step(&iter)) {
863
864                                 if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
865                                         continue;
866                                 }
867                                 if (hflag_test && !BM_elem_flag_test(ele, hflag_test)) {
868                                         continue;
869                                 }
870
871                                 if (hflag & BM_ELEM_SELECT) {
872                                         BM_elem_select_set(bm, ele, TRUE);
873                                 }
874                                 BM_elem_flag_enable(ele, hflag_nosel);
875                         }
876                 }
877         }
878 }
879
880 void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag,
881                                     int respecthide)
882 {
883         /* call with 0 hflag_test */
884         BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, 0);
885 }
886
887 void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag,
888                                    int respecthide)
889 {
890         /* call with 0 hflag_test */
891         BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, 0);
892 }
893
894 /***************** Mesh Hiding stuff *********** */
895
896 static void vert_flush_hide_set(BMVert *v)
897 {
898         BMIter iter;
899         BMEdge *e;
900         int hide = TRUE;
901
902         BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
903                 hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN);
904         }
905
906         BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
907 }
908
909 static void edge_flush_hide(BMEdge *e)
910 {
911         BMIter iter;
912         BMFace *f;
913         int hide = TRUE;
914
915         BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
916                 hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN);
917         }
918
919         BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
920 }
921
922 void BM_vert_hide_set(BMVert *v, int hide)
923 {
924         /* vert hiding: vert + surrounding edges and faces */
925         BMIter iter, fiter;
926         BMEdge *e;
927         BMFace *f;
928
929         BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
930
931         BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
932                 BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
933
934                 BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
935                         BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
936                 }
937         }
938 }
939
940 void BM_edge_hide_set(BMEdge *e, int hide)
941 {
942         BMIter iter;
943         BMFace *f;
944         /* BMVert *v; */
945
946         /* edge hiding: faces around the edge */
947         BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
948                 BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
949         }
950         
951         BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
952
953         /* hide vertices if necessary */
954         vert_flush_hide_set(e->v1);
955         vert_flush_hide_set(e->v2);
956 }
957
958 void BM_face_hide_set(BMFace *f, int hide)
959 {
960         BMIter iter;
961         BMLoop *l;
962
963         BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
964
965         BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
966                 edge_flush_hide(l->e);
967         }
968
969         BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
970                 vert_flush_hide_set(l->v);
971         }
972 }
973
974 void _bm_elem_hide_set(BMesh *bm, BMHeader *head, int hide)
975 {
976         /* Follow convention of always deselecting before
977          * hiding an element */
978         switch (head->htype) {
979                 case BM_VERT:
980                         if (hide) BM_vert_select_set(bm, (BMVert *)head, FALSE);
981                         BM_vert_hide_set((BMVert *)head, hide);
982                         break;
983                 case BM_EDGE:
984                         if (hide) BM_edge_select_set(bm, (BMEdge *)head, FALSE);
985                         BM_edge_hide_set((BMEdge *)head, hide);
986                         break;
987                 case BM_FACE:
988                         if (hide) BM_face_select_set(bm, (BMFace *)head, FALSE);
989                         BM_face_hide_set((BMFace *)head, hide);
990                         break;
991                 default:
992                         BMESH_ASSERT(0);
993                         break;
994         }
995 }