code cleanup: redundant includes and add minor comments.
[blender.git] / source / blender / bmesh / operators / bmo_dupe.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  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Eagar.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/operators/bmo_dupe.c
24  *  \ingroup bmesh
25  *
26  * Duplicate, Split, Split operators.
27  */
28
29 #include "BLI_math.h"
30 #include "BLI_alloca.h"
31
32 #include "bmesh.h"
33
34 #include "intern/bmesh_operators_private.h" /* own include */
35
36 /* local flag define */
37 #define DUPE_INPUT      1 /* input from operator */
38 #define DUPE_NEW        2
39 #define DUPE_DONE       4
40 // #define DUPE_MAPPED     8 // UNUSED
41
42 /**
43  * COPY VERTEX
44  *
45  * Copy an existing vertex from one bmesh to another.
46  */
47 static BMVert *bmo_vert_copy(BMOperator *op,
48                              BMOpSlot *slot_vertmap_out,
49                              BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash)
50 {
51         BMVert *v_dst;
52
53         /* Create a new vertex */
54         v_dst = BM_vert_create(bm_dst, v_src->co, NULL, BM_CREATE_SKIP_CD);
55         BMO_slot_map_elem_insert(op, slot_vertmap_out, v_src, v_dst);
56         BMO_slot_map_elem_insert(op, slot_vertmap_out, v_dst, v_src);
57
58         /* Insert new vertex into the vert hash */
59         BLI_ghash_insert(vhash, v_src, v_dst);
60
61         /* Copy attributes */
62         BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst);
63
64         /* Mark the vert for output */
65         BMO_elem_flag_enable(bm_dst, v_dst, DUPE_NEW);
66         
67         return v_dst;
68 }
69
70 /**
71  * COPY EDGE
72  *
73  * Copy an existing edge from one bmesh to another.
74  */
75 static BMEdge *bmo_edge_copy(BMOperator *op,
76                              BMOpSlot *slot_edgemap_out,
77                              BMOpSlot *slot_boundarymap_out,
78                              BMesh *bm_dst, BMesh *bm_src,
79                              BMEdge *e_src,
80                              GHash *vhash, GHash *ehash)
81 {
82         BMEdge *e_dst;
83         BMVert *e_dst_v1, *e_dst_v2;
84         unsigned int rlen;
85
86         /* see if any of the neighboring faces are
87          * not being duplicated.  in that case,
88          * add it to the new/old map. */
89         /* lookup edge */
90         rlen = 0;
91         if (e_src->l) {
92                 BMLoop *l_iter_src, *l_first_src;
93                 l_iter_src = l_first_src = e_src->l;
94                 do {
95                         if (BMO_elem_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) {
96                                 rlen++;
97                         }
98                 } while ((l_iter_src = l_iter_src->radial_next) != l_first_src);
99         }
100
101         /* Lookup v1 and v2 */
102         e_dst_v1 = BLI_ghash_lookup(vhash, e_src->v1);
103         e_dst_v2 = BLI_ghash_lookup(vhash, e_src->v2);
104         
105         /* Create a new edge */
106         e_dst = BM_edge_create(bm_dst, e_dst_v1, e_dst_v2, NULL, BM_CREATE_SKIP_CD);
107         BMO_slot_map_elem_insert(op, slot_edgemap_out, e_src, e_dst);
108         BMO_slot_map_elem_insert(op, slot_edgemap_out, e_dst, e_src);
109
110         /* add to new/old edge map if necassary */
111         if (rlen < 2) {
112                 /* not sure what non-manifold cases of greater then three
113                  * radial should do. */
114                 BMO_slot_map_elem_insert(op, slot_boundarymap_out, e_src, e_dst);
115         }
116
117         /* Insert new edge into the edge hash */
118         BLI_ghash_insert(ehash, e_src, e_dst);
119
120         /* Copy attributes */
121         BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst);
122
123         /* Mark the edge for output */
124         BMO_elem_flag_enable(bm_dst, e_dst, DUPE_NEW);
125         
126         return e_dst;
127 }
128
129 /**
130  * COPY FACE
131  *
132  * Copy an existing face from one bmesh to another.
133  */
134 static BMFace *bmo_face_copy(BMOperator *op,
135                              BMOpSlot *slot_facemap_out,
136                              BMesh *bm_dst, BMesh *bm_src,
137                              BMFace *f_src,
138                              GHash *vhash, GHash *ehash)
139 {
140         BMFace *f_dst;
141         BMVert **vtar = BLI_array_alloca(vtar, f_src->len);
142         BMEdge **edar = BLI_array_alloca(edar, f_src->len);
143         BMLoop *l_iter_src, *l_iter_dst, *l_first_src;
144         int i;
145
146         l_first_src = BM_FACE_FIRST_LOOP(f_src);
147
148         /* lookup edge */
149         l_iter_src = l_first_src;
150         i = 0;
151         do {
152                 vtar[i] = BLI_ghash_lookup(vhash, l_iter_src->v);
153                 edar[i] = BLI_ghash_lookup(ehash, l_iter_src->e);
154                 i++;
155         } while ((l_iter_src = l_iter_src->next) != l_first_src);
156
157         /* create new face */
158         f_dst = BM_face_create(bm_dst, vtar, edar, f_src->len, NULL, BM_CREATE_SKIP_CD);
159         BMO_slot_map_elem_insert(op, slot_facemap_out, f_src, f_dst);
160         BMO_slot_map_elem_insert(op, slot_facemap_out, f_dst, f_src);
161
162         /* Copy attributes */
163         BM_elem_attrs_copy(bm_src, bm_dst, f_src, f_dst);
164         
165         /* copy per-loop custom data */
166         l_iter_src = l_first_src;
167         l_iter_dst = BM_FACE_FIRST_LOOP(f_dst);
168         do {
169                 BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst);
170         } while ((l_iter_dst = l_iter_dst->next),
171                  (l_iter_src = l_iter_src->next) != l_first_src);
172
173         /* Mark the face for output */
174         BMO_elem_flag_enable(bm_dst, f_dst, DUPE_NEW);
175
176         return f_dst;
177 }
178
179 /**
180  * COPY MESH
181  *
182  * Internal Copy function.
183  */
184 static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
185 {
186
187         BMVert *v = NULL, *v2;
188         BMEdge *e = NULL;
189         BMFace *f = NULL;
190         
191         BMIter viter, eiter, fiter;
192         GHash *vhash, *ehash;
193
194         BMOpSlot *slot_boundary_map_out = BMO_slot_get(op->slots_out, "boundary_map.out");
195         BMOpSlot *slot_isovert_map_out  = BMO_slot_get(op->slots_out, "isovert_map.out");
196
197         BMOpSlot *slot_vert_map_out = BMO_slot_get(op->slots_out, "vert_map.out");
198         BMOpSlot *slot_edge_map_out = BMO_slot_get(op->slots_out, "edge_map.out");
199         BMOpSlot *slot_face_map_out = BMO_slot_get(op->slots_out, "face_map.out");
200
201         /* initialize pointer hashes */
202         vhash = BLI_ghash_ptr_new("bmesh dupeops v");
203         ehash = BLI_ghash_ptr_new("bmesh dupeops e");
204
205         /* duplicate flagged vertices */
206         BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) {
207                 if (BMO_elem_flag_test(bm_src, v, DUPE_INPUT) &&
208                     !BMO_elem_flag_test(bm_src, v, DUPE_DONE))
209                 {
210                         BMIter iter;
211                         bool isolated = true;
212
213                         v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash);
214
215                         BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
216                                 if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) {
217                                         isolated = false;
218                                         break;
219                                 }
220                         }
221
222                         if (isolated) {
223                                 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
224                                         if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT)) {
225                                                 isolated = false;
226                                                 break;
227                                         }
228                                 }
229                         }
230
231                         if (isolated) {
232                                 BMO_slot_map_elem_insert(op, slot_isovert_map_out, v, v2);
233                         }
234
235                         BMO_elem_flag_enable(bm_src, v, DUPE_DONE);
236                 }
237         }
238
239         /* now we dupe all the edges */
240         BM_ITER_MESH (e, &eiter, bm_src, BM_EDGES_OF_MESH) {
241                 if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT) &&
242                     !BMO_elem_flag_test(bm_src, e, DUPE_DONE))
243                 {
244                         /* make sure that verts are copied */
245                         if (!BMO_elem_flag_test(bm_src, e->v1, DUPE_DONE)) {
246                                 bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash);
247                                 BMO_elem_flag_enable(bm_src, e->v1, DUPE_DONE);
248                         }
249                         if (!BMO_elem_flag_test(bm_src, e->v2, DUPE_DONE)) {
250                                 bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash);
251                                 BMO_elem_flag_enable(bm_src, e->v2, DUPE_DONE);
252                         }
253                         /* now copy the actual edge */
254                         bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out,
255                                       bm_dst, bm_src, e, vhash, ehash);
256                         BMO_elem_flag_enable(bm_src, e, DUPE_DONE);
257                 }
258         }
259
260         /* first we dupe all flagged faces and their elements from source */
261         BM_ITER_MESH (f, &fiter, bm_src, BM_FACES_OF_MESH) {
262                 if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) {
263                         /* vertex pass */
264                         BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
265                                 if (!BMO_elem_flag_test(bm_src, v, DUPE_DONE)) {
266                                         bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash);
267                                         BMO_elem_flag_enable(bm_src, v, DUPE_DONE);
268                                 }
269                         }
270
271                         /* edge pass */
272                         BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
273                                 if (!BMO_elem_flag_test(bm_src, e, DUPE_DONE)) {
274                                         bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out,
275                                                       bm_dst, bm_src, e, vhash, ehash);
276                                         BMO_elem_flag_enable(bm_src, e, DUPE_DONE);
277                                 }
278                         }
279
280                         bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash);
281                         BMO_elem_flag_enable(bm_src, f, DUPE_DONE);
282                 }
283         }
284         
285         /* free pointer hashes */
286         BLI_ghash_free(vhash, NULL, NULL);
287         BLI_ghash_free(ehash, NULL, NULL);
288 }
289
290 /**
291  * Duplicate Operator
292  *
293  * Duplicates verts, edges and faces of a mesh.
294  *
295  * INPUT SLOTS:
296  *
297  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated
298  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated
299  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated
300  *
301  * OUTPUT SLOTS:
302  *
303  * BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices
304  * BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges
305  * BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces
306  * BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices
307  * BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges
308  * BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces
309  */
310 void bmo_duplicate_exec(BMesh *bm, BMOperator *op)
311 {
312         BMOperator *dupeop = op;
313         BMesh *bm_dst = BMO_slot_ptr_get(op->slots_in, "dest");
314         
315         if (!bm_dst)
316                 bm_dst = bm;
317
318         /* flag input */
319         BMO_slot_buffer_flag_enable(bm, dupeop->slots_in, "geom", BM_ALL_NOLOOP, DUPE_INPUT);
320
321         /* use the internal copy function */
322         bmo_mesh_copy(dupeop, bm_dst, bm);
323         
324         /* Output */
325         /* First copy the input buffers to output buffers - original data */
326         BMO_slot_copy(dupeop, slots_in,  "geom",
327                       dupeop, slots_out, "geom_orig.out");
328
329         /* Now alloc the new output buffers */
330         BMO_slot_buffer_from_enabled_flag(bm, dupeop, dupeop->slots_out, "geom.out", BM_ALL_NOLOOP, DUPE_NEW);
331 }
332
333 #if 0 /* UNUSED */
334 /* executes the duplicate operation, feeding elements of
335  * type flag etypeflag and header flag flag to it.  note,
336  * to get more useful information (such as the mapping from
337  * original to new elements) you should run the dupe op manually */
338 void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag)
339 {
340         BMOperator dupeop;
341
342         BMO_op_init(bm, &dupeop, "duplicate");
343         BMO_slot_buffer_from_enabled_hflag(bm, &dupeop, "geom", htype, hflag);
344
345         BMO_op_exec(bm, &dupeop);
346         BMO_op_finish(bm, &dupeop);
347 }
348 #endif
349
350 /**
351  * Split Operator
352  *
353  * Duplicates verts, edges and faces of a mesh but also deletes the originals.
354  *
355  * INPUT SLOTS:
356  *
357  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
358  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
359  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
360  *
361  * OUTPUT SLOTS:
362  *
363  * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
364  * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
365  * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
366  */
367 void bmo_split_exec(BMesh *bm, BMOperator *op)
368 {
369 #define SPLIT_INPUT 1
370
371         BMOperator *splitop = op;
372         BMOperator dupeop;
373         BMOperator delop;
374         const bool use_only_faces = BMO_slot_bool_get(op->slots_in, "use_only_faces");
375
376         /* initialize our sub-operator */
377         BMO_op_init(bm, &dupeop, op->flag, "duplicate");
378         BMO_op_init(bm, &delop, op->flag, "delete");
379         
380         BMO_slot_copy(splitop, slots_in, "geom",
381                       &dupeop, slots_in, "geom");
382         BMO_op_exec(bm, &dupeop);
383         
384         BMO_slot_buffer_flag_enable(bm, splitop->slots_in, "geom", BM_ALL_NOLOOP, SPLIT_INPUT);
385
386         if (use_only_faces) {
387                 BMVert *v;
388                 BMEdge *e;
389                 BMFace *f;
390                 BMIter iter, iter2;
391
392                 /* make sure to remove edges and verts we don't need */
393                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
394                         bool found = false;
395                         BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) {
396                                 if (!BMO_elem_flag_test(bm, f, SPLIT_INPUT)) {
397                                         found = true;
398                                         break;
399                                 }
400                         }
401                         if (found == false) {
402                                 BMO_elem_flag_enable(bm, e, SPLIT_INPUT);
403                         }
404                 }
405
406                 BM_ITER_MESH (v, &iter, bm,  BM_VERTS_OF_MESH) {
407                         bool found = false;
408                         BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
409                                 if (!BMO_elem_flag_test(bm, e, SPLIT_INPUT)) {
410                                         found = true;
411                                         break;
412                                 }
413                         }
414                         if (found == false) {
415                                 BMO_elem_flag_enable(bm, v, SPLIT_INPUT);
416                         }
417                 }
418         }
419
420         /* connect outputs of dupe to delete, exluding keep geometry */
421         BMO_slot_int_set(delop.slots_in, "context", DEL_FACES);
422         BMO_slot_buffer_from_enabled_flag(bm, &delop, delop.slots_in, "geom", BM_ALL_NOLOOP, SPLIT_INPUT);
423         
424         BMO_op_exec(bm, &delop);
425
426         /* now we make our outputs by copying the dupe output */
427         BMO_slot_copy(&dupeop, slots_out, "geom.out",
428                       splitop, slots_out, "geom.out");
429
430         BMO_slot_copy(&dupeop, slots_out, "boundary_map.out",
431                       splitop, slots_out, "boundary_map.out");
432
433         BMO_slot_copy(&dupeop, slots_out, "isovert_map.out",
434                       splitop, slots_out, "isovert_map.out");
435
436
437         /* cleanup */
438         BMO_op_finish(bm, &delop);
439         BMO_op_finish(bm, &dupeop);
440
441 #undef SPLIT_INPUT
442 }
443
444
445 void bmo_delete_exec(BMesh *bm, BMOperator *op)
446 {
447 #define DEL_INPUT 1
448
449         BMOperator *delop = op;
450
451         /* Mark Buffer */
452         BMO_slot_buffer_flag_enable(bm, delop->slots_in, "geom", BM_ALL_NOLOOP, DEL_INPUT);
453
454         BMO_remove_tagged_context(bm, DEL_INPUT, BMO_slot_int_get(op->slots_in, "context"));
455
456 #undef DEL_INPUT
457 }
458
459 /**
460  * Spin Operator
461  *
462  * Extrude or duplicate geometry a number of times,
463  * rotating and possibly translating after each step
464  */
465 void bmo_spin_exec(BMesh *bm, BMOperator *op)
466 {
467         BMOperator dupop, extop;
468         float cent[3], dvec[3];
469         float axis[3];
470         float rmat[3][3];
471         float phi;
472         int steps, do_dupli, a;
473         bool use_dvec;
474
475         BMO_slot_vec_get(op->slots_in, "cent", cent);
476         BMO_slot_vec_get(op->slots_in, "axis", axis);
477         normalize_v3(axis);
478         BMO_slot_vec_get(op->slots_in, "dvec", dvec);
479         use_dvec = !is_zero_v3(dvec);
480         steps    = BMO_slot_int_get(op->slots_in,   "steps");
481         phi      = BMO_slot_float_get(op->slots_in, "angle") / steps;
482         do_dupli = BMO_slot_bool_get(op->slots_in,  "use_duplicate");
483
484         axis_angle_normalized_to_mat3(rmat, axis, phi);
485
486         BMO_slot_copy(op, slots_in,  "geom",
487                       op, slots_out, "geom_last.out");
488         for (a = 0; a < steps; a++) {
489                 if (do_dupli) {
490                         BMO_op_initf(bm, &dupop, op->flag, "duplicate geom=%S", op, "geom_last.out");
491                         BMO_op_exec(bm, &dupop);
492                         BMO_op_callf(bm, op->flag,
493                                      "rotate cent=%v matrix=%m3 space=%s verts=%S",
494                                      cent, rmat, op, "space", &dupop, "geom.out");
495                         BMO_slot_copy(&dupop, slots_out, "geom.out",
496                                       op,     slots_out, "geom_last.out");
497                         BMO_op_finish(bm, &dupop);
498                 }
499                 else {
500                         BMO_op_initf(bm, &extop, op->flag, "extrude_face_region geom=%S",
501                                      op, "geom_last.out");
502                         BMO_op_exec(bm, &extop);
503                         BMO_op_callf(bm, op->flag,
504                                      "rotate cent=%v matrix=%m3 space=%s verts=%S",
505                                      cent, rmat, op, "space", &extop, "geom.out");
506                         BMO_slot_copy(&extop, slots_out, "geom.out",
507                                       op,     slots_out, "geom_last.out");
508                         BMO_op_finish(bm, &extop);
509                 }
510
511                 if (use_dvec) {
512                         mul_m3_v3(rmat, dvec);
513                         BMO_op_callf(bm, op->flag,
514                                      "translate vec=%v space=%s verts=%S",
515                                      dvec, op, "space", op, "geom_last.out");
516                 }
517         }
518 }