2
* ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18
* Contributor(s): Joseph Eagar.
20
* ***** END GPL LICENSE BLOCK *****
23
/** \file blender/bmesh/operators/bmo_dupe.c
27
#include "MEM_guardedalloc.h"
29
#include "BLI_array.h"
34
#include "intern/bmesh_operators_private.h" /* own include */
36
/* local flag define */
37
#define DUPE_INPUT 1 /* input from operator */
45
* Copy an existing vertex from one bmesh to another.
47
static BMVert *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *target_mesh, GHash *vhash)
49
BMVert *target_vertex = NULL;
51
/* Create a new vertex */
52
target_vertex = BM_vert_create(target_mesh, source_vertex->co, NULL);
54
/* Insert new vertex into the vert hash */
55
BLI_ghash_insert(vhash, source_vertex, target_vertex);
58
BM_elem_attrs_copy(source_mesh, target_mesh, source_vertex, target_vertex);
60
/* Set internal op flags */
61
BMO_elem_flag_enable(target_mesh, target_vertex, DUPE_NEW);
69
* Copy an existing edge from one bmesh to another.
71
static BMEdge *copy_edge(BMOperator *op, BMesh *source_mesh,
72
BMEdge *source_edge, BMesh *target_mesh,
73
GHash *vhash, GHash *ehash)
75
BMEdge *target_edge = NULL;
76
BMVert *target_vert1, *target_vert2;
81
/* see if any of the neighboring faces are
82
* not being duplicated. in that case,
83
* add it to the new/old map. */
85
for (face = BM_iter_new(&fiter, source_mesh, BM_FACES_OF_EDGE, source_edge);
87
face = BM_iter_step(&fiter))
89
if (BMO_elem_flag_test(source_mesh, face, DUPE_INPUT)) {
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);
98
/* Create a new edge */
99
target_edge = BM_edge_create(target_mesh, target_vert1, target_vert2, NULL, FALSE);
101
/* add to new/old edge map if necassary */
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);
109
/* Insert new edge into the edge hash */
110
BLI_ghash_insert(ehash, source_edge, target_edge);
112
/* Copy attributes */
113
BM_elem_attrs_copy(source_mesh, target_mesh, source_edge, target_edge);
115
/* Set internal op flags */
116
BMO_elem_flag_enable(target_mesh, target_edge, DUPE_NEW);
124
* Copy an existing face from one bmesh to another.
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)
131
/* BMVert *target_vert1, *target_vert2; */ /* UNUSED */
132
BMLoop *source_loop, *target_loop;
133
BMFace *target_face = NULL;
137
/* lookup the first and second vert */
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));
142
BM_iter_new(&iter, source_mesh, BM_VERTS_OF_FACE, source_face);
147
for (i = 0, source_loop = BM_iter_new(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face);
149
source_loop = BM_iter_step(&iter), i++)
151
vtar[i] = BLI_ghash_lookup(vhash, source_loop->v);
152
edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
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);
160
BM_elem_attrs_copy(source_mesh, target_mesh, source_face, target_face);
162
/* mark the face for output */
163
BMO_elem_flag_enable(target_mesh, target_face, DUPE_NEW);
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);
181
* Internal Copy function.
184
static void copy_mesh(BMOperator *op, BMesh *source, BMesh *target)
187
BMVert *v = NULL, *v2;
191
BLI_array_declare(vtar);
192
BLI_array_declare(edar);
193
BMVert **vtar = NULL;
194
BMEdge **edar = NULL;
196
BMIter viter, eiter, fiter;
197
GHash *vhash, *ehash;
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");
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))
211
v2 = copy_vertex(source, v, target, vhash);
213
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
214
if (BMO_elem_flag_test(source, f, DUPE_INPUT)) {
221
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
222
if (BMO_elem_flag_test(source, e, DUPE_INPUT)) {
230
BMO_slot_map_ptr_insert(source, op, "isovertmap", v, v2);
233
BMO_elem_flag_enable(source, v, DUPE_DONE);
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))
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);
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);
251
/* now copy the actual edge */
252
copy_edge(op, source, e, target, vhash, ehash);
253
BMO_elem_flag_enable(source, e, DUPE_DONE);
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)) {
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);
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);
276
/* ensure arrays are the right size */
277
BLI_array_empty(vtar);
278
BLI_array_empty(edar);
280
BLI_array_growitems(vtar, f->len);
281
BLI_array_growitems(edar, f->len);
283
copy_face(op, source, f, target, vtar, edar, vhash, ehash);
284
BMO_elem_flag_enable(source, f, DUPE_DONE);
288
/* free pointer hashes */
289
BLI_ghash_free(vhash, NULL, NULL);
290
BLI_ghash_free(ehash, NULL, NULL);
292
BLI_array_free(vtar); /* free vert pointer array */
293
BLI_array_free(edar); /* free edge pointer array */
299
* Duplicates verts, edges and faces of a mesh.
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
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
317
void bmo_dupe_exec(BMesh *bm, BMOperator *op)
319
BMOperator *dupeop = op;
320
BMesh *bm2 = BMO_slot_ptr_get(op, "dest");
326
BMO_slot_buffer_flag_enable(bm, dupeop, "geom", BM_ALL, DUPE_INPUT);
328
/* use the internal copy function */
329
copy_mesh(dupeop, bm, bm2);
332
/* First copy the input buffers to output buffers - original data */
333
BMO_slot_copy(dupeop, dupeop, "geom", "origout");
335
/* Now alloc the new output buffers */
336
BMO_slot_buffer_from_enabled_flag(bm, dupeop, "newout", BM_ALL, DUPE_NEW);
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)
348
BMO_op_init(bm, &dupeop, "dupe");
349
BMO_slot_buffer_from_enabled_hflag(bm, &dupeop, "geom", htype, hflag);
351
BMO_op_exec(bm, &dupeop);
352
BMO_op_finish(bm, &dupeop);
359
* Duplicates verts, edges and faces of a mesh but also deletes the originals.
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
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
374
#define SPLIT_INPUT 1
376
void bmo_split_exec(BMesh *bm, BMOperator *op)
378
BMOperator *splitop = op;
381
const short use_only_faces = BMO_slot_bool_get(op, "use_only_faces");
383
/* initialize our sub-operator */
384
BMO_op_init(bm, &dupeop, "dupe");
385
BMO_op_init(bm, &delop, "del");
387
BMO_slot_copy(splitop, &dupeop, "geom", "geom");
388
BMO_op_exec(bm, &dupeop);
390
BMO_slot_buffer_flag_enable(bm, splitop, "geom", BM_ALL, SPLIT_INPUT);
392
if (use_only_faces) {
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)) {
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)) {
410
BMO_elem_flag_enable(bm, e, SPLIT_INPUT);
414
for (v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v = BM_iter_step(&iter)) {
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)) {
424
BMO_elem_flag_enable(bm, v, SPLIT_INPUT);
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);
433
BMO_op_exec(bm, &delop);
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");
441
BMO_op_finish(bm, &delop);
442
BMO_op_finish(bm, &dupeop);
446
void bmo_del_exec(BMesh *bm, BMOperator *op)
450
BMOperator *delop = op;
453
BMO_slot_buffer_flag_enable(bm, delop, "geom", BM_ALL, DEL_INPUT);
455
BMO_remove_tagged_context(bm, DEL_INPUT, BMO_slot_int_get(op, "context"));
463
* Extrude or duplicate geometry a number of times,
464
* rotating and possibly translating after each step
467
void bmo_spin_exec(BMesh *bm, BMOperator *op)
469
BMOperator dupop, extop;
470
float cent[3], dvec[3];
471
float axis[3] = {0.0f, 0.0f, 1.0f};
474
int steps, do_dupli, a, usedvec;
476
BMO_slot_vec_get(op, "cent", cent);
477
BMO_slot_vec_get(op, "axis", 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");
485
axis_angle_to_mat3(rmat, axis, phi);
487
BMO_slot_copy(op, op, "geom", "lastout");
488
for (a = 0; a < steps; a++) {
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);
498
BMO_op_initf(bm, &extop, "extrude_face_region edgefacein=%s",
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);
508
BMO_op_callf(bm, "translate vec=%v verts=%s", dvec, op, "lastout");