dissolve faces: errors-out on holes, preserves winding, and doesn't delete original...
[blender.git] / source / blender / bmesh / intern / bmesh_to_editmesh.c
1 #include "MEM_guardedalloc.h"
2 #include "BKE_customdata.h" 
3 #include "DNA_listBase.h"
4 #include "DNA_meshdata_types.h"
5 #include "DNA_object_types.h"
6 #include "DNA_scene_types.h"
7 #include <string.h>
8 #include "BKE_utildefines.h"
9 #include "BKE_mesh.h"
10 #include "BKE_global.h"
11 #include "BKE_DerivedMesh.h"
12 #include "BKE_cdderivedmesh.h"
13
14 #include "BLI_editVert.h"
15 #include "mesh_intern.h"
16 #include "ED_mesh.h"
17
18 #include "BLI_blenlib.h"
19 #include "BLI_edgehash.h"
20
21 #include "bmesh.h"
22
23 /*
24  * BMESH TO EDITMESH
25  *
26  * This file contains functions for converting 
27  * from a bmesh to an editmesh
28  *
29 */
30
31 /*
32  * LOOPS TO EDITMESH CORNERS
33  *
34  * Converts N-Gon loop (face-edge)
35  * data (UVs, Verts Colors, ect) to
36  * face corner data.
37  *
38 */
39
40 static void loops_to_editmesh_corners(BMesh *bm, CustomData *facedata, void *face_block, BMFace *f,int numCol, int numTex){
41         int i, j;
42         BMLoop *l;
43         MTFace *texface;
44         MTexPoly *texpoly;
45         MCol *mcol;
46         MLoopCol *mloopcol;
47         MLoopUV *mloopuv;
48
49         for(i=0; i < numTex; i++){
50                 texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
51                 texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
52                 
53                 texface->tpage = texpoly->tpage;
54                 texface->flag = texpoly->flag;
55                 texface->transp = texpoly->transp;
56                 texface->mode = texpoly->mode;
57                 texface->tile = texpoly->tile;
58                 texface->unwrap = texpoly->unwrap;
59
60                 j = 0;
61                 l = f->loopbase;
62                 do {
63                         mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
64                         texface->uv[j][0] = mloopuv->uv[0];
65                         texface->uv[j][1] = mloopuv->uv[1];
66                         j++;
67                         l = ((BMLoop*)(l->head.next));
68                 } while(l!=f->loopbase);
69
70         }
71
72         for(i=0; i < numCol; i++){
73                 mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
74                 j = 0;
75                 l = f->loopbase;
76                 do {
77                         mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
78                         mcol[j].r = mloopcol->r;
79                         mcol[j].g = mloopcol->g;
80                         mcol[j].b = mloopcol->b;
81                         mcol[j].a = mloopcol->a;
82                         j++;
83                         l = ((BMLoop*)(l->head.next));
84                 } while(l!=f->loopbase);
85         }
86 }
87
88 static EditVert *bmeshvert_to_editvert(BMesh *bm, EditMesh *em, BMVert *v, int index, EditVert **evlist)
89 {
90         EditVert *eve = NULL;
91
92         v->head.eflag1 = index; /*abuse!*/
93         eve = addvertlist(em, v->co, NULL);
94         eve->keyindex = index;
95         evlist[index]= eve;
96         
97         /*copy flags*/
98         if(v->head.flag & BM_HIDDEN) eve->h = 1;
99         if (v->head.flag & BM_SELECT) eve->f |= SELECT;
100
101         eve->bweight = v->bweight;
102         CustomData_em_copy_data(&bm->vdata, &em->vdata, v->data, &eve->data);
103         /*copy normal*/
104         eve->no[0] = v->no[0];
105         eve->no[1] = v->no[1];
106         eve->no[2] = v->no[2];
107
108         return eve;
109 }
110
111 static void bmeshedge_to_editedge_internal(BMesh *bm, EditMesh *em, BMEdge *e, EditEdge *eed)
112 {
113         eed->crease = e->crease;
114         eed->bweight = e->bweight;
115         
116         //copy relavent flags
117         if (e->head.flag & BM_SELECT) eed->f |= SELECT;
118         if (e->head.flag & BM_SEAM) eed->seam = 1;
119         if (e->head.flag & BM_SHARP) eed->sharp = 1;
120         if (e->head.flag & BM_HIDDEN) eed->h = 1;
121         if (e->head.flag & BM_FGON) eed->h |= EM_FGON;
122
123         CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data);
124 }
125
126 static EditEdge *bmeshedge_to_editedge(BMesh *bm, EditMesh *em, BMEdge *e, EditVert **evlist)
127 {
128         EditEdge *eed = NULL;
129
130         if(!(findedgelist(em, evlist[e->v1->head.eflag1], evlist[e->v2->head.eflag1]))){
131                 eed= addedgelist(em, evlist[e->v1->head.eflag1], evlist[e->v2->head.eflag1], NULL);
132                 bmeshedge_to_editedge_internal(bm, em, e, eed);
133         }
134
135         return eed;
136 }
137
138 static EditFace *bmeshface_to_editface(BMesh *bm, EditMesh *em, BMFace *f, EditVert **evlist, int numCol, int numTex)
139 {
140         EditVert *eve1, *eve2, *eve3, *eve4;
141         EditFace *efa = NULL;
142         int len;
143         
144         len = f->len;
145
146         eve1= evlist[f->loopbase->v->head.eflag1];
147         eve2= evlist[((BMLoop*)(f->loopbase->head.next))->v->head.eflag1];
148         eve3= evlist[((BMLoop*)(f->loopbase->head.next->next))->v->head.eflag1];
149         if (len == 4) {
150                 eve4= evlist[ ((BMLoop*)(f->loopbase->head.prev))->v->head.eflag1];
151         }
152         else {
153                 eve4= NULL;
154         }
155         
156         if (eve1==eve2 || eve1==eve3 || eve1==eve4 || eve2==eve3 || eve3==eve4
157             || eve2==eve4) return NULL;
158
159         efa = addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL);
160         if (!efa) return NULL;
161
162         bmeshedge_to_editedge_internal(bm, em, f->loopbase->e, efa->e1);
163         bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->loopbase->head.next))->e, efa->e2);
164         bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->loopbase->head.next->next))->e, efa->e3);
165         if(eve4)
166                 bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->loopbase->head.prev))->e, efa->e4);
167
168         efa->mat_nr = (unsigned char)f->mat_nr;
169
170         /*Copy normal*/
171         efa->n[0] = f->no[0];
172         efa->n[1] = f->no[1];
173         efa->n[2] = f->no[2];
174         
175         //copy relavent original flags
176         if (f->head.flag & BM_SELECT) efa->f |= SELECT;
177         if (f->head.flag & BM_HIDDEN) efa->h = 1;
178         if (f->head.flag & BM_SMOOTH) efa->flag |= ME_SMOOTH;
179         if (f->head.flag & BM_ACTIVE) EM_set_actFace(em, efa);
180
181         CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data);
182         loops_to_editmesh_corners(bm, &em->fdata, efa->data, f, numCol,numTex);
183         
184         return efa;
185 }
186
187 EditMesh *bmesh_to_editmesh_intern(BMesh *bm) 
188 {
189         BMVert *v;
190         BMEdge *e;
191         BMFace *f;
192
193         BMIter verts;
194         BMIter edges;
195         BMIter faces;
196
197         EditMesh *em;
198         EditVert *eve, **evlist;
199
200         int totvert, i, numTex, numCol;
201
202         em = MEM_callocN(sizeof(EditMesh), "EditMesh from bmesh");
203
204         if(bm->selectmode & BM_VERT) em->selectmode |= SCE_SELECT_VERTEX;
205         if(bm->selectmode & BM_EDGE) em->selectmode |= SCE_SELECT_EDGE;
206         if(bm->selectmode & BM_FACE) em->selectmode |= SCE_SELECT_FACE;
207
208         CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
209         CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0);
210         CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_BMESH, CD_CALLOC, 0);
211         CustomData_from_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata,0);
212         numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
213         numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
214
215         totvert = BM_Count_Element(bm, BM_VERT);
216         evlist= MEM_mallocN(totvert*sizeof(EditVert *),"evlist");
217
218         /* make vertices */
219         for(i=0, v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts), i++) 
220                 eve = bmeshvert_to_editvert(bm, em, v, i, evlist);
221
222         /* make edges */
223         for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges))
224                 bmeshedge_to_editedge(bm, em, e, evlist);
225
226         /* make faces */
227         for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces))
228                 bmeshface_to_editface(bm, em, f, evlist, numCol, numTex);
229                         
230         MEM_freeN(evlist);
231
232         EM_fgon_flags(em);
233
234         EM_nvertices_selected(em);
235         EM_nedges_selected(em);
236         EM_nfaces_selected(em);
237
238         return em;
239 }
240
241 void bmesh2edit_exec(BMesh *bmesh, BMOperator *op)
242 {
243         BMO_Set_Pnt(op, BMOP_TO_EDITMESH_EMOUT, bmesh_to_editmesh_intern(bmesh));
244 }
245
246 #define FACE_NGON       1
247
248 void bmesh_make_fgons_exec(BMesh *bmesh, BMOperator *op)
249 {
250         BMOperator triop;
251         BMFace *face;
252         BMIter iter;
253         BMEdge *edge;
254         BMOpSlot *eout;
255         int i;
256
257         BMO_Init_Op(&triop, BMOP_TRIANGULATE);
258         
259         /*HACK: I don't know if this'll conflict with other flags at all!*/
260         for (face = BMIter_New(&iter, bmesh, BM_FACES, NULL); face; face=BMIter_Step(&iter)) {
261                 if (face->len > 4) {
262                         BMO_SetFlag(bmesh, face, FACE_NGON);
263                 }
264         }
265
266         BMO_Flag_To_Slot(bmesh, &triop, BMOP_TRIANG_FACEIN, FACE_NGON, BM_FACE);
267         BMO_Exec_Op(bmesh, &triop);
268
269         eout = BMO_GetSlot(&triop, BMOP_TRIANG_NEW_EDGES);
270         for (i=0; i<eout->len; i++) {
271                 edge = ((BMEdge**)eout->data.buf)[i];
272                 edge->head.flag |= BM_FGON;
273         }
274
275         BMO_Finish_Op(bmesh, &triop);
276 }
277
278 EditMesh *bmesh_to_editmesh(BMesh *bmesh)
279 {
280         BMOperator conv, makefgon;
281         EditMesh *em;
282         
283         /*first fgon-afy the mesh*/
284         BMO_Init_Op(&makefgon, BMOP_MAKE_FGONS);
285         BMO_Exec_Op(bmesh, &makefgon);
286         BMO_Finish_Op(bmesh, &makefgon);
287
288         BMO_Init_Op(&conv, BMOP_TO_EDITMESH);
289         BMO_Exec_Op(bmesh, &conv);
290         em = conv.slots[BMOP_TO_EDITMESH_EMOUT].data.p;
291         BMO_Finish_Op(bmesh, &conv);
292         
293         return em;
294 }