skip assigning vars for inline bmesh flag funcs, just cast.
[blender.git] / source / blender / bmesh / operators / bmesh_dupeops.c
1 #include "MEM_guardedalloc.h"
2
3 #include "BLI_utildefines.h"
4
5 #include "BLI_ghash.h"
6 #include "BLI_memarena.h"
7 #include "BLI_blenlib.h"
8 #include "BLI_array.h"
9 #include "BLI_math.h"
10
11 #include "bmesh.h"
12 #include "bmesh_operators_private.h"
13
14 /*local flag defines*/
15 #define DUPE_INPUT              1 /*input from operator*/
16 #define DUPE_NEW                2
17 #define DUPE_DONE               4
18 #define DUPE_MAPPED             8
19
20 /*
21  *  COPY VERTEX
22  *
23  *   Copy an existing vertex from one bmesh to another.
24  *
25 */
26 static BMVert *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *target_mesh, GHash *vhash)
27 {
28         BMVert *target_vertex = NULL;
29
30         /*Create a new vertex*/
31         target_vertex = BM_Make_Vert(target_mesh, source_vertex->co,  NULL);
32         
33         /*Insert new vertex into the vert hash*/
34         BLI_ghash_insert(vhash, source_vertex, target_vertex);  
35         
36         /*Copy attributes*/
37         BM_Copy_Attributes(source_mesh, target_mesh, source_vertex, target_vertex);
38         
39         /*Set internal op flags*/
40         BMO_SetFlag(target_mesh, (BMHeader*)target_vertex, DUPE_NEW);
41         
42         return target_vertex;
43 }
44
45 /*
46  * COPY EDGE
47  *
48  * Copy an existing edge from one bmesh to another.
49  *
50 */
51 static BMEdge *copy_edge(BMOperator *op, BMesh *source_mesh,
52                          BMEdge *source_edge, BMesh *target_mesh,
53                          GHash *vhash, GHash *ehash)
54 {
55         BMEdge *target_edge = NULL;
56         BMVert *target_vert1, *target_vert2;
57         BMFace *face;
58         BMIter fiter;
59         int rlen;
60
61         /*see if any of the neighboring faces are
62           not being duplicated.  in that case,
63           add it to the new/old map.*/
64         rlen = 0;
65         for (face=BMIter_New(&fiter,source_mesh, BM_FACES_OF_EDGE,source_edge);
66                 face; face=BMIter_Step(&fiter)) {
67                 if (BMO_TestFlag(source_mesh, face, DUPE_INPUT)) {
68                         rlen++;
69                 }
70         }
71
72         /*Lookup v1 and v2*/
73         target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
74         target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
75         
76         /*Create a new edge*/
77         target_edge = BM_Make_Edge(target_mesh, target_vert1, target_vert2, NULL, 0);
78         
79         /*add to new/old edge map if necassary*/
80         if (rlen < 2) {
81                 /*not sure what non-manifold cases of greater then three
82                   radial should do.*/
83                 BMO_Insert_MapPointer(source_mesh,op, "boundarymap",
84                         source_edge, target_edge);
85         }
86
87         /*Insert new edge into the edge hash*/
88         BLI_ghash_insert(ehash, source_edge, target_edge);      
89         
90         /*Copy attributes*/
91         BM_Copy_Attributes(source_mesh, target_mesh, source_edge, target_edge);
92         
93         /*Set internal op flags*/
94         BMO_SetFlag(target_mesh, (BMHeader*)target_edge, DUPE_NEW);
95         
96         return target_edge;
97 }
98
99 /*
100  * COPY FACE
101  *
102  *  Copy an existing face from one bmesh to another.
103  *
104 */
105 static BMFace *copy_face(BMOperator *op, BMesh *source_mesh,
106                          BMFace *source_face, BMesh *target_mesh, 
107                          BMEdge **edar, GHash *vhash, GHash *ehash)
108 {
109         BMVert *target_vert1, *target_vert2;
110         BMLoop *source_loop, *target_loop;
111         BMFace *target_face = NULL;
112         BMIter iter, iter2;
113         int i;
114         
115         /*lookup the first and second verts*/
116         target_vert1 = BLI_ghash_lookup(vhash, BMIter_New(&iter, source_mesh, BM_VERTS_OF_FACE, source_face));
117         target_vert2 = BLI_ghash_lookup(vhash, BMIter_Step(&iter));
118         
119         /*lookup edges*/
120         for (i=0,source_loop=BMIter_New(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face); 
121                      source_loop; source_loop=BMIter_Step(&iter), i++) {
122                 edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
123         }
124         
125         /*create new face*/
126         target_face = BM_Make_Ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0); 
127         BMO_Insert_MapPointer(source_mesh, op, 
128                  "facemap", source_face, target_face);
129         BMO_Insert_MapPointer(source_mesh, op, 
130                  "facemap", target_face, source_face);
131
132         BM_Copy_Attributes(source_mesh, target_mesh, source_face, target_face);
133
134         /*mark the face for output*/
135         BMO_SetFlag(target_mesh, (BMHeader*)target_face, DUPE_NEW);
136         
137         /*copy per-loop custom data*/
138         BM_ITER(source_loop, &iter, source_mesh, BM_LOOPS_OF_FACE, source_face) {
139                 BM_ITER(target_loop, &iter2, target_mesh, BM_LOOPS_OF_FACE, target_face) {
140                         if (BLI_ghash_lookup(vhash, source_loop->v) == target_loop->v) {
141                                 BM_Copy_Attributes(source_mesh, target_mesh, source_loop, target_loop);
142                                 break;
143                         }
144                 }
145         }
146
147         return target_face;
148 }
149         /*
150  * COPY MESH
151  *
152  * Internal Copy function.
153 */
154
155 static void copy_mesh(BMOperator *op, BMesh *source, BMesh *target)
156 {
157
158         BMVert *v = NULL, *v2;
159         BMEdge *e = NULL, **edar = NULL;
160         BMFace *f = NULL;
161         
162         BMIter verts;
163         BMIter edges;
164         BMIter faces;
165         
166         GHash *vhash;
167         GHash *ehash;
168         
169         int maxlength = 0;
170
171         /*initialize pointer hashes*/
172         vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh dupeops v");
173         ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh dupeops e");
174         
175         /*initialize edge pointer array*/
176         for(f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f = BMIter_Step(&faces)){
177                 if(f->len > maxlength) maxlength = f->len;
178         }
179         edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array");
180         
181         for(v = BMIter_New(&verts, source, BM_VERTS_OF_MESH, source); v; v = BMIter_Step(&verts)){
182                 if(BMO_TestFlag(source, (BMHeader*)v, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE))){
183                         BMIter iter;
184                         int iso = 1;
185
186                         v2 = copy_vertex(source, v, target, vhash);
187
188                         BM_ITER(f, &iter, source, BM_FACES_OF_VERT, v) {
189                                 if (BMO_TestFlag(source, f, DUPE_INPUT)) {
190                                         iso = 0;
191                                         break;
192                                 }
193                         }
194
195                         if (iso) {
196                                 BM_ITER(e, &iter, source, BM_EDGES_OF_VERT, v) {
197                                         if (BMO_TestFlag(source, e, DUPE_INPUT)) {
198                                                 iso = 0;
199                                                 break;
200                                         }
201                                 }
202                         }
203                         
204                         if (iso) 
205                                 BMO_Insert_MapPointer(source, op, "isovertmap", v, v2);
206
207                         BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
208                 }
209         }
210
211         /*now we dupe all the edges*/
212         for(e = BMIter_New(&edges, source, BM_EDGES_OF_MESH, source); e; e = BMIter_Step(&edges)){
213                 if(BMO_TestFlag(source, (BMHeader*)e, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE))){
214                         /*make sure that verts are copied*/
215                         if(!BMO_TestFlag(source, (BMHeader*)e->v1, DUPE_DONE)) {
216                                 copy_vertex(source, e->v1, target, vhash);
217                                 BMO_SetFlag(source, (BMHeader*)e->v1, DUPE_DONE);
218                         }
219                         if(!BMO_TestFlag(source, (BMHeader*)e->v2, DUPE_DONE)) {
220                                 copy_vertex(source, e->v2, target, vhash);
221                                 BMO_SetFlag(source, (BMHeader*)e->v2, DUPE_DONE);
222                         }
223                         /*now copy the actual edge*/
224                         copy_edge(op, source, e, target,  vhash,  ehash);                       
225                         BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE); 
226                 }
227         }
228
229         /*first we dupe all flagged faces and their elements from source*/
230         for(f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f= BMIter_Step(&faces)){
231                 if(BMO_TestFlag(source, (BMHeader*)f, DUPE_INPUT)){
232                         /*vertex pass*/
233                         for(v = BMIter_New(&verts, source, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts)){
234                                 if(!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE)){ 
235                                         copy_vertex(source,v, target, vhash);
236                                         BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
237                                 }
238                         }
239
240                         /*edge pass*/
241                         for(e = BMIter_New(&edges, source, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges)){
242                                 if(!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE)){
243                                         copy_edge(op, source, e, target,  vhash,  ehash);
244                                         BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE);
245                                 }
246                         }
247                         copy_face(op, source, f, target, edar, vhash, ehash);
248                         BMO_SetFlag(source, (BMHeader*)f, DUPE_DONE);
249                 }
250         }
251         
252         /*free pointer hashes*/
253         BLI_ghash_free(vhash, NULL, NULL);
254         BLI_ghash_free(ehash, NULL, NULL);      
255
256         /*free edge pointer array*/
257         if(edar)
258                 MEM_freeN(edar);
259 }
260
261 /*
262  * Duplicate Operator
263  *
264  * Duplicates verts, edges and faces of a mesh.
265  *
266  * INPUT SLOTS:
267  *
268  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated
269  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated
270  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated
271  *
272  * OUTPUT SLOTS:
273  * 
274  * BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices
275  * BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges
276  * BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces
277  * BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices
278  * BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges
279  * BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces
280  *
281 */
282
283 void dupeop_exec(BMesh *bm, BMOperator *op)
284 {
285         BMOperator *dupeop = op;
286         BMesh *bm2 = BMO_Get_Pnt(op, "dest");
287         
288         if (!bm2)
289                 bm2 = bm;
290                 
291         /*flag input*/
292         BMO_Flag_Buffer(bm, dupeop, "geom", DUPE_INPUT, BM_ALL);
293
294         /*use the internal copy function*/
295         copy_mesh(dupeop, bm, bm2);
296         
297         /*Output*/
298         /*First copy the input buffers to output buffers - original data*/
299         BMO_CopySlot(dupeop, dupeop, "geom", "origout");
300
301         /*Now alloc the new output buffers*/
302         BMO_Flag_To_Slot(bm, dupeop, "newout", DUPE_NEW, BM_ALL);
303 }
304
305 /*executes the duplicate operation, feeding elements of 
306   type flag etypeflag and header flag flag to it.  note,
307   to get more useful information (such as the mapping from
308   original to new elements) you should run the dupe op manually.*/
309 void BMOP_DupeFromFlag(BMesh *bm, int etypeflag, int flag)
310 {
311         BMOperator dupeop;
312
313         BMO_Init_Op(&dupeop, "dupe");
314         BMO_HeaderFlag_To_Slot(bm, &dupeop, "geom", flag, etypeflag);
315
316         BMO_Exec_Op(bm, &dupeop);
317         BMO_Finish_Op(bm, &dupeop);
318 }
319
320 /*
321  * Split Operator
322  *
323  * Duplicates verts, edges and faces of a mesh but also deletes the originals.
324  *
325  * INPUT SLOTS:
326  *
327  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
328  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
329  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
330  *
331  * OUTPUT SLOTS:
332  * 
333  * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
334  * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
335  * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
336  *
337 */
338
339 #define SPLIT_INPUT     1
340 void splitop_exec(BMesh *bm, BMOperator *op)
341 {
342         BMOperator *splitop = op;
343         BMOperator dupeop;
344         BMOperator delop;
345         BMVert *v;
346         BMEdge *e;
347         BMFace *f;
348         BMIter iter, iter2;
349         int found;
350
351         /*initialize our sub-operators*/
352         BMO_Init_Op(&dupeop, "dupe");
353         BMO_Init_Op(&delop, "del");
354         
355         BMO_CopySlot(splitop, &dupeop, "geom", "geom");
356         BMO_Exec_Op(bm, &dupeop);
357         
358         BMO_Flag_Buffer(bm, splitop, "geom", SPLIT_INPUT, BM_ALL);
359
360         /*make sure to remove edges and verts we don't need.*/
361         for (e= BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);e;e=BMIter_Step(&iter)) {
362                 found = 0;
363                 f = BMIter_New(&iter2, bm, BM_FACES_OF_EDGE, e);
364                 for (; f; f=BMIter_Step(&iter2)) {
365                         if (!BMO_TestFlag(bm, f, SPLIT_INPUT)) {
366                                 found = 1;
367                                 break;
368                         }
369                 }
370                 if (!found) BMO_SetFlag(bm, e, SPLIT_INPUT);
371         }
372         
373         for (v= BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);v;v=BMIter_Step(&iter)) {
374                 found = 0;
375                 e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, v);
376                 for (; e; e=BMIter_Step(&iter2)) {
377                         if (!BMO_TestFlag(bm, e, SPLIT_INPUT)) {
378                                 found = 1;
379                                 break;
380                         }
381                 }
382                 if (!found) BMO_SetFlag(bm, v, SPLIT_INPUT);
383
384         }
385
386         /*connect outputs of dupe to delete, exluding keep geometry*/
387         BMO_Set_Int(&delop, "context", DEL_FACES);
388         BMO_Flag_To_Slot(bm, &delop, "geom", SPLIT_INPUT, BM_ALL);
389         
390         BMO_Exec_Op(bm, &delop);
391
392         /*now we make our outputs by copying the dupe outputs*/
393         BMO_CopySlot(&dupeop, splitop, "newout", "geom");
394         BMO_CopySlot(&dupeop, splitop, "boundarymap",
395                      "boundarymap");
396         BMO_CopySlot(&dupeop, splitop, "isovertmap",
397                      "isovertmap");
398         
399         /*cleanup*/
400         BMO_Finish_Op(bm, &delop);
401         BMO_Finish_Op(bm, &dupeop);
402 }
403
404 #define DEL_INPUT               1
405 #define DEL_WIREVERT    2
406
407 static void delete_verts(BMesh *bm);
408 static void delete_context(BMesh *bm, int type);
409
410 void delop_exec(BMesh *bm, BMOperator *op)
411 {
412         BMOperator *delop = op;
413
414         /*Mark Buffers*/
415         BMO_Flag_Buffer(bm, delop, "geom", DEL_INPUT, BM_ALL);
416
417         delete_context(bm, BMO_Get_Int(op, "context"));
418 }
419
420 static void delete_verts(BMesh *bm)
421 {
422         BMVert *v;
423         BMEdge *e;
424         BMLoop *f;
425         
426         BMIter verts;
427         BMIter edges;
428         BMIter faces;
429         
430         for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
431                 if(BMO_TestFlag(bm, (BMHeader*)v, DEL_INPUT)) {
432                         /*Visit edges*/
433                         for(e = BMIter_New(&edges, bm, BM_EDGES_OF_VERT, v); e; e = BMIter_Step(&edges))
434                                 BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT);
435                         /*Visit faces*/
436                         for(f = BMIter_New(&faces, bm, BM_FACES_OF_VERT, v); f; f = BMIter_Step(&faces))
437                                 BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT);
438                 }
439         }
440
441         BM_remove_tagged_faces(bm, DEL_INPUT);
442         BM_remove_tagged_edges(bm, DEL_INPUT);
443         BM_remove_tagged_verts(bm, DEL_INPUT);
444 }
445
446 static void delete_edges(BMesh *bm){
447         BMEdge *e;
448         BMFace *f;
449         
450         BMIter edges;
451         BMIter faces;
452
453         for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
454                 if(BMO_TestFlag(bm, (BMHeader*)e, DEL_INPUT)) {
455                         for(f = BMIter_New(&faces, bm, BM_FACES_OF_EDGE, e); f; f = BMIter_Step(&faces)){
456                                         BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT);
457                         }
458                 }
459         }
460         BM_remove_tagged_faces(bm, DEL_INPUT);
461         BM_remove_tagged_edges(bm, DEL_INPUT);
462 }
463
464 /*you need to make remove tagged verts/edges/faces
465         api functions that take a filter callback.....
466         and this new filter type will be for opstack flags.
467         This is because the BM_remove_taggedXXX functions bypass iterator API.
468                  -Ops dont care about 'UI' considerations like selection state, hide state, ect. If you want to work on unhidden selections for instance,
469                  copy output from a 'select context' operator to another operator....
470 */
471
472 /*Break this into smaller functions*/
473
474 static void delete_context(BMesh *bm, int type){
475         BMVert *v;
476         BMEdge *e;
477         BMFace *f;
478
479         BMIter verts;
480         BMIter edges;
481         BMIter faces;
482         
483         if(type == DEL_VERTS) delete_verts(bm);
484         else if(type == DEL_EDGES){
485                 /*flush down to verts*/
486                 for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
487                         if(BMO_TestFlag(bm, (BMHeader*)e, DEL_INPUT)){
488                                 BMO_SetFlag(bm, (BMHeader*)(e->v1), DEL_INPUT);
489                                 BMO_SetFlag(bm, (BMHeader*)(e->v2), DEL_INPUT);
490                         }
491                 }
492                 delete_edges(bm);
493                 /*remove loose vertices*/
494                 for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
495                         if(BMO_TestFlag(bm, (BMHeader*)v, DEL_INPUT) && (!(v->e)))
496                                 BMO_SetFlag(bm, (BMHeader*)v, DEL_WIREVERT);
497                 }
498                 BM_remove_tagged_verts(bm, DEL_WIREVERT);
499         }
500         else if(type == DEL_EDGESFACES) delete_edges(bm);
501         else if(type == DEL_ONLYFACES) BM_remove_tagged_faces(bm, DEL_INPUT);
502         else if (type == DEL_ONLYTAGGED) {
503                 BM_remove_tagged_faces(bm, DEL_INPUT);
504                 BM_remove_tagged_edges(bm, DEL_INPUT);
505                 BM_remove_tagged_verts(bm, DEL_INPUT);
506         } else if(type == DEL_FACES){
507                 /*go through and mark all edges and all verts of all faces for delete*/
508                 for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
509                         if(BMO_TestFlag(bm, (BMHeader*)f, DEL_INPUT)){
510                                 for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges))
511                                         BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT);
512                                 for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts))
513                                         BMO_SetFlag(bm, (BMHeader*)v, DEL_INPUT);
514                         }
515                 }
516                 /*now go through and mark all remaining faces all edges for keeping.*/
517                 for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
518                         if(!BMO_TestFlag(bm, (BMHeader*)f, DEL_INPUT)){
519                                 for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e= BMIter_Step(&edges))
520                                         BMO_ClearFlag(bm, (BMHeader*)e, DEL_INPUT);
521                                 for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v= BMIter_Step(&verts))
522                                         BMO_ClearFlag(bm, (BMHeader*)v, DEL_INPUT);
523                         }
524                 }
525                 /*now delete marked faces*/
526                 BM_remove_tagged_faces(bm, DEL_INPUT);
527                 /*delete marked edges*/
528                 BM_remove_tagged_edges(bm, DEL_INPUT);
529                 /*remove loose vertices*/
530                 BM_remove_tagged_verts(bm, DEL_INPUT);
531         }
532         /*does this option even belong in here?*/
533         else if(type == DEL_ALL){
534                 for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces))
535                         BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT);
536                 for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges))
537                         BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT);
538                 for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts))
539                         BMO_SetFlag(bm, (BMHeader*)v, DEL_INPUT);
540                 
541                 BM_remove_tagged_faces(bm, DEL_INPUT);
542                 BM_remove_tagged_edges(bm, DEL_INPUT);
543                 BM_remove_tagged_verts(bm, DEL_INPUT);
544         }
545 }