46
/* -------------------------------------------------------------------- */
47
/* Inset Individual */
50
/* Holds Per-Face Inset Edge Data */
51
typedef struct EdgeInsetInfo {
58
* Individual Face Inset.
59
* Find all tagged faces (f), duplicate edges around faces, inset verts of
60
* created edges, create new faces between old and new edges, fill face
61
* between connected new edges, kill old face (f).
63
void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
65
BMEdge **f_edges = NULL;
66
BMVert **f_verts = NULL;
70
EdgeInsetInfo *eiinfo_arr = NULL;
72
BLI_array_declare(eiinfo_arr);
73
BLI_array_declare(f_edges);
74
BLI_array_declare(f_verts);
76
const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
77
const float depth = BMO_slot_float_get(op->slots_in, "depth");
78
const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
79
const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
80
const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
82
/* Only tag faces in slot */
83
BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
85
BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
87
BMO_ITER(f, &oiter, op->slots_in, "faces", BM_FACE) {
89
BMLoop *l_iter, *l_first;
90
BMLoop *l_iter_inner = NULL;
93
BLI_array_empty(f_verts);
94
BLI_array_empty(f_edges);
95
BLI_array_empty(eiinfo_arr);
96
BLI_array_grow_items(f_verts, f->len);
97
BLI_array_grow_items(f_edges, f->len);
98
BLI_array_grow_items(eiinfo_arr, f->len);
102
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
104
f_verts[i] = BM_vert_create(bm, l_iter->v->co, l_iter->v, 0);
106
} while ((l_iter = l_iter->next) != l_first);
112
f_edges[i] = BM_edge_create(bm, f_verts[i], f_verts[(i + 1) % f->len], l_iter->e, 0);
114
eiinfo_arr[i].e_new = f_edges[i];
115
eiinfo_arr[i].e_old = l_iter->e;
116
BM_edge_calc_face_tangent(l_iter->e, l_iter, eiinfo_arr[i].no);
118
/* Tagging (old elements) required when iterating over edges
119
* connected to verts for translation vector calculation */
120
BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
121
BM_elem_index_set(l_iter->e, i); /* set_dirty! */
123
} while ((l_iter = l_iter->next) != l_first);
124
/* done with edges */
126
bm->elem_index_dirty |= BM_EDGE;
128
/* Calculate translation vector for new */
131
EdgeInsetInfo *ei_prev = &eiinfo_arr[BM_elem_index_get(l_iter->prev->e)];
132
EdgeInsetInfo *ei_next = &eiinfo_arr[BM_elem_index_get(l_iter->e)];
137
add_v3_v3v3(tvec, ei_prev->no, ei_next->no);
140
/* l->e is traversed in order */
141
index = BM_elem_index_get(l_iter->e);
143
copy_v3_v3(v_new_co, eiinfo_arr[index].e_new->v1->co);
145
if (use_even_offset) {
146
mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(ei_prev->no, ei_next->no) / 2.0f));
149
/* Modify vertices and their normals */
150
if (use_relative_offset) {
151
mul_v3_fl(tvec, (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f);
154
madd_v3_v3fl(v_new_co, tvec, thickness);
156
/* Set normal, add depth and write new vertex position*/
157
copy_v3_v3(eiinfo_arr[index].e_new->v1->no, f->no);
159
madd_v3_v3fl(v_new_co, f->no, depth);
161
copy_v3_v3(eiinfo_arr[index].e_new->v1->co, v_new_co);
162
} while ((l_iter = l_iter->next) != l_first);
165
/* Create New Inset Faces */
166
f_new_inner = BM_face_create(bm, f_verts, f_edges, f->len, 0);
167
BLI_assert(f_new_inner != NULL); /* no reason it should fail */
170
// Don't tag, gives more useful inner/outer select option
171
// BMO_elem_flag_enable(bm, f_new_inner, ELE_NEW);
175
/* interpolate loop data or just stretch */
176
if (use_interpolate) {
177
BM_face_interp_from_face(bm, f_new_inner, f, true);
180
BM_elem_attrs_copy(bm, bm, f, f_new_inner);
183
l_iter_inner = BM_FACE_FIRST_LOOP(f_new_inner);
191
if (use_interpolate == false) {
192
BM_elem_attrs_copy(bm, bm, l_iter, l_iter_inner);
195
f_new_outer = BM_face_create_quad_tri(bm,
198
l_iter_inner->next->v,
202
BLI_assert(f_new_outer != NULL); /* no reason it should fail */
204
BM_elem_attrs_copy(bm, bm, f, f_new_outer);
205
BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW);
206
BM_elem_flag_enable(f_new_outer, BM_ELEM_TAG);
209
l_a = BM_FACE_FIRST_LOOP(f_new_outer);
213
BM_elem_attrs_copy(bm, bm, l_iter, l_a);
214
BM_elem_attrs_copy(bm, bm, l_iter->next, l_b);
217
/* Move to the last two loops in new face */
221
/* This loop should always have >1 radials
222
* (associated edge connects new and old face) */
223
BM_elem_attrs_copy(bm, bm, l_iter_inner, l_b);
224
BM_elem_attrs_copy(bm, bm, use_interpolate ? l_iter_inner->next : l_iter->next, l_a);
226
} while ((l_iter_inner = l_iter_inner->next),
227
(l_iter = l_iter->next) != l_first);
232
/* we could flag new edges/verts too, is it useful? */
233
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW);
235
BLI_array_free(f_verts);
236
BLI_array_free(f_edges);
237
BLI_array_free(eiinfo_arr);
242
/* -------------------------------------------------------------------- */
245
typedef struct SplitEdgeInfo {
46
/* -------------------------------------------------------------------- */
47
/* Generic Interp Face (use for both types of inset) */
255
50
* Interpolation, this is more complex for regions since we're not creating new faces
110
/* -------------------------------------------------------------------- */
111
/* Inset Individual */
113
static void bmo_face_inset_individual(
114
BMesh *bm, BMFace *f, MemArena *interp_arena,
115
const float thickness, const float depth,
116
const bool use_even_offset, const bool use_relative_offset, const bool use_interpolate)
118
InterpFace *iface = NULL;
120
/* stores verts split away from the face (aligned with face verts) */
121
BMVert **verts = BLI_array_alloca(verts, f->len);
122
/* store edge normals (aligned with face-loop-edges) */
123
float (*edge_nors)[3] = BLI_array_alloca(edge_nors, f->len);
124
float (*coords)[3] = BLI_array_alloca(coords, f->len);
126
BMLoop *l_iter, *l_first;
131
l_first = BM_FACE_FIRST_LOOP(f);
133
/* split off all loops */
137
BMVert *v_other = l_iter->v;
138
BMVert *v_sep = BM_face_loop_separate(bm, l_iter);
139
if (v_sep == v_other) {
140
v_other = BM_vert_create(bm, l_iter->v->co, l_iter->v, BM_CREATE_NOP);
144
/* unrelated to splitting, but calc here */
145
BM_edge_calc_face_tangent(l_iter->e, l_iter, edge_nors[i]);
146
} while (i++, ((l_iter = l_iter->next) != l_first));
149
/* build rim faces */
154
BMVert *v_other = verts[i];
155
BMVert *v_other_next = verts[(i + 1) % f->len];
157
BMEdge *e_other = BM_edge_create(bm, v_other, v_other_next, l_iter->e, BM_CREATE_NO_DOUBLE);
160
f_new_outer = BM_face_create_quad_tri(bm,
166
BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW);
169
l_other = l_iter->radial_next;
170
BM_elem_attrs_copy(bm, bm, l_iter->next, l_other->prev);
171
BM_elem_attrs_copy(bm, bm, l_iter, l_other->next->next);
173
if (use_interpolate == false) {
174
BM_elem_attrs_copy(bm, bm, l_iter->next, l_other);
175
BM_elem_attrs_copy(bm, bm, l_iter, l_other->next);
177
} while (i++, ((l_iter = l_iter->next) != l_first));
179
/* hold interpolation values */
180
if (use_interpolate) {
181
iface = BLI_memarena_alloc(interp_arena, sizeof(*iface));
182
bm_interp_face_store(iface, bm, f, interp_arena);
185
/* Calculate translation vector for new */
190
e_length_prev = BM_edge_calc_length(l_iter->prev->e);
194
const float *eno_prev = edge_nors[(i ? i : f->len) - 1];
195
const float *eno_next = edge_nors[i];
199
add_v3_v3v3(tvec, eno_prev, eno_next);
202
copy_v3_v3(v_new_co, l_iter->v->co);
204
if (use_even_offset) {
205
mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(eno_prev, eno_next) / 2.0f));
208
/* Modify vertices and their normals */
209
if (use_relative_offset) {
210
mul_v3_fl(tvec, (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f);
213
madd_v3_v3fl(v_new_co, tvec, thickness);
215
/* Set normal, add depth and write new vertex position*/
216
copy_v3_v3(l_iter->v->no, f->no);
219
const float e_length = BM_edge_calc_length(l_iter->e);
220
const float fac = depth * (use_relative_offset ? ((e_length_prev + e_length) * 0.5f) : 1.0f);
221
e_length_prev = e_length;
223
madd_v3_v3fl(v_new_co, f->no, fac);
228
copy_v3_v3(coords[i], v_new_co);
229
} while (i++, ((l_iter = l_iter->next) != l_first));
231
/* update the coords */
235
copy_v3_v3(l_iter->v->co, coords[i]);
236
} while (i++, ((l_iter = l_iter->next) != l_first));
239
if (use_interpolate) {
240
BM_face_interp_from_face_ex(bm, iface->f, iface->f, true,
241
iface->blocks_l, iface->blocks_v, iface->cos_2d, iface->axis_mat);
243
/* build rim faces */
247
l_other = l_iter->radial_next;
249
BM_elem_attrs_copy(bm, bm, l_iter->next, l_other);
250
BM_elem_attrs_copy(bm, bm, l_iter, l_other->next);
251
} while ((l_iter = l_iter->next) != l_first);
253
bm_interp_face_free(iface, bm);
259
* Individual Face Inset.
260
* Find all tagged faces (f), duplicate edges around faces, inset verts of
261
* created edges, create new faces between old and new edges, fill face
262
* between connected new edges, kill old face (f).
264
void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
269
MemArena *interp_arena = NULL;
271
const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
272
const float depth = BMO_slot_float_get(op->slots_in, "depth");
273
const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
274
const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
275
const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
277
/* Only tag faces in slot */
278
BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
280
BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
282
if (use_interpolate) {
283
interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
286
BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
287
bmo_face_inset_individual(
290
use_even_offset, use_relative_offset, use_interpolate);
292
if (use_interpolate) {
293
BLI_memarena_clear(interp_arena);
297
/* we could flag new edges/verts too, is it useful? */
298
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW);
300
if (use_interpolate) {
301
BLI_memarena_free(interp_arena);
307
/* -------------------------------------------------------------------- */
310
typedef struct SplitEdgeInfo {
314
319
* return the tag loop where there is...
315
320
* - only 1 tagged face attached to this edge.