2012-02-19 18:31:04 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup bmesh
|
2013-03-30 08:54:50 +00:00
|
|
|
*
|
|
|
|
* Extrude faces and solidify.
|
2012-04-06 09:21:19 +00:00
|
|
|
*/
|
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2012-05-22 15:30:05 +00:00
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
#include "BLI_math.h"
|
2013-03-16 00:41:32 +00:00
|
|
|
#include "BLI_buffer.h"
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-05-22 15:30:05 +00:00
|
|
|
#include "BKE_customdata.h"
|
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
#include "bmesh.h"
|
|
|
|
|
2012-03-08 03:25:53 +00:00
|
|
|
#include "intern/bmesh_operators_private.h" /* own include */
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2015-05-22 10:56:54 +10:00
|
|
|
#define USE_EDGE_REGION_FLAGS
|
|
|
|
|
2012-03-01 16:04:37 +00:00
|
|
|
enum {
|
|
|
|
EXT_INPUT = 1,
|
|
|
|
EXT_KEEP = 2,
|
2019-01-15 23:57:49 +11:00
|
|
|
EXT_DEL = 4,
|
2012-03-01 16:04:37 +00:00
|
|
|
};
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
#define VERT_MARK 1
|
|
|
|
#define EDGE_MARK 1
|
|
|
|
#define FACE_MARK 1
|
|
|
|
#define VERT_NONMAN 2
|
|
|
|
#define EDGE_NONMAN 2
|
|
|
|
|
2012-06-30 15:27:13 +00:00
|
|
|
void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2014-08-25 16:48:47 +10:00
|
|
|
const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
|
|
|
|
GHash *select_history_map = NULL;
|
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
BMOIter siter;
|
2013-07-19 11:45:21 +00:00
|
|
|
BMFace *f_org;
|
|
|
|
|
2014-08-25 16:48:47 +10:00
|
|
|
if (use_select_history) {
|
|
|
|
select_history_map = BM_select_history_map_create(bm);
|
|
|
|
}
|
|
|
|
|
2013-07-19 11:45:21 +00:00
|
|
|
BMO_ITER (f_org, &siter, op->slots_in, "faces", BM_FACE) {
|
|
|
|
BMFace *f_new;
|
|
|
|
BMLoop *l_org, *l_org_first;
|
|
|
|
BMLoop *l_new;
|
|
|
|
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_face_flag_enable(bm, f_org, EXT_DEL);
|
2013-07-19 11:45:21 +00:00
|
|
|
|
|
|
|
f_new = BM_face_copy(bm, bm, f_org, true, true);
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_face_flag_enable(bm, f_new, EXT_KEEP);
|
2013-07-19 11:45:21 +00:00
|
|
|
|
2014-08-25 16:48:47 +10:00
|
|
|
if (select_history_map) {
|
|
|
|
BMEditSelection *ese;
|
|
|
|
ese = BLI_ghash_lookup(select_history_map, f_org);
|
|
|
|
if (ese) {
|
|
|
|
ese->ele = (BMElem *)f_new;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-19 11:45:21 +00:00
|
|
|
l_org = l_org_first = BM_FACE_FIRST_LOOP(f_org);
|
|
|
|
l_new = BM_FACE_FIRST_LOOP(f_new);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2013-07-19 11:45:21 +00:00
|
|
|
do {
|
|
|
|
BMFace *f_side;
|
|
|
|
BMLoop *l_side_iter;
|
|
|
|
|
|
|
|
BM_elem_attrs_copy(bm, bm, l_org, l_new);
|
|
|
|
|
|
|
|
f_side = BM_face_create_quad_tri(bm,
|
|
|
|
l_org->next->v, l_new->next->v, l_new->v, l_org->v,
|
2013-08-21 07:51:47 +00:00
|
|
|
f_org, BM_CREATE_NOP);
|
2013-07-19 11:45:21 +00:00
|
|
|
|
|
|
|
l_side_iter = BM_FACE_FIRST_LOOP(f_side);
|
|
|
|
|
|
|
|
BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); l_side_iter = l_side_iter->next;
|
|
|
|
BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); l_side_iter = l_side_iter->next;
|
|
|
|
BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); l_side_iter = l_side_iter->next;
|
|
|
|
BM_elem_attrs_copy(bm, bm, l_org, l_side_iter);
|
2014-08-25 16:48:47 +10:00
|
|
|
|
|
|
|
if (select_history_map) {
|
|
|
|
BMEditSelection *ese;
|
|
|
|
|
|
|
|
ese = BLI_ghash_lookup(select_history_map, l_org->v);
|
|
|
|
if (ese) {
|
|
|
|
ese->ele = (BMElem *)l_new->v;
|
|
|
|
}
|
|
|
|
ese = BLI_ghash_lookup(select_history_map, l_org->e);
|
|
|
|
if (ese) {
|
|
|
|
ese->ele = (BMElem *)l_new->e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-05 09:16:12 +11:00
|
|
|
} while (((void)
|
|
|
|
(l_new = l_new->next),
|
2013-07-19 11:45:21 +00:00
|
|
|
(l_org = l_org->next)) != l_org_first);
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2014-08-25 16:48:47 +10:00
|
|
|
if (select_history_map) {
|
|
|
|
BLI_ghash_free(select_history_map, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
2012-07-21 00:58:02 +00:00
|
|
|
BMO_op_callf(bm, op->flag,
|
|
|
|
"delete geom=%ff context=%i",
|
|
|
|
EXT_DEL, DEL_ONLYFACES);
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, EXT_KEEP);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2012-04-18 19:05:28 +00:00
|
|
|
/**
|
|
|
|
* \brief Copy the loop pair from an adjacent face to both sides of this quad.
|
|
|
|
*
|
|
|
|
* The face is assumed to be a quad, created by extruding.
|
|
|
|
* This function won't crash if its not but won't work right either.
|
|
|
|
* \a e_b is the new edge.
|
|
|
|
*
|
2015-09-14 02:21:15 +10:00
|
|
|
* \note The edge this face comes from needs to be from the first and second verts to the face.
|
2012-10-28 16:17:20 +00:00
|
|
|
* The caller must ensure this else we will copy from the wrong source.
|
2012-04-18 19:05:28 +00:00
|
|
|
*/
|
2012-10-28 16:17:20 +00:00
|
|
|
static void bm_extrude_copy_face_loop_attributes(BMesh *bm, BMFace *f)
|
2012-03-20 17:02:03 +00:00
|
|
|
{
|
2012-10-28 16:17:20 +00:00
|
|
|
/* edge we are extruded from */
|
|
|
|
BMLoop *l_first_0 = BM_FACE_FIRST_LOOP(f);
|
|
|
|
BMLoop *l_first_1 = l_first_0->next;
|
|
|
|
BMLoop *l_first_2 = l_first_1->next;
|
|
|
|
BMLoop *l_first_3 = l_first_2->next;
|
|
|
|
|
|
|
|
BMLoop *l_other_0;
|
|
|
|
BMLoop *l_other_1;
|
|
|
|
|
|
|
|
if (UNLIKELY(l_first_0 == l_first_0->radial_next)) {
|
2012-04-18 19:05:28 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-03-20 17:02:03 +00:00
|
|
|
|
2012-10-28 16:17:20 +00:00
|
|
|
l_other_0 = BM_edge_other_loop(l_first_0->e, l_first_0);
|
|
|
|
l_other_1 = BM_edge_other_loop(l_first_0->e, l_first_1);
|
2012-03-20 17:02:03 +00:00
|
|
|
|
2012-04-18 09:56:19 +00:00
|
|
|
/* copy data */
|
2012-10-28 16:17:20 +00:00
|
|
|
BM_elem_attrs_copy(bm, bm, l_other_0->f, f);
|
|
|
|
BM_elem_flag_disable(f, BM_ELEM_HIDDEN); /* possibly we copy from a hidden face */
|
|
|
|
|
|
|
|
BM_elem_attrs_copy(bm, bm, l_other_0, l_first_0);
|
|
|
|
BM_elem_attrs_copy(bm, bm, l_other_0, l_first_3);
|
2012-04-18 09:56:19 +00:00
|
|
|
|
2012-10-28 16:17:20 +00:00
|
|
|
BM_elem_attrs_copy(bm, bm, l_other_1, l_first_1);
|
|
|
|
BM_elem_attrs_copy(bm, bm, l_other_1, l_first_2);
|
2012-03-20 17:02:03 +00:00
|
|
|
}
|
|
|
|
|
2012-05-22 15:30:05 +00:00
|
|
|
/* Disable the skin root flag on the input vert, assumes that the vert
|
2012-06-30 22:49:33 +00:00
|
|
|
* data includes an CD_MVERT_SKIN layer */
|
2012-05-22 15:30:05 +00:00
|
|
|
static void bm_extrude_disable_skin_root(BMesh *bm, BMVert *v)
|
|
|
|
{
|
|
|
|
MVertSkin *vs;
|
2018-06-04 08:48:38 +02:00
|
|
|
|
2012-05-22 15:30:05 +00:00
|
|
|
vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN);
|
|
|
|
vs->flag &= ~MVERT_SKIN_ROOT;
|
|
|
|
}
|
|
|
|
|
2012-02-28 09:48:00 +00:00
|
|
|
void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
BMOIter siter;
|
|
|
|
BMOperator dupeop;
|
|
|
|
BMFace *f;
|
2012-10-28 16:17:20 +00:00
|
|
|
BMEdge *e, *e_new;
|
2018-09-25 13:31:29 +10:00
|
|
|
const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
|
2018-06-04 08:48:38 +02:00
|
|
|
|
2012-11-19 14:58:31 +00:00
|
|
|
BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_edge_flag_enable(bm, e, EXT_INPUT);
|
|
|
|
BMO_vert_flag_enable(bm, e->v1, EXT_INPUT);
|
|
|
|
BMO_vert_flag_enable(bm, e->v2, EXT_INPUT);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-25 16:48:47 +10:00
|
|
|
BMO_op_initf(
|
|
|
|
bm, &dupeop, op->flag,
|
|
|
|
"duplicate geom=%fve use_select_history=%b",
|
|
|
|
EXT_INPUT, BMO_slot_bool_get(op->slots_in, "use_select_history"));
|
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
BMO_op_exec(bm, &dupeop);
|
|
|
|
|
2012-05-22 15:30:05 +00:00
|
|
|
/* disable root flag on all new skin nodes */
|
|
|
|
if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) {
|
2012-10-28 15:37:29 +00:00
|
|
|
BMVert *v;
|
2013-08-17 08:21:40 +00:00
|
|
|
BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) {
|
2012-10-28 15:37:29 +00:00
|
|
|
bm_extrude_disable_skin_root(bm, v);
|
2012-05-22 15:30:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-28 00:16:06 +00:00
|
|
|
for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) {
|
2012-10-28 15:37:29 +00:00
|
|
|
BMVert *f_verts[4];
|
2013-09-02 03:13:51 +00:00
|
|
|
e_new = BMO_iter_map_value_ptr(&siter);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2018-09-25 13:31:29 +10:00
|
|
|
|
|
|
|
const bool edge_normal_flip = !(e->l && e->v1 != e->l->v);
|
|
|
|
if (edge_normal_flip == use_normal_flip) {
|
2012-10-28 15:37:29 +00:00
|
|
|
f_verts[0] = e->v1;
|
|
|
|
f_verts[1] = e->v2;
|
2012-10-28 16:17:20 +00:00
|
|
|
f_verts[2] = e_new->v2;
|
|
|
|
f_verts[3] = e_new->v1;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-10-28 16:17:20 +00:00
|
|
|
f_verts[0] = e->v2;
|
|
|
|
f_verts[1] = e->v1;
|
|
|
|
f_verts[2] = e_new->v1;
|
|
|
|
f_verts[3] = e_new->v2;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2012-03-20 04:27:14 +00:00
|
|
|
/* not sure what to do about example face, pass NULL for now */
|
2013-08-21 07:51:47 +00:00
|
|
|
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
|
2012-10-28 16:17:20 +00:00
|
|
|
bm_extrude_copy_face_loop_attributes(bm, f);
|
2018-06-04 08:48:38 +02:00
|
|
|
|
2016-07-01 19:07:11 +10:00
|
|
|
if (BMO_edge_flag_test(bm, e, EXT_INPUT)) {
|
2012-10-28 16:17:20 +00:00
|
|
|
e = e_new;
|
2016-07-01 19:07:11 +10:00
|
|
|
}
|
2018-06-04 08:48:38 +02:00
|
|
|
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_face_flag_enable(bm, f, EXT_KEEP);
|
|
|
|
BMO_edge_flag_enable(bm, e, EXT_KEEP);
|
|
|
|
BMO_vert_flag_enable(bm, e->v1, EXT_KEEP);
|
|
|
|
BMO_vert_flag_enable(bm, e->v2, EXT_KEEP);
|
2018-06-04 08:48:38 +02:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BMO_op_finish(bm, &dupeop);
|
|
|
|
|
2012-11-27 00:50:59 +00:00
|
|
|
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, EXT_KEEP);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2012-02-28 09:48:00 +00:00
|
|
|
void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2014-08-25 16:48:47 +10:00
|
|
|
const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
|
2012-02-19 18:31:04 +00:00
|
|
|
BMOIter siter;
|
|
|
|
BMVert *v, *dupev;
|
|
|
|
BMEdge *e;
|
2013-01-14 16:42:43 +00:00
|
|
|
const bool has_vskin = CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN);
|
2014-08-25 16:48:47 +10:00
|
|
|
GHash *select_history_map = NULL;
|
|
|
|
|
|
|
|
if (use_select_history) {
|
|
|
|
select_history_map = BM_select_history_map_create(bm);
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-11-19 14:58:31 +00:00
|
|
|
for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) {
|
2013-08-21 05:39:46 +00:00
|
|
|
dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_vert_flag_enable(bm, dupev, EXT_KEEP);
|
2014-06-22 18:38:17 +10:00
|
|
|
|
2019-03-27 17:14:36 +11:00
|
|
|
if (has_vskin) {
|
2012-05-22 15:30:05 +00:00
|
|
|
bm_extrude_disable_skin_root(bm, v);
|
2019-03-27 17:14:36 +11:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2014-08-25 16:48:47 +10:00
|
|
|
if (select_history_map) {
|
|
|
|
BMEditSelection *ese;
|
|
|
|
ese = BLI_ghash_lookup(select_history_map, v);
|
|
|
|
if (ese) {
|
|
|
|
ese->ele = (BMElem *)dupev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-23 00:12:06 +10:00
|
|
|
/* not essential, but ensures face normals from extruded edges are contiguous */
|
2014-06-22 18:38:17 +10:00
|
|
|
if (BM_vert_is_wire_endpoint(v)) {
|
|
|
|
if (v->e->v1 == v) {
|
|
|
|
SWAP(BMVert *, v, dupev);
|
|
|
|
}
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2014-06-22 18:38:17 +10:00
|
|
|
e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP);
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_edge_flag_enable(bm, e, EXT_KEEP);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-25 16:48:47 +10:00
|
|
|
if (select_history_map) {
|
|
|
|
BLI_ghash_free(select_history_map, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, EXT_KEEP);
|
|
|
|
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EXT_KEEP);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2015-05-22 10:56:54 +10:00
|
|
|
#ifdef USE_EDGE_REGION_FLAGS
|
|
|
|
/**
|
|
|
|
* When create an edge for an extruded face region
|
|
|
|
* check surrounding edge flags before creating a new edge.
|
|
|
|
*/
|
|
|
|
static bool bm_extrude_region_edge_flag(const BMVert *v, char r_e_hflag[2])
|
|
|
|
{
|
|
|
|
BMEdge *e_iter;
|
|
|
|
const char hflag_enable = BM_ELEM_SEAM;
|
|
|
|
const char hflag_disable = BM_ELEM_SMOOTH;
|
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
r_e_hflag[0] = 0x0;
|
|
|
|
r_e_hflag[1] = 0xff;
|
|
|
|
|
|
|
|
/* clear flags on both disks */
|
|
|
|
e_iter = v->e;
|
|
|
|
do {
|
|
|
|
if (e_iter->l && !BM_edge_is_boundary(e_iter)) {
|
|
|
|
r_e_hflag[0] |= e_iter->head.hflag;
|
|
|
|
r_e_hflag[1] &= e_iter->head.hflag;
|
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
} while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != v->e);
|
|
|
|
|
|
|
|
if (ok) {
|
|
|
|
r_e_hflag[0] &= hflag_enable;
|
|
|
|
r_e_hflag[1] = hflag_disable & ~r_e_hflag[1];
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
#endif /* USE_EDGE_REGION_FLAGS */
|
|
|
|
|
2012-02-28 09:48:00 +00:00
|
|
|
void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
BMOperator dupeop, delop;
|
|
|
|
BMOIter siter;
|
|
|
|
BMIter iter, fiter, viter;
|
2012-10-28 16:17:20 +00:00
|
|
|
BMEdge *e, *e_new;
|
2013-03-15 22:55:10 +00:00
|
|
|
BMVert *v;
|
2012-02-19 18:31:04 +00:00
|
|
|
BMFace *f;
|
2018-09-25 13:31:29 +10:00
|
|
|
bool found, delorig = false;
|
2012-11-20 13:29:27 +00:00
|
|
|
BMOpSlot *slot_facemap_out;
|
|
|
|
BMOpSlot *slot_edges_exclude;
|
2018-09-25 13:31:29 +10:00
|
|
|
const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
|
2019-01-04 16:23:04 +11:00
|
|
|
const bool use_normal_from_adjacent = BMO_slot_bool_get(op->slots_in, "use_normal_from_adjacent");
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
/* initialize our sub-operators */
|
2014-08-25 16:48:47 +10:00
|
|
|
BMO_op_initf(
|
|
|
|
bm, &dupeop, op->flag,
|
|
|
|
"duplicate use_select_history=%b",
|
|
|
|
BMO_slot_bool_get(op->slots_in, "use_select_history"));
|
|
|
|
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, EXT_INPUT);
|
2018-06-04 08:48:38 +02:00
|
|
|
|
2012-03-11 19:09:01 +00:00
|
|
|
/* if one flagged face is bordered by an un-flagged face, then we delete
|
2012-02-19 18:31:04 +00:00
|
|
|
* original geometry unless caller explicitly asked to keep it. */
|
2012-11-20 05:50:19 +00:00
|
|
|
if (!BMO_slot_bool_get(op->slots_in, "use_keep_orig")) {
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-01 16:04:37 +00:00
|
|
|
int edge_face_tot;
|
|
|
|
|
2016-07-01 19:07:11 +10:00
|
|
|
if (!BMO_edge_flag_test(bm, e, EXT_INPUT)) {
|
2012-03-01 13:13:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-01-14 16:42:43 +00:00
|
|
|
found = false; /* found a face that isn't input? */
|
2012-03-01 16:04:37 +00:00
|
|
|
edge_face_tot = 0; /* edge/face count */
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
|
2013-01-14 16:42:43 +00:00
|
|
|
found = true;
|
|
|
|
delorig = true;
|
2012-02-19 18:31:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-03-01 16:04:37 +00:00
|
|
|
|
|
|
|
edge_face_tot++;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2013-01-14 16:42:43 +00:00
|
|
|
if ((edge_face_tot > 1) && (found == false)) {
|
2012-03-11 19:09:01 +00:00
|
|
|
/* edge has a face user, that face isn't extrude input */
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_edge_flag_enable(bm, e, EXT_DEL);
|
2012-02-25 19:43:51 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-11 19:09:01 +00:00
|
|
|
/* calculate verts to delete */
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
2012-12-27 01:02:32 +00:00
|
|
|
if (v->e) { /* only deal with verts attached to geometry [#33651] */
|
2013-01-14 16:42:43 +00:00
|
|
|
found = false;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-12-27 01:02:32 +00:00
|
|
|
BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (!BMO_edge_flag_test(bm, e, EXT_INPUT) ||
|
|
|
|
!BMO_edge_flag_test(bm, e, EXT_DEL))
|
|
|
|
{
|
2013-01-14 16:42:43 +00:00
|
|
|
found = true;
|
2012-03-01 13:13:08 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2012-12-27 01:02:32 +00:00
|
|
|
/* avoid an extra loop */
|
2013-01-14 16:42:43 +00:00
|
|
|
if (found == true) {
|
2012-12-27 01:02:32 +00:00
|
|
|
BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
|
2013-01-14 16:42:43 +00:00
|
|
|
found = true;
|
2012-12-27 01:02:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-14 16:42:43 +00:00
|
|
|
if (found == false) {
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_vert_flag_enable(bm, v, EXT_DEL);
|
2012-12-27 01:02:32 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
}
|
2018-06-04 08:48:38 +02:00
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
|
|
|
|
BMO_face_flag_enable(bm, f, EXT_DEL);
|
2012-02-25 19:43:51 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2013-01-14 16:42:43 +00:00
|
|
|
if (delorig == true) {
|
2012-07-21 00:58:02 +00:00
|
|
|
BMO_op_initf(bm, &delop, op->flag,
|
|
|
|
"delete geom=%fvef context=%i",
|
2012-02-19 18:31:04 +00:00
|
|
|
EXT_DEL, DEL_ONLYTAGGED);
|
|
|
|
}
|
|
|
|
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_slot_copy(op, slots_in, "geom",
|
2012-11-19 14:58:31 +00:00
|
|
|
&dupeop, slots_in, "geom");
|
2012-02-19 18:31:04 +00:00
|
|
|
BMO_op_exec(bm, &dupeop);
|
|
|
|
|
2012-05-22 15:30:05 +00:00
|
|
|
/* disable root flag on all new skin nodes */
|
|
|
|
if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) {
|
2013-08-17 08:21:40 +00:00
|
|
|
BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) {
|
2012-05-22 15:30:05 +00:00
|
|
|
bm_extrude_disable_skin_root(bm, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-28 00:16:06 +00:00
|
|
|
slot_facemap_out = BMO_slot_get(dupeop.slots_out, "face_map.out");
|
2016-07-01 19:07:11 +10:00
|
|
|
if (bm->act_face && BMO_face_flag_test(bm, bm->act_face, EXT_INPUT)) {
|
2012-11-26 03:16:29 +00:00
|
|
|
bm->act_face = BMO_slot_map_elem_get(slot_facemap_out, bm->act_face);
|
2012-11-20 13:29:27 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-01 16:04:37 +00:00
|
|
|
if (delorig) {
|
|
|
|
BMO_op_exec(bm, &delop);
|
|
|
|
}
|
2018-06-04 08:48:38 +02:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
/* if not delorig, reverse loops of original face */
|
|
|
|
if (!delorig) {
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
BM_face_normal_flip(bm, f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 08:48:38 +02:00
|
|
|
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_slot_copy(&dupeop, slots_out, "geom.out",
|
|
|
|
op, slots_out, "geom.out");
|
2012-04-23 02:17:57 +00:00
|
|
|
|
2012-11-20 13:29:27 +00:00
|
|
|
slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude");
|
2012-11-28 00:16:06 +00:00
|
|
|
for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) {
|
2012-10-28 15:37:29 +00:00
|
|
|
BMVert *f_verts[4];
|
2015-05-22 10:56:54 +10:00
|
|
|
#ifdef USE_EDGE_REGION_FLAGS
|
|
|
|
BMEdge *f_edges[4];
|
|
|
|
#endif
|
2012-03-01 16:27:44 +00:00
|
|
|
|
2012-03-01 17:38:04 +00:00
|
|
|
/* this should always be wire, so this is mainly a speedup to avoid map lookup */
|
2012-11-20 13:29:27 +00:00
|
|
|
if (BM_edge_is_wire(e) && BMO_slot_map_contains(slot_edges_exclude, e)) {
|
2012-08-21 14:38:03 +00:00
|
|
|
BMVert *v1 = e->v1, *v2 = e->v2;
|
|
|
|
|
2012-03-01 16:27:44 +00:00
|
|
|
/* The original edge was excluded,
|
|
|
|
* this would result in a standalone wire edge - see [#30399] */
|
|
|
|
BM_edge_kill(bm, e);
|
|
|
|
|
2012-08-21 14:38:03 +00:00
|
|
|
/* kill standalone vertices from this edge - see [#32341] */
|
2019-03-27 17:14:36 +11:00
|
|
|
if (!v1->e) {
|
2012-08-21 14:38:03 +00:00
|
|
|
BM_vert_kill(bm, v1);
|
2019-03-27 17:14:36 +11:00
|
|
|
}
|
|
|
|
if (!v2->e) {
|
2012-09-03 00:30:55 +00:00
|
|
|
BM_vert_kill(bm, v2);
|
2019-03-27 17:14:36 +11:00
|
|
|
}
|
2012-08-21 14:38:03 +00:00
|
|
|
|
2012-03-01 13:13:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2013-05-27 20:56:33 +00:00
|
|
|
/* skip creating face for excluded edges see [#35503] */
|
|
|
|
if (BMO_slot_map_contains(slot_edges_exclude, e)) {
|
|
|
|
/* simply skip creating the face */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-09-02 03:13:51 +00:00
|
|
|
e_new = BMO_iter_map_value_ptr(&siter);
|
2012-03-01 13:13:08 +00:00
|
|
|
|
2012-10-28 16:17:20 +00:00
|
|
|
if (!e_new) {
|
2012-03-01 13:13:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2019-01-04 16:23:04 +11:00
|
|
|
bool edge_normal_flip;
|
|
|
|
if (use_normal_from_adjacent == false) {
|
|
|
|
/* Orient loop to give same normal as a loop of 'e_new'
|
|
|
|
* if it exists (will be one of the faces from the region),
|
|
|
|
* else same normal as a loop of e, if it exists. */
|
|
|
|
edge_normal_flip = !(
|
|
|
|
e_new->l ?
|
|
|
|
(e_new->l->v == e_new->v1) :
|
|
|
|
(!e->l || !(e->l->v == e->v1)));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Special case, needed for repetitive extrusions
|
|
|
|
* that use the normals from the previously created faces. */
|
|
|
|
edge_normal_flip = !(e->l && e->v1 != e->l->v);
|
|
|
|
}
|
|
|
|
|
2018-09-25 13:31:29 +10:00
|
|
|
if (edge_normal_flip == use_normal_flip) {
|
2012-10-28 15:37:29 +00:00
|
|
|
f_verts[0] = e->v1;
|
|
|
|
f_verts[1] = e->v2;
|
2012-10-28 16:17:20 +00:00
|
|
|
f_verts[2] = e_new->v2;
|
|
|
|
f_verts[3] = e_new->v1;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-10-28 16:17:20 +00:00
|
|
|
f_verts[0] = e->v2;
|
|
|
|
f_verts[1] = e->v1;
|
|
|
|
f_verts[2] = e_new->v1;
|
|
|
|
f_verts[3] = e_new->v2;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2015-05-22 10:56:54 +10:00
|
|
|
#ifdef USE_EDGE_REGION_FLAGS
|
|
|
|
/* handle new edges */
|
|
|
|
f_edges[0] = e;
|
|
|
|
f_edges[2] = e_new;
|
|
|
|
|
|
|
|
f_edges[1] = BM_edge_exists(f_verts[1], f_verts[2]);
|
|
|
|
if (f_edges[1] == NULL) {
|
|
|
|
char e_hflag[2];
|
|
|
|
bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[2], e_hflag);
|
|
|
|
f_edges[1] = BM_edge_create(bm, f_verts[1], f_verts[2], NULL, BM_CREATE_NOP);
|
|
|
|
if (e_hflag_ok) {
|
|
|
|
BM_elem_flag_enable(f_edges[1], e_hflag[0]);
|
|
|
|
BM_elem_flag_disable(f_edges[1], e_hflag[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f_edges[3] = BM_edge_exists(f_verts[3], f_verts[0]);
|
|
|
|
if (f_edges[3] == NULL) {
|
|
|
|
char e_hflag[2];
|
|
|
|
bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[3], e_hflag);
|
|
|
|
f_edges[3] = BM_edge_create(bm, f_verts[3], f_verts[0], NULL, BM_CREATE_NOP);
|
|
|
|
if (e_hflag_ok) {
|
|
|
|
BM_elem_flag_enable(f_edges[3], e_hflag[0]);
|
|
|
|
BM_elem_flag_disable(f_edges[3], e_hflag[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f = BM_face_create(bm, f_verts, f_edges, 4, NULL, BM_CREATE_NOP);
|
|
|
|
#else
|
2013-08-21 07:51:47 +00:00
|
|
|
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
|
2015-05-22 10:56:54 +10:00
|
|
|
#endif
|
|
|
|
|
2012-10-28 16:17:20 +00:00
|
|
|
bm_extrude_copy_face_loop_attributes(bm, f);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* link isolated vert */
|
2012-11-28 00:16:06 +00:00
|
|
|
for (v = BMO_iter_new(&siter, dupeop.slots_out, "isovert_map.out", 0); v; v = BMO_iter_step(&siter)) {
|
2013-09-02 03:13:51 +00:00
|
|
|
BMVert *v2 = BMO_iter_map_value_ptr(&siter);
|
2014-06-23 00:12:06 +10:00
|
|
|
|
|
|
|
/* not essential, but ensures face normals from extruded edges are contiguous */
|
|
|
|
if (BM_vert_is_wire_endpoint(v)) {
|
|
|
|
if (v->e->v1 == v) {
|
|
|
|
SWAP(BMVert *, v, v2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BM_edge_create(bm, v, v2, NULL, BM_CREATE_NO_DOUBLE);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2012-03-01 13:13:08 +00:00
|
|
|
/* cleanup */
|
2019-03-27 17:14:36 +11:00
|
|
|
if (delorig) {
|
|
|
|
BMO_op_finish(bm, &delop);
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
BMO_op_finish(bm, &dupeop);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute higher-quality vertex normals used by solidify.
|
|
|
|
* Only considers geometry in the marked solidify region.
|
|
|
|
* Note that this does not work so well for non-manifold
|
|
|
|
* regions.
|
|
|
|
*/
|
|
|
|
static void calc_solidify_normals(BMesh *bm)
|
|
|
|
{
|
|
|
|
BMIter viter, eiter, fiter;
|
|
|
|
BMVert *v;
|
|
|
|
BMEdge *e;
|
|
|
|
BMFace *f, *f1, *f2;
|
|
|
|
float edge_normal[3];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* can't use BM_edge_face_count because we need to count only marked faces */
|
|
|
|
int *edge_face_count = MEM_callocN(sizeof(int) * bm->totedge, __func__);
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
|
2012-02-19 18:31:04 +00:00
|
|
|
BM_elem_flag_enable(v, BM_ELEM_TAG);
|
|
|
|
}
|
|
|
|
|
|
|
|
BM_mesh_elem_index_ensure(bm, BM_EDGE);
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (!BMO_face_flag_test(bm, f, FACE_MARK)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
/* And mark all edges and vertices on the
|
|
|
|
* marked faces */
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_edge_flag_enable(bm, e, EDGE_MARK);
|
|
|
|
BMO_vert_flag_enable(bm, e->v1, VERT_MARK);
|
|
|
|
BMO_vert_flag_enable(bm, e->v2, VERT_MARK);
|
2012-02-19 18:31:04 +00:00
|
|
|
edge_face_count[BM_elem_index_get(e)]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = edge_face_count[BM_elem_index_get(e)]++;
|
|
|
|
|
|
|
|
if (i == 0 || i > 2) {
|
|
|
|
/* Edge & vertices are non-manifold even when considering
|
|
|
|
* only marked faces */
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_edge_flag_enable(bm, e, EDGE_NONMAN);
|
|
|
|
BMO_vert_flag_enable(bm, e->v1, VERT_NONMAN);
|
|
|
|
BMO_vert_flag_enable(bm, e->v2, VERT_NONMAN);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
MEM_freeN(edge_face_count);
|
2012-03-18 07:38:51 +00:00
|
|
|
edge_face_count = NULL; /* don't re-use */
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
|
2012-03-22 07:53:11 +00:00
|
|
|
if (!BM_vert_is_manifold(v)) {
|
2016-07-01 19:07:11 +10:00
|
|
|
BMO_vert_flag_enable(bm, v, VERT_NONMAN);
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-01 19:07:11 +10:00
|
|
|
if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
zero_v3(v->no);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
/* If the edge is not part of a the solidify region
|
|
|
|
* its normal should not be considered */
|
2016-07-01 19:07:11 +10:00
|
|
|
if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the edge joins more than two marked faces high
|
|
|
|
* quality normal computation won't work */
|
2016-07-01 19:07:11 +10:00
|
|
|
if (BMO_edge_flag_test(bm, e, EDGE_NONMAN)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
f1 = f2 = NULL;
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (BMO_face_flag_test(bm, f, FACE_MARK)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
if (f1 == NULL) {
|
|
|
|
f1 = f;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(f2 == NULL);
|
|
|
|
f2 = f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_assert(f1 != NULL);
|
|
|
|
|
|
|
|
if (f2 != NULL) {
|
|
|
|
const float angle = angle_normalized_v3v3(f1->no, f2->no);
|
|
|
|
|
|
|
|
if (angle > 0.0f) {
|
|
|
|
/* two faces using this edge, calculate the edge normal
|
|
|
|
* using the angle between the faces as a weighting */
|
|
|
|
add_v3_v3v3(edge_normal, f1->no, f2->no);
|
2016-07-08 10:14:49 +10:00
|
|
|
normalize_v3_length(edge_normal, angle);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* can't do anything useful here!
|
2012-03-09 00:41:09 +00:00
|
|
|
* Set the face index for a vert in case it gets a zero normal */
|
2012-02-19 18:31:04 +00:00
|
|
|
BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
|
|
|
|
BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* only one face attached to that edge */
|
2015-01-31 17:23:30 +11:00
|
|
|
/* an edge without another attached- the weight on this is undefined,
|
|
|
|
* M_PI_2 is 90d in radians and that seems good enough */
|
2012-02-19 18:31:04 +00:00
|
|
|
copy_v3_v3(edge_normal, f1->no);
|
2015-01-31 17:23:30 +11:00
|
|
|
mul_v3_fl(edge_normal, M_PI_2);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
add_v3_v3(e->v1->no, edge_normal);
|
|
|
|
add_v3_v3(e->v2->no, edge_normal);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* normalize accumulated vertex normal */
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (!BMO_vert_flag_test(bm, v, VERT_MARK)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-01 19:07:11 +10:00
|
|
|
if (BMO_vert_flag_test(bm, v, VERT_NONMAN)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
/* use standard normals for vertices connected to non-manifold edges */
|
2012-04-19 14:38:09 +00:00
|
|
|
BM_vert_normal_update(v);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
else if (normalize_v3(v->no) == 0.0f && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
|
|
|
|
/* exceptional case, totally flat. use the normal
|
|
|
|
* of any marked face around the vertex */
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (BMO_face_flag_test(bm, f, FACE_MARK)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
copy_v3_v3(v->no, f->no);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-27 23:23:47 +00:00
|
|
|
static void solidify_add_thickness(BMesh *bm, const float dist)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
BMFace *f;
|
|
|
|
BMVert *v;
|
|
|
|
BMLoop *l;
|
|
|
|
BMIter iter, loopIter;
|
|
|
|
float *vert_angles = MEM_callocN(sizeof(float) * bm->totvert * 2, "solidify"); /* 2 in 1 */
|
|
|
|
float *vert_accum = vert_angles + bm->totvert;
|
|
|
|
int i, index;
|
|
|
|
|
2013-03-16 00:41:32 +00:00
|
|
|
BLI_buffer_declare_static(float, face_angles_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
|
|
|
|
BLI_buffer_declare_static(float *, verts_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
|
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
BM_mesh_elem_index_ensure(bm, BM_VERT);
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
2016-07-01 19:07:11 +10:00
|
|
|
if (BMO_face_flag_test(bm, f, FACE_MARK)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-12-11 15:10:19 +00:00
|
|
|
/* array for passing verts to angle_poly_v3 */
|
2015-10-04 14:14:28 +11:00
|
|
|
float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len);
|
2012-12-11 15:10:19 +00:00
|
|
|
/* array for receiving angles from angle_poly_v3 */
|
2015-10-04 14:14:28 +11:00
|
|
|
float **verts = BLI_buffer_reinit_data(&verts_buf, float *, f->len);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-12-11 15:10:19 +00:00
|
|
|
BM_ITER_ELEM_INDEX (l, &loopIter, f, BM_LOOPS_OF_FACE, i) {
|
|
|
|
verts[i] = l->v->co;
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-12-11 15:10:19 +00:00
|
|
|
angle_poly_v3(face_angles, (const float **)verts, f->len);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-12-11 15:10:19 +00:00
|
|
|
i = 0;
|
|
|
|
BM_ITER_ELEM (l, &loopIter, f, BM_LOOPS_OF_FACE) {
|
|
|
|
v = l->v;
|
|
|
|
index = BM_elem_index_get(v);
|
|
|
|
vert_accum[index] += face_angles[i];
|
2014-04-19 22:12:50 +10:00
|
|
|
vert_angles[index] += shell_v3v3_normalized_to_dist(v->no, f->no) * face_angles[i];
|
2012-12-11 15:10:19 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2013-03-16 00:41:32 +00:00
|
|
|
BLI_buffer_free(&face_angles_buf);
|
|
|
|
BLI_buffer_free(&verts_buf);
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
2012-02-19 18:31:04 +00:00
|
|
|
index = BM_elem_index_get(v);
|
|
|
|
if (vert_accum[index]) { /* zero if unselected */
|
2012-03-27 23:23:47 +00:00
|
|
|
madd_v3_v3fl(v->co, v->no, dist * (vert_angles[index] / vert_accum[index]));
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(vert_angles);
|
|
|
|
}
|
|
|
|
|
2012-02-28 09:48:00 +00:00
|
|
|
void bmo_solidify_face_region_exec(BMesh *bm, BMOperator *op)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
BMOperator extrudeop;
|
|
|
|
BMOperator reverseop;
|
|
|
|
float thickness;
|
|
|
|
|
2012-11-19 14:58:31 +00:00
|
|
|
thickness = BMO_slot_float_get(op->slots_in, "thickness");
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
/* Flip original faces (so the shell is extruded inward) */
|
2012-07-21 00:58:02 +00:00
|
|
|
BMO_op_init(bm, &reverseop, op->flag, "reverse_faces");
|
2016-03-14 14:15:56 +11:00
|
|
|
BMO_slot_bool_set(reverseop.slots_in, "flip_multires", true);
|
2012-11-19 14:58:31 +00:00
|
|
|
BMO_slot_copy(op, slots_in, "geom",
|
|
|
|
&reverseop, slots_in, "faces");
|
2012-02-19 18:31:04 +00:00
|
|
|
BMO_op_exec(bm, &reverseop);
|
|
|
|
BMO_op_finish(bm, &reverseop);
|
|
|
|
|
|
|
|
/* Extrude the region */
|
2013-01-14 16:42:43 +00:00
|
|
|
BMO_op_initf(bm, &extrudeop, op->flag, "extrude_face_region use_keep_orig=%b", true);
|
2012-11-19 14:58:31 +00:00
|
|
|
BMO_slot_copy(op, slots_in, "geom",
|
2012-11-20 05:50:19 +00:00
|
|
|
&extrudeop, slots_in, "geom");
|
2012-02-19 18:31:04 +00:00
|
|
|
BMO_op_exec(bm, &extrudeop);
|
|
|
|
|
|
|
|
/* Push the verts of the extruded faces inward to create thickness */
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_slot_buffer_flag_enable(bm, extrudeop.slots_out, "geom.out", BM_FACE, FACE_MARK);
|
2012-02-19 18:31:04 +00:00
|
|
|
calc_solidify_normals(bm);
|
|
|
|
solidify_add_thickness(bm, thickness);
|
|
|
|
|
2012-11-20 05:50:19 +00:00
|
|
|
BMO_slot_copy(&extrudeop, slots_out, "geom.out",
|
|
|
|
op, slots_out, "geom.out");
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
BMO_op_finish(bm, &extrudeop);
|
|
|
|
}
|