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