code cleanup: make bmesh operator names more consistant since python has access to...
[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
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_array.h"
30 #include "BLI_math.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 *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *target_mesh, GHash *vhash)
48 {
49         BMVert *target_vertex = NULL;
50
51         /* Create a new vertex */
52         target_vertex = BM_vert_create(target_mesh, source_vertex->co, NULL);
53         
54         /* Insert new vertex into the vert hash */
55         BLI_ghash_insert(vhash, source_vertex, target_vertex);
56         
57         /* Copy attributes */
58         BM_elem_attrs_copy(source_mesh, target_mesh, source_vertex, target_vertex);
59         
60         /* Set internal op flags */
61         BMO_elem_flag_enable(target_mesh, target_vertex, DUPE_NEW);
62         
63         return target_vertex;
64 }
65
66 /**
67  * COPY EDGE
68  *
69  * Copy an existing edge from one bmesh to another.
70  */
71 static BMEdge *copy_edge(BMOperator *op, BMesh *source_mesh,
72                          BMEdge *source_edge, BMesh *target_mesh,
73                          GHash *vhash, GHash *ehash)
74 {
75         BMEdge *target_edge = NULL;
76         BMVert *target_vert1, *target_vert2;
77         BMFace *face;
78         BMIter fiter;
79         int rlen;
80
81         /* see if any of the neighboring faces are
82          * not being duplicated.  in that case,
83          * add it to the new/old map. */
84         rlen = 0;
85         for (face = BM_iter_new(&fiter, source_mesh, BM_FACES_OF_EDGE, source_edge);
86              face;
87              face = BM_iter_step(&fiter))
88         {
89                 if (BMO_elem_flag_test(source_mesh, face, DUPE_INPUT)) {
90                         rlen++;
91                 }
92         }
93
94         /* Lookup v1 and v2 */
95         target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
96         target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
97         
98         /* Create a new edge */
99         target_edge = BM_edge_create(target_mesh, target_vert1, target_vert2, NULL, FALSE);
100         
101         /* add to new/old edge map if necassary */
102         if (rlen < 2) {
103                 /* not sure what non-manifold cases of greater then three
104                  * radial should do. */
105                 BMO_slot_map_ptr_insert(op, op->slots_out, "boundarymap.out",
106                                         source_edge, target_edge);
107         }
108
109         /* Insert new edge into the edge hash */
110         BLI_ghash_insert(ehash, source_edge, target_edge);
111         
112         /* Copy attributes */
113         BM_elem_attrs_copy(source_mesh, target_mesh, source_edge, target_edge);
114         
115         /* Set internal op flags */
116         BMO_elem_flag_enable(target_mesh, target_edge, DUPE_NEW);
117         
118         return target_edge;
119 }
120
121 /**
122  * COPY FACE
123  *
124  * Copy an existing face from one bmesh to another.
125  */
126
127 static BMFace *copy_face(BMOperator *op, BMesh *source_mesh,
128                          BMFace *source_face, BMesh *target_mesh,
129                          BMVert **vtar, BMEdge **edar, GHash *vhash, GHash *ehash)
130 {
131         /* BMVert *target_vert1, *target_vert2; */ /* UNUSED */
132         BMLoop *source_loop, *target_loop;
133         BMFace *target_face = NULL;
134         BMIter iter, iter2;
135         int i;
136         
137         /* lookup the first and second vert */
138 #if 0 /* UNUSED */
139         target_vert1 = BLI_ghash_lookup(vhash, BM_iter_new(&iter, source_mesh, BM_VERTS_OF_FACE, source_face));
140         target_vert2 = BLI_ghash_lookup(vhash, BM_iter_step(&iter));
141 #else
142         BM_iter_new(&iter, source_mesh, BM_VERTS_OF_FACE, source_face);
143         BM_iter_step(&iter);
144 #endif
145
146         /* lookup edge */
147         for (i = 0, source_loop = BM_iter_new(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face);
148              source_loop;
149              source_loop = BM_iter_step(&iter), i++)
150         {
151                 vtar[i] = BLI_ghash_lookup(vhash, source_loop->v);
152                 edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
153         }
154         
155         /* create new face */
156         target_face = BM_face_create(target_mesh, vtar, edar, source_face->len, FALSE);
157         BMO_slot_map_ptr_insert(op, op->slots_out, "facemap.out", source_face, target_face);
158         BMO_slot_map_ptr_insert(op, op->slots_out, "facemap.out", target_face, source_face);
159
160         BM_elem_attrs_copy(source_mesh, target_mesh, source_face, target_face);
161
162         /* mark the face for output */
163         BMO_elem_flag_enable(target_mesh, target_face, DUPE_NEW);
164         
165         /* copy per-loop custom data */
166         BM_ITER_ELEM (source_loop, &iter, source_face, BM_LOOPS_OF_FACE) {
167                 BM_ITER_ELEM (target_loop, &iter2, target_face, BM_LOOPS_OF_FACE) {
168                         if (BLI_ghash_lookup(vhash, source_loop->v) == target_loop->v) {
169                                 BM_elem_attrs_copy(source_mesh, target_mesh, source_loop, target_loop);
170                                 break;
171                         }
172                 }
173         }
174
175         return target_face;
176 }
177
178 /**
179  * COPY MESH
180  *
181  * Internal Copy function.
182  */
183
184 static void bmo_mesh_copy(BMOperator *op, BMesh *source, BMesh *target)
185 {
186
187         BMVert *v = NULL, *v2;
188         BMEdge *e = NULL;
189         BMFace *f = NULL;
190
191         BLI_array_declare(vtar);
192         BLI_array_declare(edar);
193         BMVert **vtar = NULL;
194         BMEdge **edar = NULL;
195         
196         BMIter viter, eiter, fiter;
197         GHash *vhash, *ehash;
198
199         /* initialize pointer hashes */
200         vhash = BLI_ghash_ptr_new("bmesh dupeops v");
201         ehash = BLI_ghash_ptr_new("bmesh dupeops e");
202
203         /* duplicate flagged vertices */
204         BM_ITER_MESH (v, &viter, source, BM_VERTS_OF_MESH) {
205                 if (BMO_elem_flag_test(source, v, DUPE_INPUT) &&
206                     !BMO_elem_flag_test(source, v, DUPE_DONE))
207                 {
208                         BMIter iter;
209                         int isolated = 1;
210
211                         v2 = copy_vertex(source, v, target, vhash);
212
213                         BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
214                                 if (BMO_elem_flag_test(source, f, DUPE_INPUT)) {
215                                         isolated = 0;
216                                         break;
217                                 }
218                         }
219
220                         if (isolated) {
221                                 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
222                                         if (BMO_elem_flag_test(source, e, DUPE_INPUT)) {
223                                                 isolated = 0;
224                                                 break;
225                                         }
226                                 }
227                         }
228
229                         if (isolated) {
230                                 BMO_slot_map_ptr_insert(op, op->slots_out, "isovertmap.out", v, v2);
231                         }
232
233                         BMO_elem_flag_enable(source, v, DUPE_DONE);
234                 }
235         }
236
237         /* now we dupe all the edges */
238         BM_ITER_MESH (e, &eiter, source, BM_EDGES_OF_MESH) {
239                 if (BMO_elem_flag_test(source, e, DUPE_INPUT) &&
240                     !BMO_elem_flag_test(source, e, DUPE_DONE))
241                 {
242                         /* make sure that verts are copied */
243                         if (!BMO_elem_flag_test(source, e->v1, DUPE_DONE)) {
244                                 copy_vertex(source, e->v1, target, vhash);
245                                 BMO_elem_flag_enable(source, e->v1, DUPE_DONE);
246                         }
247                         if (!BMO_elem_flag_test(source, e->v2, DUPE_DONE)) {
248                                 copy_vertex(source, e->v2, target, vhash);
249                                 BMO_elem_flag_enable(source, e->v2, DUPE_DONE);
250                         }
251                         /* now copy the actual edge */
252                         copy_edge(op, source, e, target, vhash, ehash);
253                         BMO_elem_flag_enable(source, e, DUPE_DONE);
254                 }
255         }
256
257         /* first we dupe all flagged faces and their elements from source */
258         BM_ITER_MESH (f, &fiter, source, BM_FACES_OF_MESH) {
259                 if (BMO_elem_flag_test(source, f, DUPE_INPUT)) {
260                         /* vertex pass */
261                         BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
262                                 if (!BMO_elem_flag_test(source, v, DUPE_DONE)) {
263                                         copy_vertex(source, v, target, vhash);
264                                         BMO_elem_flag_enable(source, v, DUPE_DONE);
265                                 }
266                         }
267
268                         /* edge pass */
269                         BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
270                                 if (!BMO_elem_flag_test(source, e, DUPE_DONE)) {
271                                         copy_edge(op, source, e, target, vhash, ehash);
272                                         BMO_elem_flag_enable(source, e, DUPE_DONE);
273                                 }
274                         }
275
276                         /* ensure arrays are the right size */
277                         BLI_array_empty(vtar);
278                         BLI_array_empty(edar);
279
280                         BLI_array_grow_items(vtar, f->len);
281                         BLI_array_grow_items(edar, f->len);
282
283                         copy_face(op, source, f, target, vtar, edar, vhash, ehash);
284                         BMO_elem_flag_enable(source, f, DUPE_DONE);
285                 }
286         }
287         
288         /* free pointer hashes */
289         BLI_ghash_free(vhash, NULL, NULL);
290         BLI_ghash_free(ehash, NULL, NULL);
291
292         BLI_array_free(vtar); /* free vert pointer array */
293         BLI_array_free(edar); /* free edge pointer array */
294 }
295
296 /**
297  * Duplicate Operator
298  *
299  * Duplicates verts, edges and faces of a mesh.
300  *
301  * INPUT SLOTS:
302  *
303  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated
304  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated
305  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated
306  *
307  * OUTPUT SLOTS:
308  *
309  * BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices
310  * BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges
311  * BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces
312  * BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices
313  * BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges
314  * BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces
315  */
316
317 void bmo_duplicate_exec(BMesh *bm, BMOperator *op)
318 {
319         BMOperator *dupeop = op;
320         BMesh *bm2 = BMO_slot_ptr_get(op->slots_in, "dest");
321         
322         if (!bm2)
323                 bm2 = bm;
324
325         /* flag input */
326         BMO_slot_buffer_flag_enable(bm, dupeop->slots_in, "geom", BM_ALL, DUPE_INPUT);
327
328         /* use the internal copy function */
329         bmo_mesh_copy(dupeop, bm, bm2);
330         
331         /* Output */
332         /* First copy the input buffers to output buffers - original data */
333         BMO_slot_copy(dupeop, slots_in,  "geom",
334                       dupeop, slots_out, "geom_orig.out");
335
336         /* Now alloc the new output buffers */
337         BMO_slot_buffer_from_enabled_flag(bm, dupeop, dupeop->slots_out, "geom.out", BM_ALL, DUPE_NEW);
338 }
339
340 #if 0 /* UNUSED */
341 /* executes the duplicate operation, feeding elements of
342  * type flag etypeflag and header flag flag to it.  note,
343  * to get more useful information (such as the mapping from
344  * original to new elements) you should run the dupe op manually */
345 void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag)
346 {
347         BMOperator dupeop;
348
349         BMO_op_init(bm, &dupeop, "duplicate");
350         BMO_slot_buffer_from_enabled_hflag(bm, &dupeop, "geom", htype, hflag);
351
352         BMO_op_exec(bm, &dupeop);
353         BMO_op_finish(bm, &dupeop);
354 }
355 #endif
356
357 /**
358  * Split Operator
359  *
360  * Duplicates verts, edges and faces of a mesh but also deletes the originals.
361  *
362  * INPUT SLOTS:
363  *
364  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
365  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
366  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
367  *
368  * OUTPUT SLOTS:
369  *
370  * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
371  * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
372  * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
373  */
374
375 #define SPLIT_INPUT 1
376
377 void bmo_split_exec(BMesh *bm, BMOperator *op)
378 {
379         BMOperator *splitop = op;
380         BMOperator dupeop;
381         BMOperator delop;
382         const short use_only_faces = BMO_slot_bool_get(op->slots_in, "use_only_faces");
383
384         /* initialize our sub-operator */
385         BMO_op_init(bm, &dupeop, op->flag, "duplicate");
386         BMO_op_init(bm, &delop, op->flag, "delete");
387         
388         BMO_slot_copy(splitop, slots_in, "geom",
389                       &dupeop, slots_in, "geom");
390         BMO_op_exec(bm, &dupeop);
391         
392         BMO_slot_buffer_flag_enable(bm, splitop->slots_in, "geom", BM_ALL, SPLIT_INPUT);
393
394         if (use_only_faces) {
395                 BMVert *v;
396                 BMEdge *e;
397                 BMFace *f;
398                 BMIter iter, iter2;
399                 int found;
400
401                 /* make sure to remove edges and verts we don't need */
402                 for (e = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e = BM_iter_step(&iter)) {
403                         found = 0;
404                         f = BM_iter_new(&iter2, bm, BM_FACES_OF_EDGE, e);
405                         for ( ; f; f = BM_iter_step(&iter2)) {
406                                 if (!BMO_elem_flag_test(bm, f, SPLIT_INPUT)) {
407                                         found = 1;
408                                         break;
409                                 }
410                         }
411                         if (!found) {
412                                 BMO_elem_flag_enable(bm, e, SPLIT_INPUT);
413                         }
414                 }
415
416                 for (v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v = BM_iter_step(&iter)) {
417                         found = 0;
418                         e = BM_iter_new(&iter2, bm, BM_EDGES_OF_VERT, v);
419                         for ( ; e; e = BM_iter_step(&iter2)) {
420                                 if (!BMO_elem_flag_test(bm, e, SPLIT_INPUT)) {
421                                         found = 1;
422                                         break;
423                                 }
424                         }
425                         if (!found) {
426                                 BMO_elem_flag_enable(bm, v, SPLIT_INPUT);
427                         }
428                 }
429         }
430
431         /* connect outputs of dupe to delete, exluding keep geometry */
432         BMO_slot_int_set(delop.slots_in, "context", DEL_FACES);
433         BMO_slot_buffer_from_enabled_flag(bm, &delop, delop.slots_in, "geom", BM_ALL, SPLIT_INPUT);
434         
435         BMO_op_exec(bm, &delop);
436
437         /* now we make our outputs by copying the dupe output */
438         BMO_slot_copy(&dupeop, slots_out, "geom.out",
439                       splitop, slots_out, "geom.out");
440
441         BMO_slot_copy(&dupeop, slots_out, "boundarymap.out",
442                       splitop, slots_out, "boundarymap.out");
443
444         BMO_slot_copy(&dupeop, slots_out, "isovertmap.out",
445                       splitop, slots_out, "isovertmap.out");
446
447
448         /* cleanup */
449         BMO_op_finish(bm, &delop);
450         BMO_op_finish(bm, &dupeop);
451 }
452
453
454 void bmo_delete_exec(BMesh *bm, BMOperator *op)
455 {
456 #define DEL_INPUT 1
457
458         BMOperator *delop = op;
459
460         /* Mark Buffer */
461         BMO_slot_buffer_flag_enable(bm, delop->slots_in, "geom", BM_ALL, DEL_INPUT);
462
463         BMO_remove_tagged_context(bm, DEL_INPUT, BMO_slot_int_get(op->slots_in, "context"));
464
465 #undef DEL_INPUT
466 }
467
468 /**
469  * Spin Operator
470  *
471  * Extrude or duplicate geometry a number of times,
472  * rotating and possibly translating after each step
473  */
474
475 void bmo_spin_exec(BMesh *bm, BMOperator *op)
476 {
477         BMOperator dupop, extop;
478         float cent[3], dvec[3];
479         float axis[3] = {0.0f, 0.0f, 1.0f};
480         float rmat[3][3];
481         float phi;
482         int steps, do_dupli, a, usedvec;
483
484         BMO_slot_vec_get(op->slots_in, "cent", cent);
485         BMO_slot_vec_get(op->slots_in, "axis", axis);
486         normalize_v3(axis);
487         BMO_slot_vec_get(op->slots_in, "dvec", dvec);
488         usedvec = !is_zero_v3(dvec);
489         steps    = BMO_slot_int_get(op->slots_in,   "steps");
490         phi      = BMO_slot_float_get(op->slots_in, "angle") * DEG2RADF(1.0f) / steps;
491         do_dupli = BMO_slot_bool_get(op->slots_in,  "use_duplicate");
492
493         axis_angle_to_mat3(rmat, axis, phi);
494
495         BMO_slot_copy(op, slots_in,  "geom",
496                       op, slots_out, "geom_last.out");
497         for (a = 0; a < steps; a++) {
498                 if (do_dupli) {
499                         BMO_op_initf(bm, &dupop, op->flag, "duplicate geom=%S", op, "geom_last.out");
500                         BMO_op_exec(bm, &dupop);
501                         BMO_op_callf(bm, op->flag,
502                                      "rotate cent=%v mat=%m3 verts=%S",
503                                      cent, rmat, &dupop, "geom.out");
504                         BMO_slot_copy(&dupop, slots_out, "geom.out",
505                                       op,     slots_out, "geom_last.out");
506                         BMO_op_finish(bm, &dupop);
507                 }
508                 else {
509                         BMO_op_initf(bm, &extop, op->flag, "extrude_face_region geom=%S",
510                                      op, "geom_last.out");
511                         BMO_op_exec(bm, &extop);
512                         BMO_op_callf(bm, op->flag,
513                                      "rotate cent=%v mat=%m3 verts=%S",
514                                      cent, rmat, &extop, "geom.out");
515                         BMO_slot_copy(&extop, slots_out, "geom.out",
516                                       op,     slots_out, "geom_last.out");
517                         BMO_op_finish(bm, &extop);
518                 }
519
520                 if (usedvec) {
521                         mul_m3_v3(rmat, dvec);
522                         BMO_op_callf(bm, op->flag,
523                                      "translate vec=%v verts=%S",
524                                      dvec, op, "geom_last.out");
525                 }
526         }
527 }