295fd29afc6d6319eade8ffa79249c916dbba81f
[blender.git] / source / blender / bmesh / operators / dissolveops.c
1 #include "MEM_guardedalloc.h"
2
3 #include "BKE_utildefines.h"
4
5 #include "bmesh.h"
6 #include "mesh_intern.h"
7 #include "bmesh_private.h"
8 #include "BLI_arithb.h"
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #define FACE_MARK       1
15 #define FACE_ORIG       2
16 #define VERT_MARK       1
17 #define FACE_NEW        4
18
19 void dissolvefaces_exec(BMesh *bm, BMOperator *op)
20 {
21         BMOIter oiter;
22         BMIter liter, liter2;
23         BMLoop *l, *l2;
24         BMFace *f, *f2, *nf = NULL;
25         V_DECLARE(region);
26         V_DECLARE(regions);
27         BMLoop ***regions = NULL;
28         BMLoop **region = NULL;
29         BMWalker walker, regwalker;
30         int i, j, fcopied;
31
32         BMO_Flag_Buffer(bm, op, BMOP_DISFACES_FACEIN, FACE_MARK);
33         
34         /*collect regions*/
35         f = BMO_IterNew(&oiter, bm, op, BMOP_DISFACES_FACEIN);
36         for (; f; f=BMO_IterStep(&oiter)) {
37                 if (!BMO_TestFlag(bm, f, FACE_MARK)) continue;
38
39                 l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
40                 for (; l; l=BMIter_Step(&liter)) {
41                         l2 = bmesh_radial_nextloop(l);
42                         if (l2!=l && BMO_TestFlag(bm, l2->f, FACE_MARK))
43                                 continue;
44                         if (BM_FacesAroundEdge(l->e) <= 2) {
45                                 V_RESET(region);
46                                 region = NULL; /*forces different allocation*/
47
48                                 /*yay, walk!*/
49                                 BMW_Init(&walker, bm, BMW_ISLANDBOUND, FACE_MARK);
50                                 l = BMW_Begin(&walker, l);
51                                 for (; l; l=BMW_Step(&walker)) {
52                                         V_GROW(region);
53                                         region[V_COUNT(region)-1] = l;
54                                 }
55                                 BMW_End(&walker);
56
57                                 if (BMO_HasError(bm)) {
58                                         BMO_ClearStack(bm);
59                                         BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
60                                         goto cleanup;
61                                 }
62                                 
63                                 if (region == NULL) continue;
64
65                                 BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK);
66                                 f2 = BMW_Begin(&regwalker, region[0]->f);
67                                 for (; f2; f2=BMW_Step(&regwalker)) {
68                                         BMO_ClearFlag(bm, f2, FACE_MARK);
69                                         BMO_SetFlag(bm, f2, FACE_ORIG);
70                                 }
71                                 BMW_End(&regwalker);
72
73                                 if (BMO_HasError(bm)) {
74                                         BMO_ClearStack(bm);
75                                         BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
76                                         goto cleanup;
77                                 }
78                                 
79                                 V_GROW(region);
80                                 V_GROW(regions);
81                                 regions[V_COUNT(regions)-1] = region;
82                                 region[V_COUNT(region)-1] = NULL;
83                                 break;
84                         }
85                 }
86         }
87         
88         for (i=0; i<V_COUNT(regions); i++) {
89                 BMEdge **edges = NULL;
90                 V_DECLARE(edges);
91
92                 region = regions[i];
93                 for (j=0; region[j]; j++) {
94                         V_GROW(edges);
95                         edges[V_COUNT(edges)-1] = region[j]->e;
96                 }
97                 
98                 f= BM_Make_Ngon(bm, edges[0]->v1, edges[0]->v2,  edges, j, 0);
99                 
100                 if (!f) continue;
101
102                 /*
103                 NOTE: sadly, make ngon's overlap checking option
104                       crashes ;/
105                 make ngon can fail, if there was already an existing face.
106                 this is desired behaviour, I think, so we'll just silently
107                 ignore any possible other error cases.
108                 if (!f) {
109                         //raise error
110                         BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
111                         goto cleanup;
112                 }*/
113                 
114                 BMO_SetFlag(bm, f, FACE_NEW);
115
116                 fcopied = 0;
117                 l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
118                 for (; l; l=BMIter_Step(&liter)) {
119                         /*ensure winding is identical*/
120                         l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l);
121                         for (; l2; l2=BMIter_Step(&liter2)) {
122                                 if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) {
123                                         if (l2->v != l->v)
124                                                 bmesh_loop_reverse(bm, l2->f);
125                                         break;
126                                 }
127                         }
128                         
129                         /*copy over attributes*/
130                         l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l);
131                         for (; l2; l2=BMIter_Step(&liter2)) {
132                                 if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) {
133                                         if (!fcopied) {
134                                                 BM_Copy_Attributes(bm, bm, l2->f, f);
135                                                 fcopied = 1;
136                                         }
137                                         BM_Copy_Attributes(bm, bm, l2, l);
138                                         break;
139                                 }
140                         }
141                 }
142         }
143
144         BMO_CallOpf(bm, "del geom=%ff context=%d", FACE_ORIG, DEL_FACES);
145         if (BMO_HasError(bm)) return;
146
147         BMO_Flag_To_Slot(bm, op, BMOP_DISFACES_REGIONOUT, FACE_NEW, BM_FACE);
148
149 cleanup:
150         /*free/cleanup*/
151         for (i=0; i<V_COUNT(regions); i++) {
152                 if (regions[i]) V_FREE(regions[i]);
153         }
154
155         V_FREE(regions);
156 }
157
158 /*returns 1 if any faces were dissolved*/
159 int BM_DissolveFaces(EditMesh *em, int flag) {
160         BMesh *bm = editmesh_to_bmesh(em);
161         EditMesh *em2;
162         BMOperator op;
163
164         BMO_Init_Op(&op, BMOP_DISSOLVE_FACES);
165         BMO_HeaderFlag_To_Slot(bm, &op, BMOP_DISFACES_FACEIN, flag, BM_FACE);
166         BMO_Exec_Op(bm, &op);
167         BMO_Finish_Op(bm, &op);
168         
169         em2 = bmesh_to_editmesh(bm);
170         set_editMesh(em, em2);
171         MEM_freeN(em2);
172
173         return BMO_GetSlot(&op, BMOP_DISFACES_REGIONOUT)->len > 0;
174 }
175
176 void dissolveverts_exec(BMesh *bm, BMOperator *op)
177 {
178         BMOpSlot *vinput;
179         BMIter iter, fiter;
180         BMVert *v;
181         BMFace *f;
182         
183         vinput = BMO_GetSlot(op, BMOP_DISVERTS_VERTIN);
184
185         BMO_Flag_Buffer(bm, op, BMOP_DISVERTS_VERTIN, VERT_MARK);
186         
187         for (v=BMIter_New(&iter, bm, BM_VERTS, NULL); v; v=BMIter_Step(&iter)) {
188                 if (BMO_TestFlag(bm, v, VERT_MARK)) {
189                         f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
190                         for (; f; f=BMIter_Step(&fiter)) {
191                                 BMO_SetFlag(bm, f, FACE_MARK);
192                         }
193                 }
194         }
195
196         BMO_CallOpf(bm, "dissolvefaces faces=%ff", FACE_MARK);
197         if (BMO_HasError(bm)) {
198                         BMO_ClearStack(bm);
199                         BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED, NULL);
200         }
201 }
202
203 /*this code is for cleaning up two-edged faces, it shall become
204   it's own function one day.*/
205 #if 0
206                 /*clean up two-edged faces*/
207                 /*basic idea is to keep joining 2-edged faces until their
208                   gone.  this however relies on joining two 2-edged faces
209                   together to work, which doesn't.*/
210                 found3 = 1;
211                 while (found3) {
212                         found3 = 0;
213                         for (f=BMIter_New(&iter, bm, BM_FACES, NULL); f; f=BMIter_Step(&iter)){
214                                 if (!BM_Validate_Face(bm, f, stderr)) {
215                                         printf("error.\n");
216                                 }
217
218                                 if (f->len == 2) {
219                                         //this design relies on join faces working
220                                         //with two-edged faces properly.
221                                         //commenting this line disables the
222                                         //outermost loop.
223                                         //found3 = 1;
224                                         found2 = 0;
225                                         l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
226                                         fe = l->e;
227                                         for (; l; l=BMIter_Step(&liter)) {
228                                                 f2 = BMIter_New(&fiter, bm,
229                                                                 BM_FACES_OF_EDGE, l->e);
230                                                 for (; f2; f2=BMIter_Step(&fiter)) {
231                                                         if (f2 != f) {
232                                                                 BM_Join_Faces(bm, f, f2, l->e, 
233                                                                               1, 0);
234                                                                 found2 = 1;
235                                                                 break;
236                                                         }
237                                                 }
238                                                 if (found2) break;
239                                         }
240
241                                         if (!found2) {
242                                                 bmesh_kf(bm, f);
243                                                 bmesh_ke(bm, fe);
244                                         }
245                                 } /*else if (f->len == 3) {
246                                         BMEdge *ed[3];
247                                         BMVert *vt[3];
248                                         BMLoop *lp[3];
249                                         int i=0;
250
251                                         //check for duplicate edges
252                                         l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
253                                         for (; l; l=BMIter_Step(&liter)) {
254                                                 ed[i] = l->e;   
255                                                 lp[i] = l;
256                                                 vt[i++] = l->v;
257                                         }
258                                         if (vt[0] == vt[1] || vt[0] == vt[2]) {
259                                                 i += 1;
260                                         }
261                                 }*/
262                         }
263                 }
264                 if (oldlen == len) break;
265                 oldlen = len;
266
267 #endif