Blender V4.3
bmo_offset_edgeloops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14#include "MEM_guardedalloc.h"
15
16#include "BLI_alloca.h"
17#include "BLI_math_vector.h"
19
20#include "BKE_customdata.hh"
21
22#include "bmesh.hh"
23
24#include "intern/bmesh_operators_private.hh" /* own include */
25
26#define USE_CAP_OPTION
27
28#define ELE_NEW (1 << 0)
29
30#ifdef USE_CAP_OPTION
31# define ELE_VERT_ENDPOINT (1 << 1)
32#endif
33
34/* set for debugging */
35#define OFFSET 0.0f
36
38{
39 float(*cos)[3];
40 BMLoop *l_dst;
41 BMFace *f;
42 int num, i;
43
44 for (l_dst = l_src->prev, num = 0; BM_elem_index_get(l_dst->prev->v) != -1;
45 l_dst = l_dst->prev, num++)
46 {
47 /* pass */
48 }
49
50 BLI_assert(num != 0);
51
52 cos = BLI_array_alloca(cos, num);
53
54 for (l_dst = l_src->prev, i = 0; BM_elem_index_get(l_dst->prev->v) != -1;
55 l_dst = l_dst->prev, i++)
56 {
57 copy_v3_v3(cos[num - (i + 1)], l_dst->v->co);
58 }
59
60 f = BM_face_split_n(bm, l_src->f, l_dst->prev, l_src->next, cos, num, r_l, nullptr);
61
62 return f;
63}
64
66{
67 const int edges_num = BMO_slot_buffer_len(op->slots_in, "edges");
68 BMVert **verts;
70 int i;
71
72#ifdef USE_CAP_OPTION
73 bool use_cap_endpoint = BMO_slot_bool_get(op->slots_in, "use_cap_endpoint");
74 int v_edges_max = 0;
75#endif
76
77 BMOIter oiter;
78
79 /* only so we can detect new verts (index == -1) */
81
83
84 /* over alloc */
85 verts = static_cast<BMVert **>(MEM_mallocN(sizeof(*verts) * (edges_num * 2), __func__));
86
87 STACK_INIT(verts, (edges_num * 2));
88
89 {
90 BMEdge *e;
91 BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) {
92 int j;
93
95
96 for (j = 0; j < 2; j++) {
97 BMVert *v_edge = *(&(e->v1) + j);
98 if (!BM_elem_flag_test(v_edge, BM_ELEM_TAG)) {
100 STACK_PUSH(verts, v_edge);
101 }
102 }
103 }
104 }
105
106 /* -------------------------------------------------------------------- */
107 /* Remove verts only used by tagged edges */
108
109 for (i = 0; i < STACK_SIZE(verts); i++) {
110 BMIter iter;
111 int flag = 0;
112 BMEdge *e;
113
114 BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) {
115 flag |= BM_elem_flag_test(e, BM_ELEM_TAG) ? 1 : 2;
116 if (flag == (1 | 2)) {
117 break;
118 }
119 }
120
121 /* only boundary verts are interesting */
122 if (flag != (1 | 2)) {
124 }
125 }
126
127 /* possible but unlikely we have no mixed vertices */
128 if (UNLIKELY(STACK_SIZE(verts) == 0)) {
130 return;
131 }
132
133 /* main loop */
134 for (i = 0; i < STACK_SIZE(verts); i++) {
135 int v_edges_num = 0;
136 int v_edges_num_untag = 0;
137 BMVert *v = verts[i];
138 BMIter iter;
139 BMEdge *e;
140
141 BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) {
143 BMVert *v_other;
144 BMIter liter;
145 BMLoop *l;
146
147 BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
149 }
150
151 v_other = BM_edge_other_vert(e, v);
152 BM_edge_split(bm, e, v_other, nullptr, 1.0f - OFFSET);
153 }
154 else {
155 v_edges_num_untag += 1;
156 }
157
158 v_edges_num += 1;
159 }
160
161#ifdef USE_CAP_OPTION
162 if (v_edges_num_untag == 1) {
164 }
165
166 CLAMP_MIN(v_edges_max, v_edges_num);
167#endif
168 }
169
170 for (i = 0; i < STACK_SIZE(verts); i++) {
171 BMVert *v = verts[i];
172 BMIter liter;
173 BMLoop *l;
174
175 BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
176 if (BM_elem_flag_test(l->f, BM_ELEM_TAG) && (l->f->len != 3)) {
177 BMFace *f_cmp = l->f;
178 if ((BM_elem_index_get(l->next->v) == -1) && (BM_elem_index_get(l->prev->v) == -1)) {
179#ifdef USE_CAP_OPTION
180 if (use_cap_endpoint || (BMO_vert_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0))
181#endif
182 {
183 BMLoop *l_new;
184 BM_face_split(bm, l->f, l->prev, l->next, &l_new, nullptr, true);
185 BLI_assert(f_cmp == l->f);
186 BLI_assert(f_cmp != l_new->f);
187 UNUSED_VARS_NDEBUG(f_cmp);
189 }
190 }
191 else if (l->f->len > 4) {
193 if (BM_elem_index_get(l->next->v) == -1) {
194 if (BM_elem_index_get(l->prev->prev->v) == -1) {
195 BMLoop *l_new;
196 BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, nullptr, true);
197 BLI_assert(f_cmp == l->f);
198 BLI_assert(f_cmp != l_new->f);
201 }
202 else {
203 /* walk backwards */
204 BMLoop *l_new;
205 bm_face_split_walk_back(bm, l, &l_new);
206 do {
208 l_new = l_new->next;
209 } while (BM_vert_is_edge_pair(l_new->v));
211 }
212 }
213
214/* NOTE: instead of duplicate code in alternate direction,
215 * we can be sure to hit the other vertex, so the code above runs. */
216#if 0
217 else if (BM_elem_index_get(l->prev->v) == -1) {
218 if (BM_elem_index_get(l->next->next->v) == -1) {
219 /* pass */
220 }
221 }
222#endif
223 }
224 }
225 }
226 }
227 }
228
229#ifdef USE_CAP_OPTION
230 if (use_cap_endpoint == false) {
231 BMVert **varr = BLI_array_alloca(varr, v_edges_max);
232 STACK_DECLARE(varr);
233 BMVert *v;
234
235 for (i = 0; i < STACK_SIZE(verts); i++) {
236 BMIter iter;
237 BMEdge *e;
238
239 v = verts[i];
240
241 STACK_INIT(varr, v_edges_max);
242
243 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
244 BMVert *v_other;
245 v_other = BM_edge_other_vert(e, v);
246 if (BM_elem_index_get(v_other) == -1) {
247 if (BM_vert_is_edge_pair(v_other)) {
248 /* defer bmesh_kernel_join_edge_kill_vert to avoid looping over data we're removing */
249 v_other->e = e;
250 STACK_PUSH(varr, v_other);
251 }
252 }
253 }
254
255 while ((v = STACK_POP(varr))) {
256 bmesh_kernel_join_edge_kill_vert(bm, v->e, v, true, false, false, true);
257 }
258 }
259 }
260#endif
261
263
265}
CustomData interface, see also DNA_customdata_types.h.
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:25
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define CLAMP_MIN(a, b)
#define STACK_POP(stack)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
#define STACK_REMOVE(stack, i)
Read Guarded memory(de)allocation.
@ BM_ELEM_TAG
BMEdge * bmesh_kernel_join_edge_kill_vert(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool check_edge_exists, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Join Edge Kill Vert (JEKV)
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BMFace * BM_face_split_n(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, float cos[][3], int n, BMLoop **r_l, BMEdge *example)
Face Split with intermediate points.
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
BMFace * BM_face_split(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, const bool no_double)
Face Split.
#define BM_FACE
#define BM_EDGE
#define BM_VERT
#define BMO_edge_flag_enable(bm, e, oflag)
#define BMO_vert_flag_enable(bm, e, oflag)
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
#define BMO_vert_flag_test(bm, e, oflag)
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
bool BM_vert_is_edge_pair(const BMVert *v)
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
#define OFFSET
#define ELE_NEW
static BMFace * bm_face_split_walk_back(BMesh *bm, BMLoop *l_src, BMLoop **r_l)
#define ELE_VERT_ENDPOINT
draw_view in_light_buf[] float
static float verts[][3]
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float3 cos(float3 v)
struct BMVert * v
struct BMEdge * e
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
struct BMEdge * e
uint8_t flag
Definition wm_window.cc:138