replace BLI_array_growone() with BLI_array_growitems() when the size of the increase...
[blender.git] / source / blender / bmesh / intern / bmesh_construct.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  * about this.  
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2007 Blender Foundation.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): Geoffrey Bantle.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file blender/bmesh/intern/bmesh_construct.c
30  *  \ingroup bmesh
31  *
32  * BM construction functions.
33  */
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BKE_customdata.h" 
38 #include "BKE_utildefines.h"
39
40 #include "BLI_array.h"
41 #include "BLI_utildefines.h"
42
43 #include "DNA_meshdata_types.h"
44 #include "DNA_mesh_types.h"
45
46 #include "BLI_math.h"
47 #include "BLI_utildefines.h"
48
49 #include "bmesh.h"
50 #include "bmesh_private.h"
51
52 #include <math.h>
53 #include <stdio.h>
54 #include <string.h>
55
56 #define SELECT 1
57
58 /*prototypes*/
59 static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh,
60                                     const BMLoop *source_loop, BMLoop *target_loop);
61 #if 0
62
63 /*
64  * BM_CONSTRUCT.C
65  *
66  * This file contains functions for making and destroying
67  * individual elements like verts, edges and faces.
68  *
69 */
70
71 /*
72  * BMESH MAKE VERT
73  *
74  * Creates a new vertex and returns a pointer
75  * to it. If a pointer to an example vertex is
76  * passed in, it's custom data and properties
77  * will be copied to the new vertex.
78  *
79 */
80
81 BMVert *BM_Make_Vert(BMesh *bm, float co[3], BMVert *example)
82 {
83         BMVert *v = NULL;
84         v = bmesh_mv(bm, co);
85         if(example)
86                 CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->head.data, &v->head.data);
87         return v;
88 }
89
90 /*
91  * BMESH MAKE EDGE
92  *
93  * Creates a new edge betweeen two vertices and returns a
94  * pointer to it. If 'nodouble' equals 1, then a check is
95  * is done to make sure that an edge between those two vertices
96  * does not already exist. If it does, that edge is returned instead
97  * of creating a new one.
98  *
99  * If a new edge is created, and a pointer to an example edge is
100  * provided, it's custom data and properties will be copied to the
101  * new edge.
102  *
103 */
104
105 BMEdge *BM_Make_Edge(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge *example, int nodouble)
106 {
107         BMEdge *e = NULL;
108         
109         if(nodouble) /*test if edge already exists.*/
110                 e = BM_Edge_Exist(v1, v2);
111
112         if(!e) {
113                 e = bmesh_me(bm, v1, v2);
114
115                 if(example)
116                         CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->head.data, &e->head.data);
117         }
118         
119         return e;
120         
121 }
122 #endif
123
124 /*
125  * BMESH MAKE QUADTRIANGLE
126  *
127  * Creates a new quad or triangle from
128  * a list of 3 or 4 vertices. If nodouble
129  * equals 1, then a check is done to see
130  * if a face with these vertices already
131  * exists and returns it instead. If a pointer
132  * to an example face is provided, it's custom
133  * data and properties will be copied to the new
134  * face.
135  *
136  * Note that the winding of the face is determined
137  * by the order of the vertices in the vertex array
138  *
139 */
140
141 BMFace *BM_Make_Face_QuadTri(BMesh *bm,
142                              BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
143                              const BMFace *example, const int nodouble)
144 {
145         BMVert *vtar[4]= {v1, v2, v3, v4};
146         return BM_Make_Face_QuadTri_v(bm, vtar, v4 ? 4 : 3, example, nodouble);
147 }
148
149 /*remove the edge array bits from this. Its not really needed?*/
150 BMFace *BM_Make_Face_QuadTri_v(BMesh *bm, BMVert **verts, int len, const BMFace *example, const int nodouble)
151 {
152         BMEdge *edar[4]= {NULL};
153         BMFace *f = NULL;
154         int overlap = 0;
155
156         edar[0] = BM_Edge_Exist(verts[0], verts[1]);
157         edar[1] = BM_Edge_Exist(verts[1], verts[2]);
158         if(len == 4) {
159                 edar[2] = BM_Edge_Exist(verts[2], verts[3]);
160                 edar[3] = BM_Edge_Exist(verts[3], verts[0]);
161         }
162         else {
163                 edar[2] = BM_Edge_Exist(verts[2], verts[0]);
164         }
165
166         if(nodouble) {
167                 /*check if face exists or overlaps*/
168                 if(len == 4) {
169                         overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f);
170                 }
171                 else {
172                         overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f);
173                 }
174         }
175
176         /*make new face*/
177         if((!f) && (!overlap)) {
178                 if(!edar[0]) edar[0] = BM_Make_Edge(bm, verts[0], verts[1], NULL, 0);
179                 if(!edar[1]) edar[1] = BM_Make_Edge(bm, verts[1], verts[2], NULL, 0);
180                 if(len == 4) {
181                         if(!edar[2]) edar[2] = BM_Make_Edge(bm, verts[2], verts[3], NULL, 0);
182                         if(!edar[3]) edar[3] = BM_Make_Edge(bm, verts[3], verts[0], NULL, 0);
183                 } else {
184                         if(!edar[2]) edar[2] = BM_Make_Edge(bm, verts[2], verts[0], NULL, 0);
185                 }
186         
187                 f = BM_Make_Face(bm, verts, edar, len, 0);
188         
189                 if(example && f)
190                         BM_Copy_Attributes(bm, bm, example, f);
191
192         }
193
194         return f;
195 }
196
197
198 /*copies face data from shared adjacent faces*/
199 void BM_Face_CopyShared(BMesh *bm, BMFace *f)
200 {
201         BMIter iter;
202         BMLoop *l, *l2;
203
204         if (!f) return;
205
206         l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
207         for (; l; l=BMIter_Step(&iter)) {
208                 l2 = l->radial_next;
209                 
210                 if (l2 && l2 != l) {
211                         if (l2->v == l->v) {
212                                 bm_copy_loop_attributes(bm, bm, l2, l);
213                         } else {
214                                 l2 = l2->next;
215                                 bm_copy_loop_attributes(bm, bm, l2, l);
216                         }
217                 }
218         }
219 }
220
221 /*
222  * BMESH MAKE NGON
223  *
224  * Attempts to make a new Ngon from a list of edges.
225  * If nodouble equals one, a check for overlaps or existing
226  *
227  * The edges are not required to be ordered, simply to to form
228  * a single closed loop as a whole
229  *
230  * Note that while this function will work fine when the edges
231  * are already sorted, if the edges are always going to be sorted,
232  * BM_Make_Face should be considered over this function as it
233  * avoids some unnecessary work.
234 */
235 BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble)
236 {
237         BMEdge **edges2 = NULL;
238         BLI_array_staticdeclare(edges2, BM_NGON_STACK_SIZE);
239         BMVert **verts = NULL, *v;
240         BLI_array_staticdeclare(verts, BM_NGON_STACK_SIZE);
241         BMFace *f = NULL;
242         BMEdge *e;
243         BMVert *ev1, *ev2;
244         int i, /* j,*/ v1found, reverse;
245
246         /*this code is hideous, yeek.  I'll have to think about ways of
247           cleaning it up.  basically, it now combines the old BM_Make_Ngon
248           *and* the old bmesh_mf functions, so its kindof smashed together
249                 - joeedh*/
250
251         if (!len || !v1 || !v2 || !edges || !bm)
252                 return NULL;
253
254         /*put edges in correct order*/
255         for (i=0; i<len; i++) {
256                 bmesh_api_setflag(edges[i], _FLAG_MF);
257         }
258
259         ev1 = edges[0]->v1;
260         ev2 = edges[0]->v2;
261
262         if (v1 == ev2) {
263                 /* Swapping here improves performance and consistency of face
264                    structure in the special case that the edges are already in
265                    the correct order and winding */
266                 SWAP(BMVert *, ev1, ev2);
267         }
268
269         BLI_array_append(verts, ev1);
270         v = ev2;
271         e = edges[0];
272         do {
273                 BMEdge *e2 = e;
274
275                 BLI_array_append(verts, v);
276                 BLI_array_append(edges2, e);
277
278                 do {
279                         e2 = bmesh_disk_nextedge(e2, v);
280                         if (e2 != e && bmesh_api_getflag(e2, _FLAG_MF)) {
281                                 v = BM_OtherEdgeVert(e2, v);
282                                 break;
283                         }
284                 } while (e2 != e);
285
286                 if (e2 == e)
287                         goto err; /*the edges do not form a closed loop*/
288
289                 e = e2;
290         } while (e != edges[0]);
291
292         if (BLI_array_count(edges2) != len)
293                 goto err; /*we didn't use all edges in forming the boundary loop*/
294
295         /*ok, edges are in correct order, now ensure they are going
296           in the correct direction*/
297         v1found = reverse = 0;
298         for (i=0; i<len; i++) {
299                 if (BM_Vert_In_Edge(edges2[i], v1)) {
300                         /*see if v1 and v2 are in the same edge*/
301                         if (BM_Vert_In_Edge(edges2[i], v2)) {
302                                 /*if v1 is shared by the *next* edge, then the winding
303                                   is incorrect*/
304                                 if (BM_Vert_In_Edge(edges2[(i+1)%len], v1)) {
305                                         reverse = 1;
306                                         break;
307                                 }
308                         }
309
310                         v1found = 1;
311                 }
312
313                 if (!v1found && BM_Vert_In_Edge(edges2[i], v2)) {
314                         reverse = 1;
315                         break;
316                 }
317         }
318
319         if (reverse) {
320                 for (i=0; i<len/2; i++) {
321                         v = verts[i];
322                         verts[i] = verts[len-i-1];
323                         verts[len-i-1] = v;
324                 }
325         }
326
327         for (i=0; i<len; i++) {
328                 edges2[i] = BM_Edge_Exist(verts[i], verts[(i+1)%len]);
329                 if (!edges2[i])
330                         goto err;
331         }
332
333         f = BM_Make_Face(bm, verts, edges2, len, nodouble);
334
335         /*clean up flags*/
336         for (i=0; i<len; i++) {
337                 bmesh_api_clearflag(edges2[i], _FLAG_MF);
338         }
339
340         BLI_array_free(verts);
341         BLI_array_free(edges2);
342
343         return f;
344
345 err:
346         for (i=0; i<len; i++) {
347                 bmesh_api_clearflag(edges[i], _FLAG_MF);
348         }
349
350         BLI_array_free(verts);
351         BLI_array_free(edges2);
352
353         return NULL;
354 }
355
356
357 /*bmesh_make_face_from_face(BMesh *bm, BMFace *source, BMFace *target) */
358
359
360 /*
361  * REMOVE TAGGED XXX
362  *
363  * Called by operators to remove elements that they have marked for
364  * removal.
365  *
366 */
367
368 void BM_remove_tagged_faces(BMesh *bm, int flag)
369 {
370         BMFace *f;
371         BMIter iter;
372
373         BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
374                 if(BMO_TestFlag(bm, f, flag)) BM_Kill_Face(bm, f);
375         }
376 }
377
378 void BM_remove_tagged_edges(BMesh *bm, int flag)
379 {
380         BMEdge *e;
381         BMIter iter;
382
383         BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
384                 if(BMO_TestFlag(bm, e, flag)) BM_Kill_Edge(bm, e);
385         }
386 }
387
388 void BM_remove_tagged_verts(BMesh *bm, int flag)
389 {
390         BMVert *v;
391         BMIter iter;
392
393         BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
394                 if(BMO_TestFlag(bm, v, flag)) BM_Kill_Vert(bm, v);
395         }
396 }
397
398 static void bm_copy_vert_attributes(BMesh *source_mesh, BMesh *target_mesh, const BMVert *source_vertex, BMVert *target_vertex)
399 {
400         if ((source_mesh == target_mesh) && (source_vertex == target_vertex)) {
401                 return;
402         }
403         copy_v3_v3(target_vertex->no, source_vertex->no);
404         CustomData_bmesh_free_block(&target_mesh->vdata, &target_vertex->head.data);
405         CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->head.data, &target_vertex->head.data);      
406 }
407
408 static void bm_copy_edge_attributes(BMesh *source_mesh, BMesh *target_mesh, const BMEdge *source_edge, BMEdge *target_edge)
409 {
410         if ((source_mesh == target_mesh) && (source_edge == target_edge)) {
411                 return;
412         }
413         CustomData_bmesh_free_block(&target_mesh->edata, &target_edge->head.data);
414         CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->head.data, &target_edge->head.data);
415 }
416
417 static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh, const BMLoop *source_loop, BMLoop *target_loop)
418 {
419         if ((source_mesh == target_mesh) && (source_loop == target_loop)) {
420                 return;
421         }
422         CustomData_bmesh_free_block(&target_mesh->ldata, &target_loop->head.data);
423         CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->head.data, &target_loop->head.data);
424 }
425
426 static void bm_copy_face_attributes(BMesh *source_mesh, BMesh *target_mesh, const BMFace *source_face, BMFace *target_face)
427 {
428         if ((source_mesh == target_mesh) && (source_face == target_face)) {
429                 return;
430         }
431         copy_v3_v3(target_face->no, source_face->no);
432         CustomData_bmesh_free_block(&target_mesh->pdata, &target_face->head.data);
433         CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->head.data, &target_face->head.data);  
434         target_face->mat_nr = source_face->mat_nr;
435 }
436
437 /*BMESH_TODO: Special handling for hide flags?*/
438
439 void BM_Copy_Attributes(BMesh *source_mesh, BMesh *target_mesh, const void *source, void *target)
440 {
441         const BMHeader *sheader = source;
442         BMHeader *theader = target;
443         
444         if(sheader->htype != theader->htype)
445                 return;
446
447         /*First we copy select*/
448         if(BM_Selected(source_mesh, source)) BM_Select(target_mesh, target, TRUE);
449         
450         /*Now we copy flags*/
451         theader->hflag = sheader->hflag;
452         
453         /*Copy specific attributes*/
454         if(theader->htype == BM_VERT)
455                 bm_copy_vert_attributes(source_mesh, target_mesh, (const BMVert*)source, (BMVert*)target);
456         else if(theader->htype == BM_EDGE)
457                 bm_copy_edge_attributes(source_mesh, target_mesh, (const BMEdge*)source, (BMEdge*)target);
458         else if(theader->htype == BM_LOOP)
459                 bm_copy_loop_attributes(source_mesh, target_mesh, (const BMLoop*)source, (BMLoop*)target);
460         else if(theader->htype == BM_FACE)
461                 bm_copy_face_attributes(source_mesh, target_mesh, (const BMFace*)source, (BMFace*)target);
462 }
463
464 BMesh *BM_Copy_Mesh(BMesh *bmold)
465 {
466         BMesh *bm;
467         BMVert *v, *v2, **vtable = NULL;
468         BMEdge *e, *e2, **edges = NULL, **etable = NULL;
469         BLI_array_declare(edges);
470         BMLoop *l, /* *l2,*/ **loops = NULL;
471         BLI_array_declare(loops);
472         BMFace *f, *f2, **ftable = NULL;
473         BMEditSelection *ese;
474         BMIter iter, liter;
475         int allocsize[4] = {512,512,2048,512};
476         int i, j;
477
478         /*allocate a bmesh*/
479         bm = BM_Make_Mesh(bmold->ob, allocsize);
480
481         CustomData_copy(&bmold->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
482         CustomData_copy(&bmold->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
483         CustomData_copy(&bmold->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
484         CustomData_copy(&bmold->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
485
486         CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
487         CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
488         CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
489         CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
490
491         vtable= MEM_mallocN(sizeof(BMVert *) * bmold->totvert, "BM_Copy_Mesh vtable");
492         etable= MEM_mallocN(sizeof(BMEdge *) * bmold->totedge, "BM_Copy_Mesh etable");
493         ftable= MEM_mallocN(sizeof(BMFace *) * bmold->totface, "BM_Copy_Mesh ftable");
494
495         v = BMIter_New(&iter, bmold, BM_VERTS_OF_MESH, NULL);
496         for (i=0; v; v=BMIter_Step(&iter), i++) {
497                 v2 = BM_Make_Vert(bm, v->co, NULL); /* copy between meshes so cant use 'example' argument */
498                 BM_Copy_Attributes(bmold, bm, v, v2);
499                 vtable[i] = v2;
500                 BM_SetIndex(v, i); /* set_inline */
501                 BM_SetIndex(v2, i); /* set_inline */
502         }
503         bmold->elem_index_dirty &= ~BM_VERT;
504         bm->elem_index_dirty &= ~BM_VERT;
505
506         /* safety check */
507         BLI_assert(i == bmold->totvert);
508         
509         e = BMIter_New(&iter, bmold, BM_EDGES_OF_MESH, NULL);
510         for (i=0; e; e=BMIter_Step(&iter), i++) {
511                 e2 = BM_Make_Edge(bm, vtable[BM_GetIndex(e->v1)],
512                                   vtable[BM_GetIndex(e->v2)], e, 0);
513
514                 BM_Copy_Attributes(bmold, bm, e, e2);
515                 etable[i] = e2;
516                 BM_SetIndex(e, i); /* set_inline */
517                 BM_SetIndex(e2, i); /* set_inline */
518         }
519         bmold->elem_index_dirty &= ~BM_EDGE;
520         bm->elem_index_dirty &= ~BM_EDGE;
521
522         /* safety check */
523         BLI_assert(i == bmold->totedge);
524         
525         f = BMIter_New(&iter, bmold, BM_FACES_OF_MESH, NULL);
526         for (i=0; f; f=BMIter_Step(&iter), i++) {
527                 BM_SetIndex(f, i); /* set_inline */
528
529                 BLI_array_empty(loops);
530                 BLI_array_empty(edges);
531                 BLI_array_growitems(loops, f->len);
532                 BLI_array_growitems(edges, f->len);
533
534                 l = BMIter_New(&liter, bmold, BM_LOOPS_OF_FACE, f);
535                 for (j=0; j<f->len; j++, l = BMIter_Step(&liter)) {
536                         loops[j] = l;
537                         edges[j] = etable[BM_GetIndex(l->e)];
538                 }
539
540                 v = vtable[BM_GetIndex(loops[0]->v)];
541                 v2 = vtable[BM_GetIndex(loops[1]->v)];
542
543                 if (!bmesh_verts_in_edge(v, v2, edges[0])) {
544                         v = vtable[BM_GetIndex(loops[BLI_array_count(loops)-1]->v)];
545                         v2 = vtable[BM_GetIndex(loops[0]->v)];
546                 }
547
548                 f2 = BM_Make_Ngon(bm, v, v2, edges, f->len, 0);
549                 if (!f2)
550                         continue;
551                 /* use totface incase adding some faces fails */
552                 BM_SetIndex(f2, (bm->totface-1)); /* set_inline */
553
554                 ftable[i] = f2;
555
556                 BM_Copy_Attributes(bmold, bm, f, f2);
557                 copy_v3_v3(f2->no, f->no);
558
559                 l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f2);
560                 for (j=0; j<f->len; j++, l = BMIter_Step(&liter)) {
561                         BM_Copy_Attributes(bmold, bm, loops[j], l);
562                 }
563
564                 if (f == bmold->act_face) bm->act_face = f2;
565         }
566         bmold->elem_index_dirty &= ~BM_FACE;
567         bm->elem_index_dirty &= ~BM_FACE;
568
569         /* safety check */
570         BLI_assert(i == bmold->totface);
571
572         /*copy over edit selection history*/
573         for (ese=bmold->selected.first; ese; ese=ese->next) {
574                 void *ele = NULL;
575
576                 if (ese->htype == BM_VERT)
577                         ele= vtable[BM_GetIndex(ese->data)];
578                 else if (ese->htype == BM_EDGE)
579                         ele= etable[BM_GetIndex(ese->data)];
580                 else if (ese->htype == BM_FACE) {
581                         ele= ftable[BM_GetIndex(ese->data)];
582                 }
583                 else {
584                         BLI_assert(0);
585                 }
586                 
587                 if (ele)
588                         BM_store_selection(bm, ele);
589         }
590
591         MEM_freeN(etable);
592         MEM_freeN(vtable);
593         MEM_freeN(ftable);
594
595         BLI_array_free(loops);
596         BLI_array_free(edges);
597
598         return bm;
599 }
600
601 /* ME -> BM */
602 char BM_Vert_Flag_From_MEFlag(const char  meflag)
603 {
604     return ( ((meflag & SELECT)       ? BM_SELECT : 0) |
605              ((meflag & ME_HIDE)      ? BM_HIDDEN : 0)
606              );
607 }
608 char BM_Edge_Flag_From_MEFlag(const short meflag)
609 {
610         return ( ((meflag & SELECT)       ? BM_SELECT : 0) |
611                  ((meflag & ME_SEAM)      ? BM_SEAM   : 0) |
612                  ((meflag & ME_SHARP)     ? BM_SHARP  : 0) |
613                  ((meflag & ME_HIDE)      ? BM_HIDDEN : 0)
614                  );
615 }
616 char BM_Face_Flag_From_MEFlag(const char  meflag)
617 {
618     return ( ((meflag & ME_FACE_SEL)  ? BM_SELECT : 0) |
619              ((meflag & ME_SMOOTH)    ? BM_SMOOTH : 0) |
620              ((meflag & ME_HIDE)      ? BM_HIDDEN : 0)
621              );
622 }
623
624 /* BM -> ME */
625 char  BM_Vert_Flag_To_MEFlag(BMVert *eve)
626 {
627     const char hflag= eve->head.hflag;
628
629     return ( ((hflag & BM_SELECT)  ? SELECT  : 0) |
630              ((hflag & BM_HIDDEN)  ? ME_HIDE : 0)
631              );
632 }
633 short BM_Edge_Flag_To_MEFlag(BMEdge *eed)
634 {
635         const char hflag= eed->head.hflag;
636
637         return ( ((hflag & BM_SELECT)       ? SELECT    : 0) |
638                  ((hflag & BM_SEAM)         ? ME_SEAM   : 0) |
639                  ((hflag & BM_SHARP)        ? ME_SHARP  : 0) |
640                  ((hflag & BM_HIDDEN)       ? ME_HIDE   : 0) |
641                  ((BM_Wire_Edge(NULL, eed)) ? ME_LOOSEEDGE : 0) | /* not typical */
642                  (ME_EDGEDRAW | ME_EDGERENDER)
643                  );
644 }
645 char  BM_Face_Flag_To_MEFlag(BMFace *efa)
646 {
647     const char hflag= efa->head.hflag;
648
649     return ( ((hflag & BM_SELECT) ? ME_FACE_SEL : 0) |
650              ((hflag & BM_SMOOTH) ? ME_SMOOTH   : 0) |
651              ((hflag & BM_HIDDEN) ? ME_HIDE     : 0)
652              );
653 }
654
655 /* unused, type spesific functions below */
656 #if 0
657 /*
658   BM FLAGS TO ME FLAGS
659
660   Returns the flags stored in element,
661   which much be either a BMVert, BMEdge,
662   or BMFace, converted to mesh flags.
663 */
664 short BMFlags_To_MEFlags(void *element)
665 {
666         const char src_htype= ((BMHeader *)element)->htype;
667
668         if (src_htype == BM_FACE) {
669                 return BM_Face_Flag_To_MEFlag(element);
670         }
671         else if (src_htype == BM_EDGE) {
672                 return BM_Edge_Flag_To_MEFlag(element);
673         }
674         else if (src_htype == BM_VERT) {
675                 return BM_Vert_Flag_To_MEFlag(element);
676         }
677         else {
678                 return 0;
679         }
680 }
681
682 /*
683   BM FLAGS TO ME FLAGS
684
685   Returns the flags stored in element,
686   which much be either a MVert, MEdge,
687   or MPoly, converted to mesh flags.
688   type must be either BM_VERT, BM_EDGE,
689   or BM_FACE.
690 */
691 char MEFlags_To_BMFlags(const short hflag, const char htype)
692 {
693         if (htype == BM_FACE) {
694                 return BM_Face_Flag_From_MEFlag(hflag);
695         }
696         else if (htype == BM_EDGE) {
697                 return BM_Edge_Flag_From_MEFlag(hflag);
698         }
699         else if (htype == BM_VERT) {
700                 return BM_Vert_Flag_From_MEFlag(hflag);
701         }
702         else {
703                 return 0;
704         }
705 }
706 #endif