Mesh Tool,
inset interpolation now works for 'inset_region', enabled by default. Example: http://www.graphicall.org/ftp/ideasman42/inset_interpolation_new.png
This commit is contained in:
@@ -167,29 +167,18 @@ void BM_data_interp_face_vert_edge(BMesh *bm, BMVert *v1, BMVert *UNUSED(v2), BM
|
||||
*
|
||||
* \note Only handles loop customdata. multires is handled.
|
||||
*/
|
||||
void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source)
|
||||
void BM_face_interp_from_face_ex(BMesh *bm, BMFace *target, BMFace *source,
|
||||
void **blocks, float (*cos_2d)[2], float axis_mat[3][3])
|
||||
{
|
||||
BMLoop *l_iter;
|
||||
BMLoop *l_first;
|
||||
|
||||
void **blocks = BLI_array_alloca(blocks, source->len);
|
||||
float (*cos_2d)[2] = BLI_array_alloca(cos_2d, source->len);
|
||||
float *w = BLI_array_alloca(w, source->len);
|
||||
float axis_mat[3][3]; /* use normal to transform into 2d xy coords */
|
||||
float *w = BLI_array_alloca(w, source->len);
|
||||
float co[2];
|
||||
int i;
|
||||
|
||||
/* convert the 3d coords into 2d for projection */
|
||||
axis_dominant_v3_to_m3(axis_mat, source->no);
|
||||
|
||||
BM_elem_attrs_copy(bm, bm, source, target);
|
||||
|
||||
i = 0;
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(source);
|
||||
do {
|
||||
mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
|
||||
blocks[i] = l_iter->head.data;
|
||||
} while (i++, (l_iter = l_iter->next) != l_first);
|
||||
if (source != target)
|
||||
BM_elem_attrs_copy(bm, bm, source, target);
|
||||
|
||||
/* interpolate */
|
||||
i = 0;
|
||||
@@ -201,6 +190,31 @@ void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source)
|
||||
} while (i++, (l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
||||
void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source)
|
||||
{
|
||||
BMLoop *l_iter;
|
||||
BMLoop *l_first;
|
||||
|
||||
void **blocks = BLI_array_alloca(blocks, source->len);
|
||||
float (*cos_2d)[2] = BLI_array_alloca(cos_2d, source->len);
|
||||
float *w = BLI_array_alloca(w, source->len);
|
||||
float axis_mat[3][3]; /* use normal to transform into 2d xy coords */
|
||||
int i;
|
||||
|
||||
/* convert the 3d coords into 2d for projection */
|
||||
axis_dominant_v3_to_m3(axis_mat, source->no);
|
||||
|
||||
i = 0;
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(source);
|
||||
do {
|
||||
mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
|
||||
blocks[i] = l_iter->head.data;
|
||||
} while (i++, (l_iter = l_iter->next) != l_first);
|
||||
|
||||
BM_face_interp_from_face_ex(bm, target, source,
|
||||
blocks, cos_2d, axis_mat);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Multires Interpolation
|
||||
*
|
||||
|
||||
@@ -42,6 +42,8 @@ void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int d
|
||||
float BM_elem_float_data_get(CustomData *cd, void *element, int type);
|
||||
void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val);
|
||||
|
||||
void BM_face_interp_from_face_ex(BMesh *bm, BMFace *target, BMFace *source,
|
||||
void **blocks, float (*cos_2d)[2], float axis_mat[3][3]);
|
||||
void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source);
|
||||
void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source,
|
||||
const bool do_vertex, const bool do_multires);
|
||||
|
||||
@@ -1533,6 +1533,7 @@ static BMOpDefine bmo_inset_region_def = {
|
||||
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
|
||||
{"use_boundary", BMO_OP_SLOT_BOOL},
|
||||
{"use_even_offset", BMO_OP_SLOT_BOOL},
|
||||
{"use_interpolate", BMO_OP_SLOT_BOOL},
|
||||
{"use_relative_offset", BMO_OP_SLOT_BOOL},
|
||||
{"thickness", BMO_OP_SLOT_FLT},
|
||||
{"depth", BMO_OP_SLOT_FLT},
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_array.h"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BKE_customdata.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
@@ -243,6 +245,59 @@ typedef struct SplitEdgeInfo {
|
||||
BMLoop *l;
|
||||
} SplitEdgeInfo;
|
||||
|
||||
|
||||
/**
|
||||
* Interpolation, this is more complex for regions since we're not creating new faces
|
||||
* and throwing away old ones, so instead, store face data needed for interpolation.
|
||||
*
|
||||
* \note This uses CustomData functions in quite a low-level way which should be
|
||||
* avoided, but in this case its hard to do without storing a duplicate mesh. */
|
||||
|
||||
/* just enough of a face to store interpolation data we can use once the inset is done */
|
||||
typedef struct InterpFace {
|
||||
BMFace *f;
|
||||
void **blocks;
|
||||
float (*cos_2d)[2];
|
||||
float axis_mat[3][3];
|
||||
} InterpFace;
|
||||
|
||||
/* basically a clone of #BM_vert_interp_from_face */
|
||||
static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena)
|
||||
{
|
||||
BMLoop *l_iter, *l_first;
|
||||
void **blocks = iface->blocks = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks) * f->len);
|
||||
float (*cos_2d)[2] = iface->cos_2d = BLI_memarena_alloc(interp_arena, sizeof(*iface->cos_2d) * f->len);
|
||||
void *axis_mat = iface->axis_mat;
|
||||
int i;
|
||||
|
||||
axis_dominant_v3_to_m3(axis_mat, f->no);
|
||||
|
||||
iface->f = f;
|
||||
|
||||
i = 0;
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||
do {
|
||||
mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
|
||||
blocks[i] = NULL;
|
||||
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_iter->head.data, &blocks[i]);
|
||||
/* if we were not modifying the loops later we would do... */
|
||||
// blocks[i] = l_iter->head.data;
|
||||
|
||||
/* use later for index lookups */
|
||||
BM_elem_index_set(l_iter, i); /* set_ok */
|
||||
} while (i++, (l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
static void bm_interp_face_free(InterpFace *iface, BMesh *bm)
|
||||
{
|
||||
void **blocks = iface->blocks;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < iface->f->len; i++) {
|
||||
CustomData_bmesh_free_block(&bm->ldata, &blocks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return the tag loop where there is...
|
||||
* - only 1 tagged face attached to this edge.
|
||||
@@ -298,6 +353,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
|
||||
const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
|
||||
const bool use_even_boundry = use_even_offset; /* could make own option */
|
||||
const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
|
||||
const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
|
||||
const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
|
||||
const float depth = BMO_slot_float_get(op->slots_in, "depth");
|
||||
|
||||
@@ -307,11 +363,24 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
|
||||
SplitEdgeInfo *edge_info;
|
||||
SplitEdgeInfo *es;
|
||||
|
||||
/* Interpolation Vars */
|
||||
/* an array alligned with faces but only fill items which are used. */
|
||||
InterpFace **iface_array = NULL;
|
||||
int iface_array_len;
|
||||
MemArena *interp_arena = NULL;
|
||||
|
||||
BMVert *v;
|
||||
BMEdge *e;
|
||||
BMFace *f;
|
||||
int i, j, k;
|
||||
|
||||
if (use_interpolate) {
|
||||
interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
||||
/* warning, we could be more clever here and not over alloc */
|
||||
iface_array = MEM_callocN(sizeof(*iface_array) * bm->totface, __func__);
|
||||
iface_array_len = bm->totface;
|
||||
}
|
||||
|
||||
if (use_outset == false) {
|
||||
BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
|
||||
BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
|
||||
@@ -392,9 +461,22 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
|
||||
/* important to tag again here */
|
||||
BM_elem_flag_enable(es->e_new->v1, BM_ELEM_TAG);
|
||||
BM_elem_flag_enable(es->e_new->v2, BM_ELEM_TAG);
|
||||
}
|
||||
|
||||
|
||||
/* initialize interpolation vars */
|
||||
/* this could go in its own loop,
|
||||
* only use the 'es->l->f' so we don't store loops for faces which have no mixed selection */
|
||||
if (use_interpolate) {
|
||||
const int j = BM_elem_index_get((f = es->l->f));
|
||||
if (iface_array[j] == NULL) {
|
||||
InterpFace *iface = BLI_memarena_alloc(interp_arena, sizeof(*iface));
|
||||
bm_interp_face_store(iface, bm, f, interp_arena);
|
||||
iface_array[j] = iface;
|
||||
}
|
||||
}
|
||||
/* done interpolation */
|
||||
}
|
||||
|
||||
/* show edge normals for debugging */
|
||||
#if 0
|
||||
for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
|
||||
@@ -638,6 +720,16 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
if (use_interpolate) {
|
||||
for (i = 0; i < iface_array_len; i++) {
|
||||
if (iface_array[i]) {
|
||||
InterpFace *iface = iface_array[i];
|
||||
BM_face_interp_from_face_ex(bm, iface->f, iface->f,
|
||||
iface->blocks, iface->cos_2d, iface->axis_mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* create faces */
|
||||
for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
|
||||
BMVert *varr[4] = {NULL};
|
||||
@@ -704,10 +796,30 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
|
||||
l_b = l_a->next;
|
||||
|
||||
/* swap a<->b intentionally */
|
||||
BM_elem_attrs_copy(bm, bm, l_a_other, l_b);
|
||||
BM_elem_attrs_copy(bm, bm, l_b_other, l_a);
|
||||
if (use_interpolate) {
|
||||
InterpFace *iface = iface_array[BM_elem_index_get(es->l->f)];
|
||||
const int i_a = BM_elem_index_get(l_a_other);
|
||||
const int i_b = BM_elem_index_get(l_b_other);
|
||||
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks[i_a], &l_b->head.data);
|
||||
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks[i_b], &l_a->head.data);
|
||||
}
|
||||
else {
|
||||
BM_elem_attrs_copy(bm, bm, l_a_other, l_b);
|
||||
BM_elem_attrs_copy(bm, bm, l_b_other, l_a);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (use_interpolate) {
|
||||
for (i = 0; i < iface_array_len; i++) {
|
||||
if (iface_array[i]) {
|
||||
bm_interp_face_free(iface_array[i], bm);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_memarena_free(interp_arena);
|
||||
MEM_freeN(iface_array);
|
||||
}
|
||||
|
||||
/* we could flag new edges/verts too, is it useful? */
|
||||
|
||||
@@ -209,9 +209,9 @@ static int edbm_inset_calc(wmOperator *op)
|
||||
}
|
||||
else {
|
||||
EDBM_op_init(em, &bmop, op,
|
||||
"inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b "
|
||||
"thickness=%f depth=%f use_outset=%b",
|
||||
BM_ELEM_SELECT, use_boundary, use_even_offset, use_relative_offset,
|
||||
"inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b"
|
||||
" use_interpolate=%b thickness=%f depth=%f use_outset=%b",
|
||||
BM_ELEM_SELECT, use_boundary, use_even_offset, use_relative_offset, use_interpolate,
|
||||
thickness, depth, use_outset);
|
||||
}
|
||||
BMO_op_exec(em->bm, &bmop);
|
||||
|
||||
Reference in New Issue
Block a user