remove $Id: tags after discussion on the mailign list: http://markmail.org/message...
[blender.git] / source / blender / blenkernel / intern / BME_conversions.c
1 /*
2  * BME_mesh.c    jan 2007
3  *
4  *      BMesh mesh level functions.
5  *
6  *
7  * ***** BEGIN GPL LICENSE BLOCK *****
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  * about this.  
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  * The Original Code is Copyright (C) 2007 Blender Foundation.
25  * All rights reserved.
26  *
27  * The Original Code is: all of this file.
28  *
29  * Contributor(s): Geoffrey Bantle, Levi Schooley.
30  *
31  * ***** END GPL LICENSE BLOCK *****
32  */
33
34 /** \file blender/blenkernel/intern/BME_conversions.c
35  *  \ingroup bke
36  */
37
38
39 #include "MEM_guardedalloc.h"
40
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44
45 #include "BLI_edgehash.h"
46 #include "BLI_listbase.h"
47 #include "BLI_utildefines.h"
48
49 #include "BKE_mesh.h"
50 #include "BKE_cdderivedmesh.h"
51
52 //XXX #include "BIF_editmesh.h"
53 //XXX #include "editmesh.h"
54 #include "bmesh_private.h"
55
56 //XXX #include "BSE_edit.h"
57
58 /* XXX IMPORTANT: editmesh stuff doesn't belong in kernel! (ton) */
59
60 /*merge these functions*/
61 static void BME_DMcorners_to_loops(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f, int numCol, int numTex){
62         int i, j;
63         BME_Loop *l;
64         MTFace *texface;
65         MTexPoly *texpoly;
66         MCol *mcol;
67         MLoopCol *mloopcol;
68         MLoopUV *mloopuv;
69
70         for(i=0; i< numTex; i++){
71                 texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
72                 texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
73
74                 texpoly->tpage = texface[index].tpage;
75                 texpoly->flag = texface[index].flag;
76                 texpoly->transp = texface[index].transp;
77                 texpoly->mode = texface[index].mode;
78                 texpoly->tile = texface[index].tile;
79                 texpoly->unwrap = texface[index].unwrap;
80
81                 j = 0;
82                 l = f->loopbase;
83                 do{
84                         mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
85                         mloopuv->uv[0] = texface[index].uv[j][0];
86                         mloopuv->uv[1] = texface[index].uv[j][1];
87                         j++;
88                         l = l->next;
89                 }while(l!=f->loopbase);
90         }
91
92         for(i=0; i < numCol; i++){
93                 mcol = CustomData_get_layer_n(facedata, CD_MCOL, i);
94                 j = 0;
95                 l = f->loopbase;
96                 do{
97                         mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
98                         mloopcol->r = mcol[(index*4)+j].r;
99                         mloopcol->g = mcol[(index*4)+j].g;
100                         mloopcol->b = mcol[(index*4)+j].b;
101                         mloopcol->a = mcol[(index*4)+j].a;
102                         j++;
103                         l = l->next;
104                 }while(l!=f->loopbase);
105         }
106 }
107
108 static void BME_DMloops_to_corners(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f,int numCol, int numTex){
109         int i, j;
110         BME_Loop *l;
111         MTFace *texface;
112         MTexPoly *texpoly;
113         MCol *mcol;
114         MLoopCol *mloopcol;
115         MLoopUV *mloopuv;
116
117         for(i=0; i < numTex; i++){
118                 texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
119                 texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
120                 
121                 texface[index].tpage = texpoly->tpage;
122                 texface[index].flag = texpoly->flag;
123                 texface[index].transp = texpoly->transp;
124                 texface[index].mode = texpoly->mode;
125                 texface[index].tile = texpoly->tile;
126                 texface[index].unwrap = texpoly->unwrap;
127
128                 j = 0;
129                 l = f->loopbase;
130                 do{
131                         mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
132                         texface[index].uv[j][0] = mloopuv->uv[0];
133                         texface[index].uv[j][1] = mloopuv->uv[1];
134                         j++;
135                         l = l->next;
136                 }while(l!=f->loopbase);
137
138         }
139         for(i=0; i < numCol; i++){
140                 mcol = CustomData_get_layer_n(facedata,CD_MCOL, i);
141                 j = 0;
142                 l = f->loopbase;
143                 do{
144                         mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
145                         mcol[(index*4) + j].r = mloopcol->r;
146                         mcol[(index*4) + j].g = mloopcol->g;
147                         mcol[(index*4) + j].b = mloopcol->b;
148                         mcol[(index*4) + j].a = mloopcol->a;
149                         j++;
150                         l = l->next;
151                 }while(l!=f->loopbase);
152         }
153 }
154
155
156 static void BME_corners_to_loops(BME_Mesh *bm, CustomData *facedata, void *face_block, BME_Poly *f,int numCol, int numTex){
157         int i, j;
158         BME_Loop *l;
159         MTFace *texface;
160         MTexPoly *texpoly;
161         MCol *mcol;
162         MLoopCol *mloopcol;
163         MLoopUV *mloopuv;
164
165         for(i=0; i < numTex; i++){
166                 texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
167                 texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
168                 
169                 texpoly->tpage = texface->tpage;
170                 texpoly->flag = texface->flag;
171                 texpoly->transp = texface->transp;
172                 texpoly->mode = texface->mode;
173                 texpoly->tile = texface->tile;
174                 texpoly->unwrap = texface->unwrap;
175
176                 j = 0;
177                 l = f->loopbase;
178                 do{
179                         mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
180                         mloopuv->uv[0] = texface->uv[j][0];
181                         mloopuv->uv[1] = texface->uv[j][1];
182                         j++;
183                         l = l->next;
184                 }while(l!=f->loopbase);
185
186         }
187         for(i=0; i < numCol; i++){
188                 mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
189                 j = 0;
190                 l = f->loopbase;
191                 do{
192                         mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
193                         mloopcol->r = mcol[j].r;
194                         mloopcol->g = mcol[j].g;
195                         mloopcol->b = mcol[j].b;
196                         mloopcol->a = mcol[j].a;
197                         j++;
198                         l = l->next;
199                 }while(l!=f->loopbase);
200         }
201 }
202
203 static void BME_loops_to_corners(BME_Mesh *bm, CustomData *facedata, void *face_block, BME_Poly *f,int numCol, int numTex){
204         int i, j;
205         BME_Loop *l;
206         MTFace *texface;
207         MTexPoly *texpoly;
208         MCol *mcol;
209         MLoopCol *mloopcol;
210         MLoopUV *mloopuv;
211
212         for(i=0; i < numTex; i++){
213                 texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
214                 texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
215                 
216                 texface->tpage = texpoly->tpage;
217                 texface->flag = texpoly->flag;
218                 texface->transp = texpoly->transp;
219                 texface->mode = texpoly->mode;
220                 texface->tile = texpoly->tile;
221                 texface->unwrap = texpoly->unwrap;
222
223                 j = 0;
224                 l = f->loopbase;
225                 do{
226                         mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
227                         texface->uv[j][0] = mloopuv->uv[0];
228                         texface->uv[j][1] = mloopuv->uv[1];
229                         j++;
230                         l = l->next;
231                 }while(l!=f->loopbase);
232
233         }
234         for(i=0; i < numCol; i++){
235                 mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
236                 j = 0;
237                 l = f->loopbase;
238                 do{
239                         mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
240                         mcol[j].r = mloopcol->r;
241                         mcol[j].g = mloopcol->g;
242                         mcol[j].b = mloopcol->b;
243                         mcol[j].a = mloopcol->a;
244                         j++;
245                         l = l->next;
246                 }while(l!=f->loopbase);
247         }
248 }
249 /*move the EditMesh conversion functions to editmesh_tools.c*/
250 BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) {
251         BME_Mesh *bm;
252         int allocsize[4] = {512,512,2048,512}, numTex, numCol;
253         BME_Vert *v1, *v2;
254         BME_Edge *e, *edar[4];
255         BME_Poly *f;
256
257         EditVert *eve;
258         EditEdge *eed;
259         EditFace *efa;
260
261         int len;
262         bm = BME_make_mesh(allocsize);
263
264         /*copy custom data layout*/
265         CustomData_copy(&em->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
266         CustomData_copy(&em->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
267         CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
268
269         /*copy face corner data*/
270         CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata);
271         /*initialize memory pools*/
272         CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
273         CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
274         CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
275         CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
276         /*needed later*/
277         numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
278         numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
279
280         BME_model_begin(bm);
281         /*add verts*/
282         eve= em->verts.first;
283         while(eve) {
284                 v1 = BME_MV(bm,eve->co);
285                 VECCOPY(v1->no,eve->no);
286                 v1->flag = eve->f;
287                 v1->h = eve->h;
288                 v1->bweight = eve->bweight;
289                 /*Copy Custom Data*/
290                 CustomData_bmesh_copy_data(&em->vdata, &bm->vdata, eve->data, &v1->data);
291                 eve->tmp.v = (EditVert*)v1;
292                 eve = eve->next;
293         }
294         
295         /*add edges*/
296         eed= em->edges.first;
297         while(eed) {
298                 v1 = (BME_Vert*)eed->v1->tmp.v;
299                 v2 = (BME_Vert*)eed->v2->tmp.v;
300                 e = BME_ME(bm, v1, v2);
301                 e->crease = eed->crease;
302                 e->bweight = eed->bweight;
303                 e->flag = eed->f & SELECT;
304                 if(eed->sharp) e->flag |= ME_SHARP;
305                 if(eed->seam) e->flag |= ME_SEAM;
306                 //XXX if(eed->h & EM_FGON) e->flag |= ME_FGON;
307                 if(eed->h & 1) e->flag |= ME_HIDE;
308                 eed->tmp.e = (EditEdge*)e;
309                 CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->data);
310                 eed = eed->next;
311         }
312         /*add faces.*/
313         efa= em->faces.first;
314         while(efa) {
315                 if(efa->v4) len = 4;
316                 else len = 3;
317                 
318                 edar[0] = (BME_Edge*)efa->e1->tmp.e;
319                 edar[1] = (BME_Edge*)efa->e2->tmp.e;
320                 edar[2] = (BME_Edge*)efa->e3->tmp.e;
321                 if(len == 4){
322                         edar[3] = (BME_Edge*)efa->e4->tmp.e;
323                 }
324                 
325                 /*find v1 and v2*/
326                 v1 = (BME_Vert*)efa->v1->tmp.v;
327                 v2 = (BME_Vert*)efa->v2->tmp.v;
328                 
329                 f = BME_MF(bm,v1,v2,edar,len);
330                 f->mat_nr = efa->mat_nr;
331                 f->flag = efa->flag;
332                 if(efa->h) {
333                         f->flag |= ME_HIDE;
334                         f->flag &= ~ME_FACE_SEL;
335                 }
336                 else {
337                         if(efa->f & 1) f->flag |= ME_FACE_SEL;
338                         else f->flag &= ~ME_FACE_SEL;
339                 }
340                 CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->data);
341                 BME_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex);
342                 efa = efa->next;
343         }
344         BME_model_end(bm);
345         return bm;
346 }
347 /* adds the geometry in the bmesh to editMesh (does not free editMesh)
348  * if td != NULL, the transdata will be mapped to the EditVert's co */
349 void BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em) {
350         BME_Vert *v1;
351         BME_Edge *e;
352         BME_Poly *f;
353         
354         BME_TransData *vtd;
355
356         EditVert *eve1, /* *eve2, *eve3, *eve4, */ /* UNUSED */ **evlist;
357         EditEdge *eed;
358         EditFace *efa;
359
360         int totvert, len, i, numTex, numCol;
361
362         if (em == NULL) return;
363
364         CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
365         CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0);
366         CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_BMESH, CD_CALLOC, 0);
367         CustomData_from_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata,0);
368         numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
369         numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
370
371
372         /* convert to EditMesh */
373         /* make editverts */
374         totvert = BLI_countlist(&(bm->verts));
375         evlist= (EditVert **)MEM_mallocN(totvert*sizeof(void *),"evlist");
376         for (i=0,v1=bm->verts.first;v1;v1=v1->next,i++) {
377                 v1->tflag1 = i;
378                 eve1 = NULL; //XXX addvertlist(v1->co,NULL);
379                 if (td && (vtd = BME_get_transdata(td,v1))) {
380                         vtd->loc = eve1->co;
381                 }
382                 eve1->keyindex = i;
383                 evlist[i]= eve1;
384                 eve1->f = (unsigned char)v1->flag;
385                 eve1->h = (unsigned char)v1->h;
386                 eve1->bweight = v1->bweight;
387                 CustomData_em_copy_data(&bm->vdata, &em->vdata, v1->data, &eve1->data);
388         }
389         
390         /* make edges */
391         for (e=bm->edges.first;e;e=e->next) {
392                 if(0) { //XXX if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){
393                         eed= NULL; //XXX addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL);
394                         eed->crease = e->crease;
395                         eed->bweight = e->bweight;
396                         if(e->flag & ME_SEAM) eed->seam = 1;
397                         if(e->flag & ME_SHARP) eed->sharp = 1;
398                         if(e->flag & SELECT) eed->f |= SELECT;
399                         //XXX if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
400                         if(e->flag & ME_HIDE) eed->h |= 1;
401                         if(em->selectmode==SCE_SELECT_EDGE) { 
402                                 ; //XXX EM_select_edge(eed, eed->f & SELECT);
403                         }
404                         CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data);
405                 }
406         }
407
408         /* make faces */
409         for (f=bm->polys.first;f;f=f->next) {
410                 len = BME_cycle_length(f->loopbase);
411                 if (len==3 || len==4) {
412                         eve1= evlist[f->loopbase->v->tflag1];
413                         /* eve2= evlist[f->loopbase->next->v->tflag1]; */ /* UNUSED */
414                         /* eve3= evlist[f->loopbase->next->next->v->tflag1]; */ /* UNUSED */
415                         /* if (len == 4) {
416                                 eve4= evlist[f->loopbase->prev->v->tflag1];
417                         }
418                         else {
419                                 eve4= NULL;
420                         } */ /* UNUSED */
421
422                         efa = NULL; //XXX addfacelist(eve1, eve2, eve3, eve4, NULL, NULL);
423                         efa->mat_nr = (unsigned char)f->mat_nr;
424                         efa->flag= f->flag & ~ME_HIDE;
425                         if(f->flag & ME_FACE_SEL) {
426                                 efa->f |= SELECT;
427                         }
428                         if(f->flag & ME_HIDE) efa->h= 1;
429                         // XXX flag depricated
430                         // if((G.f & G_FACESELECT) && (efa->f & SELECT))
431                                 //XXX EM_select_face(efa, 1); /* flush down */
432                         CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data);
433                         BME_loops_to_corners(bm, &em->fdata, efa->data, f,numCol,numTex);
434                 }
435         }
436
437         MEM_freeN(evlist);
438
439 }
440
441 /* Adds the geometry found in dm to bm
442   */
443 BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm)
444 {
445         
446         BME_Mesh *bm;
447         int allocsize[4] = {512,512,2048,512};
448         MVert *mvert, *mv;
449         MEdge *medge, *me;
450         MFace *mface, *mf;
451         int totface,totedge,totvert,i,len, numTex, numCol;
452         BME_Vert *v1=NULL,*v2=NULL, **vert_array;
453         BME_Edge *e=NULL;
454         BME_Poly *f=NULL;
455         
456         EdgeHash *edge_hash = BLI_edgehash_new();
457
458         bm = BME_make_mesh(allocsize);
459         /*copy custom data layout*/
460         CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
461         CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
462         CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
463
464         /*copy face corner data*/
465         CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata);
466         /*initialize memory pools*/
467         CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
468         CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
469         CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
470         CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
471         /*needed later*/
472         numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
473         numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
474
475         totvert = dm->getNumVerts(dm);
476         totedge = dm->getNumEdges(dm);
477         totface = dm->getNumFaces(dm);
478         mvert = dm->getVertArray(dm);
479         medge = dm->getEdgeArray(dm);
480         mface = dm->getFaceArray(dm);
481
482         vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array");
483
484         BME_model_begin(bm);
485         /*add verts*/
486         for(i=0,mv = mvert; i < totvert;i++,mv++){
487                 v1 = BME_MV(bm,mv->co);
488                 vert_array[i] = v1;
489                 v1->flag = mv->flag;
490                 v1->bweight = mv->bweight/255.0f;
491                 CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v1->data);
492         }
493         /*add edges*/
494         for(i=0,me = medge; i < totedge;i++,me++){
495                 v1 = vert_array[me->v1];
496                 v2 = vert_array[me->v2];
497                 e = BME_ME(bm, v1, v2);
498                 e->crease = me->crease/255.0f;
499                 e->bweight = me->bweight/255.0f;
500                 e->flag = (unsigned char)me->flag;
501                 BLI_edgehash_insert(edge_hash,me->v1,me->v2,e);
502                 CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->data);
503         }
504         /*add faces.*/
505         for(i=0,mf = mface; i < totface;i++,mf++){
506                 BME_Edge *edar[4];
507                 if(mf->v4) len = 4;
508                 else len = 3;
509                 
510                 edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2);
511                 edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3);
512                 if(len == 4){
513                         edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4);
514                         edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1);
515                 }
516                 else
517                         edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1);
518                 
519                 /*find v1 and v2*/
520                 v1 = vert_array[mf->v1];
521                 v2 = vert_array[mf->v2];
522                 
523                 f = BME_MF(bm,v1,v2,edar,len);
524                 f->mat_nr = mf->mat_nr;
525                 f->flag = mf->flag;
526                 CustomData_to_bmesh_block(&dm->faceData,&bm->pdata,i,&f->data);
527                 BME_DMcorners_to_loops(bm, &dm->faceData,i,f, numCol,numTex);
528         }
529         
530         BME_model_end(bm);
531         BLI_edgehash_free(edge_hash, NULL);
532         MEM_freeN(vert_array);
533         return bm;
534 }
535
536 DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
537 {
538         MFace *mface, *mf;
539         MEdge *medge, *me;
540         MVert *mvert, *mv;
541         int *origindex;
542         int totface, totedge, totvert, i, /* bmeshok, */ /* UNUSED */ len, numTex, numCol;
543
544         BME_Vert *v1=NULL;
545         BME_Edge *e=NULL, *oe=NULL;
546         BME_Poly *f=NULL;
547         
548         DerivedMesh *result;
549         EdgeHash *edge_hash = BLI_edgehash_new();
550
551         totvert = BLI_countlist(&(bm->verts));
552         totedge = 0;
553         
554         /*we cannot have double edges in a derived mesh!*/
555         for(i=0, v1=bm->verts.first; v1; v1=v1->next, i++) v1->tflag1 = i;
556         for(e=bm->edges.first; e; e=e->next){
557                 oe = BLI_edgehash_lookup(edge_hash,e->v1->tflag1, e->v2->tflag1);
558                 if(!oe){
559                         totedge++;
560                         BLI_edgehash_insert(edge_hash,e->v1->tflag1,e->v2->tflag1,e);
561                         e->tflag2 = 1;
562                 }
563                 else{
564                         e->tflag2 = 0;
565                 }
566         }
567         
568         /*count quads and tris*/
569         totface = 0;
570         /* bmeshok = 1; */ /* UNUSED */
571         for(f=bm->polys.first;f;f=f->next){
572                 len = BME_cycle_length(f->loopbase);
573                 if(len == 3 || len == 4) totface++;
574         }
575         
576         /*convert back to mesh*/
577         result = CDDM_from_template(dm,totvert,totedge,totface);
578         CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
579         CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
580         CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
581         CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface);
582         numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
583         numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
584
585
586         /*Make Verts*/
587         mvert = CDDM_get_verts(result);
588         origindex = result->getVertDataArray(result, CD_ORIGINDEX);
589         for(i=0,v1=bm->verts.first,mv=mvert;v1;v1=v1->next,i++,mv++){
590                 VECCOPY(mv->co,v1->co);
591                 mv->flag = (unsigned char)v1->flag;
592                 mv->bweight = (char)(255.0*v1->bweight);
593                 CustomData_from_bmesh_block(&bm->vdata, &result->vertData, &v1->data, i);
594                 origindex[i] = ORIGINDEX_NONE;
595         }
596         medge = CDDM_get_edges(result);
597         origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
598         i=0;
599         for(e=bm->edges.first,me=medge;e;e=e->next){
600                 if(e->tflag2){
601                         if(e->v1->tflag1 < e->v2->tflag1){
602                                 me->v1 = e->v1->tflag1;
603                                 me->v2 = e->v2->tflag1;
604                         }
605                         else{
606                                 me->v1 = e->v2->tflag1;
607                                 me->v2 = e->v1->tflag1;
608                         }
609                 
610                         me->crease = (char)(255.0*e->crease);
611                         me->bweight = (char)(255.0*e->bweight);
612                         me->flag = e->flag;
613                         CustomData_from_bmesh_block(&bm->edata, &result->edgeData, &e->data, i);
614                         origindex[i] = ORIGINDEX_NONE;
615                         me++;
616                         i++;
617                 }
618         }
619         if(totface){
620                 mface = CDDM_get_faces(result);
621                 origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
622                 /*make faces*/
623                 for(i=0,f=bm->polys.first;f;f=f->next){
624                         mf = &mface[i];
625                         len = BME_cycle_length(f->loopbase);
626                         if(len==3 || len==4){
627                                 mf->v1 = f->loopbase->v->tflag1;
628                                 mf->v2 = f->loopbase->next->v->tflag1;
629                                 mf->v3 = f->loopbase->next->next->v->tflag1;
630                                 if(len == 4){
631                                         mf->v4 = f->loopbase->prev->v->tflag1;
632                                 }
633                                 /* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */
634                                 if(mf->v3 == 0 || (len == 4 && mf->v4 == 0)){
635                                         test_index_face(mf, NULL, i, len);
636                                 }
637                                 mf->mat_nr = (unsigned char)f->mat_nr;
638                                 mf->flag = (unsigned char)f->flag;
639                                 CustomData_from_bmesh_block(&bm->pdata, &result->faceData, &f->data, i);
640                                 BME_DMloops_to_corners(bm, &result->faceData, i, f,numCol,numTex);
641                                 origindex[i] = ORIGINDEX_NONE;
642                                 i++;
643                         }
644                 }
645         }
646         BLI_edgehash_free(edge_hash, NULL);
647         return result;
648 }