This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/bmesh/operators/bmo_dupe.c
Campbell Barton 90d215535e add option so operators can be called with a flag, currently the only flag is to respect hidden geometry.
this is useful for bmesh tools that operate in object mode or for modifiers which would previously use hidden faces in some cases.
2012-07-21 00:58:02 +00:00

517 lines
14 KiB
C

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/operators/bmo_dupe.c
* \ingroup bmesh
*/
#include "MEM_guardedalloc.h"
#include "BLI_array.h"
#include "BLI_math.h"
#include "bmesh.h"
#include "intern/bmesh_operators_private.h" /* own include */
/* local flag define */
#define DUPE_INPUT 1 /* input from operator */
#define DUPE_NEW 2
#define DUPE_DONE 4
#define DUPE_MAPPED 8
/**
* COPY VERTEX
*
* Copy an existing vertex from one bmesh to another.
*/
static BMVert *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *target_mesh, GHash *vhash)
{
BMVert *target_vertex = NULL;
/* Create a new vertex */
target_vertex = BM_vert_create(target_mesh, source_vertex->co, NULL);
/* Insert new vertex into the vert hash */
BLI_ghash_insert(vhash, source_vertex, target_vertex);
/* Copy attributes */
BM_elem_attrs_copy(source_mesh, target_mesh, source_vertex, target_vertex);
/* Set internal op flags */
BMO_elem_flag_enable(target_mesh, target_vertex, DUPE_NEW);
return target_vertex;
}
/**
* COPY EDGE
*
* Copy an existing edge from one bmesh to another.
*/
static BMEdge *copy_edge(BMOperator *op, BMesh *source_mesh,
BMEdge *source_edge, BMesh *target_mesh,
GHash *vhash, GHash *ehash)
{
BMEdge *target_edge = NULL;
BMVert *target_vert1, *target_vert2;
BMFace *face;
BMIter fiter;
int rlen;
/* see if any of the neighboring faces are
* not being duplicated. in that case,
* add it to the new/old map. */
rlen = 0;
for (face = BM_iter_new(&fiter, source_mesh, BM_FACES_OF_EDGE, source_edge);
face;
face = BM_iter_step(&fiter))
{
if (BMO_elem_flag_test(source_mesh, face, DUPE_INPUT)) {
rlen++;
}
}
/* Lookup v1 and v2 */
target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
/* Create a new edge */
target_edge = BM_edge_create(target_mesh, target_vert1, target_vert2, NULL, FALSE);
/* add to new/old edge map if necassary */
if (rlen < 2) {
/* not sure what non-manifold cases of greater then three
* radial should do. */
BMO_slot_map_ptr_insert(source_mesh, op, "boundarymap",
source_edge, target_edge);
}
/* Insert new edge into the edge hash */
BLI_ghash_insert(ehash, source_edge, target_edge);
/* Copy attributes */
BM_elem_attrs_copy(source_mesh, target_mesh, source_edge, target_edge);
/* Set internal op flags */
BMO_elem_flag_enable(target_mesh, target_edge, DUPE_NEW);
return target_edge;
}
/**
* COPY FACE
*
* Copy an existing face from one bmesh to another.
*/
static BMFace *copy_face(BMOperator *op, BMesh *source_mesh,
BMFace *source_face, BMesh *target_mesh,
BMVert **vtar, BMEdge **edar, GHash *vhash, GHash *ehash)
{
/* BMVert *target_vert1, *target_vert2; */ /* UNUSED */
BMLoop *source_loop, *target_loop;
BMFace *target_face = NULL;
BMIter iter, iter2;
int i;
/* lookup the first and second vert */
#if 0 /* UNUSED */
target_vert1 = BLI_ghash_lookup(vhash, BM_iter_new(&iter, source_mesh, BM_VERTS_OF_FACE, source_face));
target_vert2 = BLI_ghash_lookup(vhash, BM_iter_step(&iter));
#else
BM_iter_new(&iter, source_mesh, BM_VERTS_OF_FACE, source_face);
BM_iter_step(&iter);
#endif
/* lookup edge */
for (i = 0, source_loop = BM_iter_new(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face);
source_loop;
source_loop = BM_iter_step(&iter), i++)
{
vtar[i] = BLI_ghash_lookup(vhash, source_loop->v);
edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
}
/* create new face */
target_face = BM_face_create(target_mesh, vtar, edar, source_face->len, FALSE);
BMO_slot_map_ptr_insert(source_mesh, op, "facemap", source_face, target_face);
BMO_slot_map_ptr_insert(source_mesh, op, "facemap", target_face, source_face);
BM_elem_attrs_copy(source_mesh, target_mesh, source_face, target_face);
/* mark the face for output */
BMO_elem_flag_enable(target_mesh, target_face, DUPE_NEW);
/* copy per-loop custom data */
BM_ITER_ELEM (source_loop, &iter, source_face, BM_LOOPS_OF_FACE) {
BM_ITER_ELEM (target_loop, &iter2, target_face, BM_LOOPS_OF_FACE) {
if (BLI_ghash_lookup(vhash, source_loop->v) == target_loop->v) {
BM_elem_attrs_copy(source_mesh, target_mesh, source_loop, target_loop);
break;
}
}
}
return target_face;
}
/**
* COPY MESH
*
* Internal Copy function.
*/
static void BKE_mesh_copy(BMOperator *op, BMesh *source, BMesh *target)
{
BMVert *v = NULL, *v2;
BMEdge *e = NULL;
BMFace *f = NULL;
BLI_array_declare(vtar);
BLI_array_declare(edar);
BMVert **vtar = NULL;
BMEdge **edar = NULL;
BMIter viter, eiter, fiter;
GHash *vhash, *ehash;
/* initialize pointer hashes */
vhash = BLI_ghash_ptr_new("bmesh dupeops v");
ehash = BLI_ghash_ptr_new("bmesh dupeops e");
/* duplicate flagged vertices */
BM_ITER_MESH (v, &viter, source, BM_VERTS_OF_MESH) {
if (BMO_elem_flag_test(source, v, DUPE_INPUT) &&
!BMO_elem_flag_test(source, v, DUPE_DONE))
{
BMIter iter;
int isolated = 1;
v2 = copy_vertex(source, v, target, vhash);
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
if (BMO_elem_flag_test(source, f, DUPE_INPUT)) {
isolated = 0;
break;
}
}
if (isolated) {
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BMO_elem_flag_test(source, e, DUPE_INPUT)) {
isolated = 0;
break;
}
}
}
if (isolated) {
BMO_slot_map_ptr_insert(source, op, "isovertmap", v, v2);
}
BMO_elem_flag_enable(source, v, DUPE_DONE);
}
}
/* now we dupe all the edges */
BM_ITER_MESH (e, &eiter, source, BM_EDGES_OF_MESH) {
if (BMO_elem_flag_test(source, e, DUPE_INPUT) &&
!BMO_elem_flag_test(source, e, DUPE_DONE))
{
/* make sure that verts are copied */
if (!BMO_elem_flag_test(source, e->v1, DUPE_DONE)) {
copy_vertex(source, e->v1, target, vhash);
BMO_elem_flag_enable(source, e->v1, DUPE_DONE);
}
if (!BMO_elem_flag_test(source, e->v2, DUPE_DONE)) {
copy_vertex(source, e->v2, target, vhash);
BMO_elem_flag_enable(source, e->v2, DUPE_DONE);
}
/* now copy the actual edge */
copy_edge(op, source, e, target, vhash, ehash);
BMO_elem_flag_enable(source, e, DUPE_DONE);
}
}
/* first we dupe all flagged faces and their elements from source */
BM_ITER_MESH (f, &fiter, source, BM_FACES_OF_MESH) {
if (BMO_elem_flag_test(source, f, DUPE_INPUT)) {
/* vertex pass */
BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
if (!BMO_elem_flag_test(source, v, DUPE_DONE)) {
copy_vertex(source, v, target, vhash);
BMO_elem_flag_enable(source, v, DUPE_DONE);
}
}
/* edge pass */
BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
if (!BMO_elem_flag_test(source, e, DUPE_DONE)) {
copy_edge(op, source, e, target, vhash, ehash);
BMO_elem_flag_enable(source, e, DUPE_DONE);
}
}
/* ensure arrays are the right size */
BLI_array_empty(vtar);
BLI_array_empty(edar);
BLI_array_grow_items(vtar, f->len);
BLI_array_grow_items(edar, f->len);
copy_face(op, source, f, target, vtar, edar, vhash, ehash);
BMO_elem_flag_enable(source, f, DUPE_DONE);
}
}
/* free pointer hashes */
BLI_ghash_free(vhash, NULL, NULL);
BLI_ghash_free(ehash, NULL, NULL);
BLI_array_free(vtar); /* free vert pointer array */
BLI_array_free(edar); /* free edge pointer array */
}
/**
* Duplicate Operator
*
* Duplicates verts, edges and faces of a mesh.
*
* INPUT SLOTS:
*
* BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated
* BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated
* BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated
*
* OUTPUT SLOTS:
*
* BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices
* BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges
* BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces
* BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices
* BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges
* BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces
*/
void bmo_duplicate_exec(BMesh *bm, BMOperator *op)
{
BMOperator *dupeop = op;
BMesh *bm2 = BMO_slot_ptr_get(op, "dest");
if (!bm2)
bm2 = bm;
/* flag input */
BMO_slot_buffer_flag_enable(bm, dupeop, "geom", BM_ALL, DUPE_INPUT);
/* use the internal copy function */
BKE_mesh_copy(dupeop, bm, bm2);
/* Output */
/* First copy the input buffers to output buffers - original data */
BMO_slot_copy(dupeop, dupeop, "geom", "origout");
/* Now alloc the new output buffers */
BMO_slot_buffer_from_enabled_flag(bm, dupeop, "newout", BM_ALL, DUPE_NEW);
}
#if 0 /* UNUSED */
/* executes the duplicate operation, feeding elements of
* type flag etypeflag and header flag flag to it. note,
* to get more useful information (such as the mapping from
* original to new elements) you should run the dupe op manually */
void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag)
{
BMOperator dupeop;
BMO_op_init(bm, &dupeop, "duplicate");
BMO_slot_buffer_from_enabled_hflag(bm, &dupeop, "geom", htype, hflag);
BMO_op_exec(bm, &dupeop);
BMO_op_finish(bm, &dupeop);
}
#endif
/**
* Split Operator
*
* Duplicates verts, edges and faces of a mesh but also deletes the originals.
*
* INPUT SLOTS:
*
* BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
* BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
* BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
*
* OUTPUT SLOTS:
*
* BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
* BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
* BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
*/
#define SPLIT_INPUT 1
void bmo_split_exec(BMesh *bm, BMOperator *op)
{
BMOperator *splitop = op;
BMOperator dupeop;
BMOperator delop;
const short use_only_faces = BMO_slot_bool_get(op, "use_only_faces");
/* initialize our sub-operator */
BMO_op_init(bm, &dupeop, op->flag, "duplicate");
BMO_op_init(bm, &delop, op->flag, "delete");
BMO_slot_copy(splitop, &dupeop, "geom", "geom");
BMO_op_exec(bm, &dupeop);
BMO_slot_buffer_flag_enable(bm, splitop, "geom", BM_ALL, SPLIT_INPUT);
if (use_only_faces) {
BMVert *v;
BMEdge *e;
BMFace *f;
BMIter iter, iter2;
int found;
/* make sure to remove edges and verts we don't need */
for (e = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e = BM_iter_step(&iter)) {
found = 0;
f = BM_iter_new(&iter2, bm, BM_FACES_OF_EDGE, e);
for ( ; f; f = BM_iter_step(&iter2)) {
if (!BMO_elem_flag_test(bm, f, SPLIT_INPUT)) {
found = 1;
break;
}
}
if (!found) {
BMO_elem_flag_enable(bm, e, SPLIT_INPUT);
}
}
for (v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v = BM_iter_step(&iter)) {
found = 0;
e = BM_iter_new(&iter2, bm, BM_EDGES_OF_VERT, v);
for ( ; e; e = BM_iter_step(&iter2)) {
if (!BMO_elem_flag_test(bm, e, SPLIT_INPUT)) {
found = 1;
break;
}
}
if (!found) {
BMO_elem_flag_enable(bm, v, SPLIT_INPUT);
}
}
}
/* connect outputs of dupe to delete, exluding keep geometry */
BMO_slot_int_set(&delop, "context", DEL_FACES);
BMO_slot_buffer_from_enabled_flag(bm, &delop, "geom", BM_ALL, SPLIT_INPUT);
BMO_op_exec(bm, &delop);
/* now we make our outputs by copying the dupe output */
BMO_slot_copy(&dupeop, splitop, "newout", "geomout");
BMO_slot_copy(&dupeop, splitop, "boundarymap", "boundarymap");
BMO_slot_copy(&dupeop, splitop, "isovertmap", "isovertmap");
/* cleanup */
BMO_op_finish(bm, &delop);
BMO_op_finish(bm, &dupeop);
}
void bmo_delete_exec(BMesh *bm, BMOperator *op)
{
#define DEL_INPUT 1
BMOperator *delop = op;
/* Mark Buffer */
BMO_slot_buffer_flag_enable(bm, delop, "geom", BM_ALL, DEL_INPUT);
BMO_remove_tagged_context(bm, DEL_INPUT, BMO_slot_int_get(op, "context"));
#undef DEL_INPUT
}
/**
* Spin Operator
*
* Extrude or duplicate geometry a number of times,
* rotating and possibly translating after each step
*/
void bmo_spin_exec(BMesh *bm, BMOperator *op)
{
BMOperator dupop, extop;
float cent[3], dvec[3];
float axis[3] = {0.0f, 0.0f, 1.0f};
float rmat[3][3];
float phi;
int steps, do_dupli, a, usedvec;
BMO_slot_vec_get(op, "cent", cent);
BMO_slot_vec_get(op, "axis", axis);
normalize_v3(axis);
BMO_slot_vec_get(op, "dvec", dvec);
usedvec = !is_zero_v3(dvec);
steps = BMO_slot_int_get(op, "steps");
phi = BMO_slot_float_get(op, "ang") * DEG2RADF(1.0f) / steps;
do_dupli = BMO_slot_bool_get(op, "do_dupli");
axis_angle_to_mat3(rmat, axis, phi);
BMO_slot_copy(op, op, "geom", "lastout");
for (a = 0; a < steps; a++) {
if (do_dupli) {
BMO_op_initf(bm, &dupop, op->flag, "duplicate geom=%s", op, "lastout");
BMO_op_exec(bm, &dupop);
BMO_op_callf(bm, op->flag,
"rotate cent=%v mat=%m3 verts=%s",
cent, rmat, &dupop, "newout");
BMO_slot_copy(&dupop, op, "newout", "lastout");
BMO_op_finish(bm, &dupop);
}
else {
BMO_op_initf(bm, &extop, op->flag, "extrude_face_region edgefacein=%s",
op, "lastout");
BMO_op_exec(bm, &extop);
BMO_op_callf(bm, op->flag,
"rotate cent=%v mat=%m3 verts=%s",
cent, rmat, &extop, "geomout");
BMO_slot_copy(&extop, op, "geomout", "lastout");
BMO_op_finish(bm, &extop);
}
if (usedvec) {
mul_m3_v3(rmat, dvec);
BMO_op_callf(bm, op->flag,
"translate vec=%v verts=%s",
dvec, op, "lastout");
}
}
}