diff options
-rw-r--r-- | source/blender/bmesh/intern/bmesh_opdefines.c | 1 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_fill_grid.c | 116 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_tools.c | 7 |
3 files changed, 83 insertions, 41 deletions
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index e6291cac241..0bd4907eab9 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -542,6 +542,7 @@ static BMOpDefine bmo_grid_fill_def = { /* restricts edges to groups. maps edges to integer */ {"mat_nr", BMO_OP_SLOT_INT}, /* material to use */ {"use_smooth", BMO_OP_SLOT_BOOL}, /* smooth state to use */ + {"use_interp_simple", BMO_OP_SLOT_BOOL}, /* use simple interpolation */ {{'\0'}}, }, /* slots_out */ diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c index 35916c76e85..b0af0c0218b 100644 --- a/source/blender/bmesh/operators/bmo_fill_grid.c +++ b/source/blender/bmesh/operators/bmo_fill_grid.c @@ -154,25 +154,15 @@ static void bm_loop_pair_test_copy(BMLoop *l_pair_a[2], BMLoop *l_pair_b[2]) * Interpolate from boundary loops. * * \note These weights will be calculated multiple times per vertex. - * Since this runs on each loop, could reduce calls to #barycentric_weights_v2_quad. */ -static void bm_loop_interp_from_grid_boundary_4(BMesh *bm, BMLoop *l, BMLoop *l_bound[4], const float uv[2]) +static void bm_loop_interp_from_grid_boundary_4(BMesh *bm, BMLoop *l, BMLoop *l_bound[4], const float w[4]) { - float cos[4][2] = { - {uv[0], 0}, - {0, uv[1]}, - {uv[0], 1}, - {1, uv[1]}}; - void *l_cdata[4] = { l_bound[0]->head.data, l_bound[1]->head.data, l_bound[2]->head.data, l_bound[3]->head.data}; - float w[4]; - - barycentric_weights_v2_quad(UNPACK4(cos), uv, w); CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 4, l->head.data); } @@ -192,13 +182,42 @@ static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, BMLoop *l, BMLoop *l_ /** + * Avoids calling #barycentric_weights_v2_quad often by caching weights into an array. + */ +static void barycentric_weights_v2_grid_cache(const unsigned int xtot, const unsigned int ytot, + float (*weight_table)[4]) +{ + float x_step = 1.0f / (float)(xtot - 1); + float y_step = 1.0f / (float)(ytot - 1); + unsigned int i = 0; + float xy_fl[2]; + + unsigned int x, y; + for (y = 0; y < ytot; y++) { + xy_fl[1] = y_step * (float)y; + for (x = 0; x < xtot; x++) { + xy_fl[0] = x_step * (float)x; + { + const float cos[4][2] = { + {xy_fl[0], 0.0f}, + {0.0f, xy_fl[1]}, + {xy_fl[0], 1.0f}, + {1.0f, xy_fl[1]}}; + barycentric_weights_v2_quad(UNPACK4(cos), xy_fl, weight_table[i++]); + } + } + } +} + + +/** * This may be useful outside the bmesh operator. * * \param v_grid 2d array of verts, all boundary verts must be set, we fill in the middle. */ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const int ytot, const short mat_nr, const bool use_smooth, - const bool use_flip) + const bool use_flip, const bool use_interp_simple) { const bool use_vert_interp = CustomData_has_interp(&bm->vdata); const bool use_loop_interp = CustomData_has_interp(&bm->ldata); @@ -207,6 +226,8 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const /* for use_loop_interp */ BMLoop *((*larr_x_a)[2]), *((*larr_x_b)[2]), *((*larr_y_a)[2]), *((*larr_y_b)[2]); + float (*weight_table)[4]; + #define XY(_x, _y) ((_x) + ((_y) * (xtot))) #ifdef BARYCENTRIC_INTERP @@ -233,6 +254,14 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const true); #endif + if (use_interp_simple || use_vert_interp || use_loop_interp) { + weight_table = MEM_mallocN(sizeof(*weight_table) * xtot * ytot, __func__); + barycentric_weights_v2_grid_cache(xtot, ytot, weight_table); + } + else { + weight_table = NULL; + } + /* Store loops */ if (use_loop_interp) { @@ -279,7 +308,7 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const /* place the vertex */ #ifdef BARYCENTRIC_INTERP - { + if (use_interp_simple == false) { float co_a[3], co_b[3]; barycentric_transform( @@ -295,14 +324,17 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const interp_v3_v3v3(co, co_a, co_b, (float)y / ((float)ytot - 1)); } - -#else - interp_v3_v3v3( - co, - v_grid[x]->co, - v_grid[(xtot * ytot) + (x - xtot)]->co, - (float)y / ((float)ytot - 1)); + else #endif + { + const float *w = weight_table[XY(x, y)]; + + zero_v3(co); + madd_v3_v3fl(co, v_grid[XY(x, 0)]->co, w[0]); + madd_v3_v3fl(co, v_grid[XY(0, y)]->co, w[1]); + madd_v3_v3fl(co, v_grid[XY(x, ytot - 1)]->co, w[2]); + madd_v3_v3fl(co, v_grid[XY(xtot - 1, y)]->co, w[3]); + } v = BM_vert_create(bm, co, NULL, BM_CREATE_NOP); v_grid[(y * xtot) + x] = v; @@ -310,13 +342,16 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const /* interpolate only along one axis, this could be changed * but from user pov gives predictable results since these are selected loop */ if (use_vert_interp) { - void *v_cdata[2] = { - v_grid[XY(x, 0)]->head.data, - v_grid[XY(x, (ytot - 1))]->head.data, + const float *w = weight_table[XY(x, y)]; + + void *v_cdata[4] = { + v_grid[XY(x, 0)]->head.data, + v_grid[XY(0, y)]->head.data, + v_grid[XY(x, ytot - 1)]->head.data, + v_grid[XY(xtot - 1, y)]->head.data, }; - const float t = (float)y / ((float)ytot - 1); - const float w[2] = {1.0f - t, t}; - CustomData_bmesh_interp(&bm->vdata, v_cdata, w, NULL, 2, v->head.data); + + CustomData_bmesh_interp(&bm->vdata, v_cdata, w, NULL, 4, v->head.data); } } @@ -354,7 +389,6 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const BMLoop *l_quad[4]; BMLoop *l_bound[4]; BMLoop *l_tmp; - float uv[2]; /* xy in the grid */ int x_side, y_side, i; char interp_from; @@ -396,29 +430,28 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const for (x_side = 0; x_side < 2; x_side++) { for (y_side = 0; y_side < 2; y_side++) { - - uv[0] = (float)(x + x_side) / (xtot - 1); - uv[1] = (float)(y + y_side) / (ytot - 1); - if (interp_from == 'B') { + const float *w = weight_table[XY(x + x_side, y + y_side)]; l_bound[0] = larr_x_a[x][x_side]; /* B */ l_bound[1] = larr_y_a[y][y_side]; /* L */ l_bound[2] = larr_x_b[x][x_side]; /* T */ l_bound[3] = larr_y_b[y][y_side]; /* R */ - bm_loop_interp_from_grid_boundary_4(bm, l_quad[i++], l_bound, uv); + bm_loop_interp_from_grid_boundary_4(bm, l_quad[i++], l_bound, w); } else if (interp_from == 'X') { + const float t = (float)(y + y_side) / (ytot - 1); l_bound[0] = larr_x_a[x][x_side]; /* B */ l_bound[1] = larr_x_b[x][x_side]; /* T */ - bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, uv[1]); + bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t); } else if (interp_from == 'Y') { + const float t = (float)(x + x_side) / (xtot - 1); l_bound[0] = larr_y_a[y][y_side]; /* L */ l_bound[1] = larr_y_b[y][y_side]; /* R */ - bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, uv[0]); + bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t); } else { BLI_assert(0); @@ -444,13 +477,17 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const MEM_freeN(larr_y_b); } + if (weight_table) { + MEM_freeN(weight_table); + } + #undef XY } static void bm_grid_fill(BMesh *bm, struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b, struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b, - const short mat_nr, const bool use_smooth) + const short mat_nr, const bool use_smooth, const bool use_interp_simple) { #define USE_FLIP_DETECT @@ -521,7 +558,7 @@ static void bm_grid_fill(BMesh *bm, #endif - bm_grid_fill_array(bm, v_grid, xtot, ytot, mat_nr, use_smooth, use_flip); + bm_grid_fill_array(bm, v_grid, xtot, ytot, mat_nr, use_smooth, use_flip, use_interp_simple); MEM_freeN(v_grid); #undef USE_FLIP_DETECT @@ -550,8 +587,9 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op) struct BMEdgeLoopStore *estore_rail_a, *estore_rail_b; BMVert *v_a_first, *v_a_last; BMVert *v_b_first, *v_b_last; - const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); - const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); + const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + const bool use_interp_simple = BMO_slot_bool_get(op->slots_in, "use_interp_simple"); int count; bool change = false; @@ -643,7 +681,7 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op) /* finally we have all edge loops needed */ bm_grid_fill(bm, estore_a, estore_b, estore_rail_a, estore_rail_b, - mat_nr, use_smooth); + mat_nr, use_smooth, use_interp_simple); change = true; cleanup: diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 75ff5256e10..757f1a83751 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2983,6 +2983,7 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) const short use_smooth = edbm_add_edge_face__smooth_get(em->bm); const int totedge_orig = em->bm->totedge; const int totface_orig = em->bm->totface; + const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple"); const bool use_prepare = true; @@ -3018,8 +3019,9 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) if (!EDBM_op_init(em, &bmop, op, - "grid_fill edges=%he mat_nr=%i use_smooth=%b", - use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT, em->mat_nr, use_smooth)) + "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b", + use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT, + em->mat_nr, use_smooth, use_interp_simple)) { return OPERATOR_CANCELLED; } @@ -3066,6 +3068,7 @@ void MESH_OT_fill_grid(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "Number of sides (zero disables)", -100, 100); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_boolean(ot->srna, "use_interp_simple", 0, "Simple Blending", ""); } static int edbm_fill_holes_exec(bContext *C, wmOperator *op) |