code cleanup: function naming, use BKE_*type* prefix.
[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
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(source_mesh, op, "boundarymap",
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(source_mesh, op, "facemap", source_face, target_face);
158         BMO_slot_map_ptr_insert(source_mesh, op, "facemap", 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 BKE_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_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh dupeops v");
201         ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "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(source, op, "isovertmap", 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_dupe_exec(BMesh *bm, BMOperator *op)
318 {
319         BMOperator *dupeop = op;
320         BMesh *bm2 = BMO_slot_ptr_get(op, "dest");
321         
322         if (!bm2)
323                 bm2 = bm;
324
325         /* flag input */
326         BMO_slot_buffer_flag_enable(bm, dupeop, "geom", BM_ALL, DUPE_INPUT);
327
328         /* use the internal copy function */
329         BKE_mesh_copy(dupeop, bm, bm2);
330         
331         /* Output */
332         /* First copy the input buffers to output buffers - original data */
333         BMO_slot_copy(dupeop, dupeop, "geom", "origout");
334
335         /* Now alloc the new output buffers */
336         BMO_slot_buffer_from_enabled_flag(bm, dupeop, "newout", BM_ALL, DUPE_NEW);
337 }
338
339 #if 0 /* UNUSED */
340 /* executes the duplicate operation, feeding elements of
341  * type flag etypeflag and header flag flag to it.  note,
342  * to get more useful information (such as the mapping from
343  * original to new elements) you should run the dupe op manually */
344 void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag)
345 {
346         BMOperator dupeop;
347
348         BMO_op_init(bm, &dupeop, "dupe");
349         BMO_slot_buffer_from_enabled_hflag(bm, &dupeop, "geom", htype, hflag);
350
351         BMO_op_exec(bm, &dupeop);
352         BMO_op_finish(bm, &dupeop);
353 }
354 #endif
355
356 /**
357  * Split Operator
358  *
359  * Duplicates verts, edges and faces of a mesh but also deletes the originals.
360  *
361  * INPUT SLOTS:
362  *
363  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
364  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
365  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
366  *
367  * OUTPUT SLOTS:
368  *
369  * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
370  * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
371  * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
372  */
373
374 #define SPLIT_INPUT 1
375
376 void bmo_split_exec(BMesh *bm, BMOperator *op)
377 {
378         BMOperator *splitop = op;
379         BMOperator dupeop;
380         BMOperator delop;
381         const short use_only_faces = BMO_slot_bool_get(op, "use_only_faces");
382
383         /* initialize our sub-operator */
384         BMO_op_init(bm, &dupeop, "dupe");
385         BMO_op_init(bm, &delop, "del");
386         
387         BMO_slot_copy(splitop, &dupeop, "geom", "geom");
388         BMO_op_exec(bm, &dupeop);
389         
390         BMO_slot_buffer_flag_enable(bm, splitop, "geom", BM_ALL, SPLIT_INPUT);
391
392         if (use_only_faces) {
393                 BMVert *v;
394                 BMEdge *e;
395                 BMFace *f;
396                 BMIter iter, iter2;
397                 int found;
398
399                 /* make sure to remove edges and verts we don't need */
400                 for (e = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e = BM_iter_step(&iter)) {
401                         found = 0;
402                         f = BM_iter_new(&iter2, bm, BM_FACES_OF_EDGE, e);
403                         for ( ; f; f = BM_iter_step(&iter2)) {
404                                 if (!BMO_elem_flag_test(bm, f, SPLIT_INPUT)) {
405                                         found = 1;
406                                         break;
407                                 }
408                         }
409                         if (!found) {
410                                 BMO_elem_flag_enable(bm, e, SPLIT_INPUT);
411                         }
412                 }
413
414                 for (v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v = BM_iter_step(&iter)) {
415                         found = 0;
416                         e = BM_iter_new(&iter2, bm, BM_EDGES_OF_VERT, v);
417                         for ( ; e; e = BM_iter_step(&iter2)) {
418                                 if (!BMO_elem_flag_test(bm, e, SPLIT_INPUT)) {
419                                         found = 1;
420                                         break;
421                                 }
422                         }
423                         if (!found) {
424                                 BMO_elem_flag_enable(bm, v, SPLIT_INPUT);
425                         }
426                 }
427         }
428
429         /* connect outputs of dupe to delete, exluding keep geometry */
430         BMO_slot_int_set(&delop, "context", DEL_FACES);
431         BMO_slot_buffer_from_enabled_flag(bm, &delop, "geom", BM_ALL, SPLIT_INPUT);
432         
433         BMO_op_exec(bm, &delop);
434
435         /* now we make our outputs by copying the dupe output */
436         BMO_slot_copy(&dupeop, splitop, "newout", "geomout");
437         BMO_slot_copy(&dupeop, splitop, "boundarymap", "boundarymap");
438         BMO_slot_copy(&dupeop, splitop, "isovertmap", "isovertmap");
439         
440         /* cleanup */
441         BMO_op_finish(bm, &delop);
442         BMO_op_finish(bm, &dupeop);
443 }
444
445
446 void bmo_del_exec(BMesh *bm, BMOperator *op)
447 {
448 #define DEL_INPUT 1
449
450         BMOperator *delop = op;
451
452         /* Mark Buffer */
453         BMO_slot_buffer_flag_enable(bm, delop, "geom", BM_ALL, DEL_INPUT);
454
455         BMO_remove_tagged_context(bm, DEL_INPUT, BMO_slot_int_get(op, "context"));
456
457 #undef DEL_INPUT
458 }
459
460 /**
461  * Spin Operator
462  *
463  * Extrude or duplicate geometry a number of times,
464  * rotating and possibly translating after each step
465  */
466
467 void bmo_spin_exec(BMesh *bm, BMOperator *op)
468 {
469         BMOperator dupop, extop;
470         float cent[3], dvec[3];
471         float axis[3] = {0.0f, 0.0f, 1.0f};
472         float rmat[3][3];
473         float phi;
474         int steps, do_dupli, a, usedvec;
475
476         BMO_slot_vec_get(op, "cent", cent);
477         BMO_slot_vec_get(op, "axis", axis);
478         normalize_v3(axis);
479         BMO_slot_vec_get(op, "dvec", dvec);
480         usedvec = !is_zero_v3(dvec);
481         steps = BMO_slot_int_get(op, "steps");
482         phi = BMO_slot_float_get(op, "ang") * DEG2RADF(1.0f) / steps;
483         do_dupli = BMO_slot_bool_get(op, "do_dupli");
484
485         axis_angle_to_mat3(rmat, axis, phi);
486
487         BMO_slot_copy(op, op, "geom", "lastout");
488         for (a = 0; a < steps; a++) {
489                 if (do_dupli) {
490                         BMO_op_initf(bm, &dupop, "dupe geom=%s", op, "lastout");
491                         BMO_op_exec(bm, &dupop);
492                         BMO_op_callf(bm, "rotate cent=%v mat=%m3 verts=%s",
493                                      cent, rmat, &dupop, "newout");
494                         BMO_slot_copy(&dupop, op, "newout", "lastout");
495                         BMO_op_finish(bm, &dupop);
496                 }
497                 else {
498                         BMO_op_initf(bm, &extop, "extrude_face_region edgefacein=%s",
499                                      op, "lastout");
500                         BMO_op_exec(bm, &extop);
501                         BMO_op_callf(bm, "rotate cent=%v mat=%m3 verts=%s",
502                                      cent, rmat, &extop, "geomout");
503                         BMO_slot_copy(&extop, op, "geomout", "lastout");
504                         BMO_op_finish(bm, &extop);
505                 }
506
507                 if (usedvec)
508                         BMO_op_callf(bm, "translate vec=%v verts=%s", dvec, op, "lastout");
509         }
510 }