108
/* -------------------------------------------------------------------- */
109
/* Handle Loop Pairs */
115
* Assign a loop pair from 2 verts (which _must_ share an edge)
117
static void bm_loop_pair_from_verts(BMVert *v_a, BMVert *v_b,
120
BMEdge *e = BM_edge_exists(v_a, v_b);
122
if (e->l->v == v_a) {
124
l_pair[1] = e->l->next;
127
l_pair[0] = e->l->next;
138
* Copy loop pair from one side to the other if either is missing,
139
* this simplifies interpolation code so we only need to check if x/y are missing,
140
* rather then checking each loop.
142
static void bm_loop_pair_test_copy(BMLoop *l_pair_a[2], BMLoop *l_pair_b[2])
144
/* if the first one is set, we know the second is too */
145
if (l_pair_a[0] && l_pair_b[0] == NULL) {
146
l_pair_b[0] = l_pair_a[1];
147
l_pair_b[1] = l_pair_a[0];
149
else if (l_pair_b[0] && l_pair_a[0] == NULL) {
150
l_pair_a[0] = l_pair_b[1];
151
l_pair_a[1] = l_pair_b[0];
156
* Interpolate from boundary loops.
158
* \note These weights will be calculated multiple times per vertex.
160
static void bm_loop_interp_from_grid_boundary_4(BMesh *bm, BMLoop *l, BMLoop *l_bound[4], const float w[4])
163
l_bound[0]->head.data,
164
l_bound[1]->head.data,
165
l_bound[2]->head.data,
166
l_bound[3]->head.data};
168
CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 4, l->head.data);
171
static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, BMLoop *l, BMLoop *l_bound[2], const float t)
175
l_bound[0]->head.data,
176
l_bound[1]->head.data};
178
const float w[2] = {1.0f - t, t};
180
CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 2, l->head.data);
187
* Avoids calling #barycentric_weights_v2_quad often by caching weights into an array.
189
static void barycentric_weights_v2_grid_cache(const unsigned int xtot, const unsigned int ytot,
190
float (*weight_table)[4])
192
float x_step = 1.0f / (float)(xtot - 1);
193
float y_step = 1.0f / (float)(ytot - 1);
198
for (y = 0; y < ytot; y++) {
199
xy_fl[1] = y_step * (float)y;
200
for (x = 0; x < xtot; x++) {
201
xy_fl[0] = x_step * (float)x;
203
const float cos[4][2] = {
208
barycentric_weights_v2_quad(UNPACK4(cos), xy_fl, weight_table[i++]);
107
216
* This may be useful outside the bmesh operator.
109
218
* \param v_grid 2d array of verts, all boundary verts must be set, we fill in the middle.
111
static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const int ytot,
220
static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xtot, unsigned const int ytot,
112
221
const short mat_nr, const bool use_smooth,
222
const bool use_flip, const bool use_interp_simple)
115
224
const bool use_vert_interp = CustomData_has_interp(&bm->vdata);
225
const bool use_loop_interp = CustomData_has_interp(&bm->ldata);
228
/* for use_loop_interp */
229
BMLoop *((*larr_x_a)[2]), *((*larr_x_b)[2]), *((*larr_y_a)[2]), *((*larr_y_b)[2]);
231
float (*weight_table)[4];
118
233
#define XY(_x, _y) ((_x) + ((_y) * (xtot)))
259
if (use_interp_simple || use_vert_interp || use_loop_interp) {
260
weight_table = MEM_mallocN(sizeof(*weight_table) * (size_t)(xtot * ytot), __func__);
261
barycentric_weights_v2_grid_cache(xtot, ytot, weight_table);
269
if (use_loop_interp) {
270
/* x2 because each edge connects 2 loops */
271
larr_x_a = MEM_mallocN(sizeof(*larr_x_a) * (xtot - 1), __func__);
272
larr_x_b = MEM_mallocN(sizeof(*larr_x_b) * (xtot - 1), __func__);
274
larr_y_a = MEM_mallocN(sizeof(*larr_y_a) * (ytot - 1), __func__);
275
larr_y_b = MEM_mallocN(sizeof(*larr_y_b) * (ytot - 1), __func__);
277
/* fill in the loops */
278
for (x = 0; x < xtot - 1; x++) {
279
bm_loop_pair_from_verts(v_grid[XY(x, 0)], v_grid[XY(x + 1, 0)], larr_x_a[x]);
280
bm_loop_pair_from_verts(v_grid[XY(x, ytot - 1)], v_grid[XY(x + 1, ytot - 1)], larr_x_b[x]);
281
bm_loop_pair_test_copy(larr_x_a[x], larr_x_b[x]);
284
for (y = 0; y < ytot - 1; y++) {
285
bm_loop_pair_from_verts(v_grid[XY(0, y)], v_grid[XY(0, y + 1)], larr_y_a[y]);
286
bm_loop_pair_from_verts(v_grid[XY(xtot - 1, y)], v_grid[XY(xtot - 1, y + 1)], larr_y_b[y]);
287
bm_loop_pair_test_copy(larr_y_a[y], larr_y_b[y]);
144
292
/* Build Verts */
145
293
for (y = 1; y < ytot - 1; y++) {
146
294
#ifdef BARYCENTRIC_INTERP
179
327
interp_v3_v3v3(co, co_a, co_b, (float)y / ((float)ytot - 1));
186
v_grid[(xtot * ytot) + (x - xtot)]->co,
187
(float)y / ((float)ytot - 1));
190
v = BM_vert_create(bm, co, NULL, 0);
332
const float *w = weight_table[XY(x, y)];
335
madd_v3_v3fl(co, v_grid[XY(x, 0)]->co, w[0]);
336
madd_v3_v3fl(co, v_grid[XY(0, y)]->co, w[1]);
337
madd_v3_v3fl(co, v_grid[XY(x, ytot - 1)]->co, w[2]);
338
madd_v3_v3fl(co, v_grid[XY(xtot - 1, y)]->co, w[3]);
341
v = BM_vert_create(bm, co, NULL, BM_CREATE_NOP);
191
342
v_grid[(y * xtot) + x] = v;
193
344
/* interpolate only along one axis, this could be changed
194
345
* but from user pov gives predictable results since these are selected loop */
195
346
if (use_vert_interp) {
197
v_grid[XY(x, 0)]->head.data,
198
v_grid[XY(x, (ytot - 1))]->head.data,
347
const float *w = weight_table[XY(x, y)];
350
v_grid[XY(x, 0)]->head.data,
351
v_grid[XY(0, y)]->head.data,
352
v_grid[XY(x, ytot - 1)]->head.data,
353
v_grid[XY(xtot - 1, y)]->head.data,
200
const float t = (float)y / ((float)ytot - 1);
201
const float w[2] = {1.0f - t, t};
202
CustomData_bmesh_interp(&bm->vdata, v_cdata, w, NULL, 2, v->head.data);
356
CustomData_bmesh_interp(&bm->vdata, v_cdata, w, NULL, 4, v->head.data);
228
382
v_grid[XY(x, y + 1)], /* TL */
229
383
v_grid[XY(x, y + 0)], /* BL */
389
if (use_loop_interp && (larr_x_a[x][0] || larr_y_a[y][0])) {
390
/* bottom/left/top/right */
394
unsigned int x_side, y_side, i;
398
if (larr_x_a[x][0] && larr_y_a[y][0]) {
399
interp_from = 'B'; /* B == both */
400
l_tmp = larr_x_a[x][0];
402
else if (larr_x_a[x][0]) {
404
l_tmp = larr_x_a[x][0];
408
l_tmp = larr_y_a[y][0];
411
BM_elem_attrs_copy(bm, bm, l_tmp->f, f);
414
BM_face_as_array_loop_quad(f, l_quad);
416
l_tmp = BM_FACE_FIRST_LOOP(f);
419
l_quad[0] = l_tmp; l_tmp = l_tmp->next;
420
l_quad[1] = l_tmp; l_tmp = l_tmp->next;
421
l_quad[3] = l_tmp; l_tmp = l_tmp->next;
425
l_quad[2] = l_tmp; l_tmp = l_tmp->next;
426
l_quad[3] = l_tmp; l_tmp = l_tmp->next;
427
l_quad[1] = l_tmp; l_tmp = l_tmp->next;
433
for (x_side = 0; x_side < 2; x_side++) {
434
for (y_side = 0; y_side < 2; y_side++) {
435
if (interp_from == 'B') {
436
const float *w = weight_table[XY(x + x_side, y + y_side)];
437
l_bound[0] = larr_x_a[x][x_side]; /* B */
438
l_bound[1] = larr_y_a[y][y_side]; /* L */
439
l_bound[2] = larr_x_b[x][x_side]; /* T */
440
l_bound[3] = larr_y_b[y][y_side]; /* R */
442
bm_loop_interp_from_grid_boundary_4(bm, l_quad[i++], l_bound, w);
444
else if (interp_from == 'X') {
445
const float t = (float)(y + y_side) / (float)(ytot - 1);
446
l_bound[0] = larr_x_a[x][x_side]; /* B */
447
l_bound[1] = larr_x_b[x][x_side]; /* T */
449
bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t);
451
else if (interp_from == 'Y') {
452
const float t = (float)(x + x_side) / (float)(xtot - 1);
453
l_bound[0] = larr_y_a[y][y_side]; /* L */
454
l_bound[1] = larr_y_b[y][y_side]; /* R */
456
bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t);
233
467
BMO_elem_flag_enable(bm, f, FACE_OUT);
234
468
f->mat_nr = mat_nr;
235
469
if (use_smooth) {
475
if (use_loop_interp) {
483
MEM_freeN(weight_table);
243
489
static void bm_grid_fill(BMesh *bm,
244
490
struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b,
245
491
struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b,
246
const short mat_nr, const bool use_smooth)
492
const short mat_nr, const bool use_smooth, const bool use_interp_simple)
248
494
#define USE_FLIP_DETECT
250
const int xtot = BM_edgeloop_length_get(estore_a);
251
const int ytot = BM_edgeloop_length_get(estore_rail_a);
496
const unsigned int xtot = (unsigned int)BM_edgeloop_length_get(estore_a);
497
const unsigned int ytot = (unsigned int)BM_edgeloop_length_get(estore_rail_a);
258
504
bool use_flip = false;
343
589
struct BMEdgeLoopStore *estore_rail_a, *estore_rail_b;
344
590
BMVert *v_a_first, *v_a_last;
345
591
BMVert *v_b_first, *v_b_last;
346
const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr");
347
const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth");
592
const short mat_nr = (short)BMO_slot_int_get(op->slots_in, "mat_nr");
593
const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth");
594
const bool use_interp_simple = BMO_slot_bool_get(op->slots_in, "use_interp_simple");
350
597
bool change = false;