Blender V5.0
editmesh_preselect_edgering.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
8
9#include "MEM_guardedalloc.h"
10
11#include "DNA_userdef_types.h"
12
13#include "BLI_math_vector.h"
14#include "BLI_stack.h"
15
16#include "GPU_immediate.hh"
17#include "GPU_matrix.hh"
18#include "GPU_state.hh"
19
20#include "ED_mesh.hh"
21
22#include "UI_resources.hh"
23
24#include "bmesh.hh"
25
26using blender::float3;
27using blender::Span;
28
29/* -------------------------------------------------------------------- */
40
41static void edgering_vcos_get(BMVert *v[2][2],
42 float r_cos[2][2][3],
43 const Span<float3> vert_positions)
44{
45 if (!vert_positions.is_empty()) {
46 int j, k;
47 for (j = 0; j < 2; j++) {
48 for (k = 0; k < 2; k++) {
49 copy_v3_v3(r_cos[j][k], vert_positions[BM_elem_index_get(v[j][k])]);
50 }
51 }
52 }
53 else {
54 int j, k;
55 for (j = 0; j < 2; j++) {
56 for (k = 0; k < 2; k++) {
57 copy_v3_v3(r_cos[j][k], v[j][k]->co);
58 }
59 }
60 }
61}
62
64 float r_cos[2][3],
65 const Span<float3> vert_positions)
66{
67 if (!vert_positions.is_empty()) {
68 int j;
69 for (j = 0; j < 2; j++) {
70 copy_v3_v3(r_cos[j], vert_positions[BM_elem_index_get(v[j])]);
71 }
72 }
73 else {
74 int j;
75 for (j = 0; j < 2; j++) {
76 copy_v3_v3(r_cos[j], v[j]->co);
77 }
78 }
79}
80
85static void edgering_find_order(BMEdge *eed_last, BMEdge *eed, BMVert *eve_last, BMVert *v[2][2])
86{
87 BMLoop *l = eed->l;
88
89 /* find correct order for v[1] */
90 if (!(BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))) {
91 BMIter liter;
92 BM_ITER_ELEM (l, &liter, l, BM_LOOPS_OF_LOOP) {
93 if (BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f)) {
94 break;
95 }
96 }
97 }
98
99 /* this should never happen */
100 if (!l) {
101 v[0][0] = eed->v1;
102 v[0][1] = eed->v2;
103 v[1][0] = eed_last->v1;
104 v[1][1] = eed_last->v2;
105 return;
106 }
107
108 BMLoop *l_other = BM_loop_other_edge_loop(l, eed->v1);
109 const bool rev = (l_other == l->prev);
110 while (!ELEM(l_other->v, eed_last->v1, eed_last->v2)) {
111 l_other = rev ? l_other->prev : l_other->next;
112 }
113
114 if (l_other->v == eve_last) {
115 v[0][0] = eed->v1;
116 v[0][1] = eed->v2;
117 }
118 else {
119 v[0][0] = eed->v2;
120 v[0][1] = eed->v1;
121 }
122}
123
131
133{
135 MEM_callocN(sizeof(*psel), __func__));
136 return psel;
137}
138
144
146{
147 MEM_SAFE_FREE(psel->edges);
148 psel->edges_len = 0;
149
150 MEM_SAFE_FREE(psel->verts);
151 psel->verts_len = 0;
152}
153
154void EDBM_preselect_edgering_draw(EditMesh_PreSelEdgeRing *psel, const float matrix[4][4])
155{
156 if ((psel->edges_len == 0) && (psel->verts_len == 0)) {
157 return;
158 }
159
162
164 GPU_matrix_mul(matrix);
165
167 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
168
169 if (psel->edges_len > 0) {
170 float viewport[4];
171 GPU_viewport_size_get_f(viewport);
172
174 immUniform2fv("viewportSize", &viewport[2]);
176 immUniform1f("lineWidth", U.pixelsize);
178
179 for (int i = 0; i < psel->edges_len; i++) {
180 immVertex3fv(pos, psel->edges[i][0]);
181 immVertex3fv(pos, psel->edges[i][1]);
182 }
183
184 immEnd();
186 }
187
188 if (psel->verts_len > 0) {
192
193 /* Same size as an edit mode vertex */
194 immUniform1f("size",
195 2.0 * U.pixelsize *
196 max_ff(1.0f, UI_GetThemeValuef(TH_VERTEX_SIZE) * float(M_SQRT2) / 2.0f));
197
199
200 for (int i = 0; i < psel->verts_len; i++) {
201 immVertex3fv(pos, psel->verts[i]);
202 }
203
204 immEnd();
207 }
208
210
211 /* Reset default */
214}
215
218 BMesh * /*bm*/,
219 BMEdge *eed_start,
220 int previewlines,
221 const Span<float3> vert_positions)
222{
223 float v_cos[2][3];
224 float (*verts)[3];
225 int i, tot = 0;
226
227 verts = static_cast<float (*)[3]>(MEM_mallocN(sizeof(*psel->verts) * previewlines, __func__));
228
229 edgering_vcos_get_pair(&eed_start->v1, v_cos, vert_positions);
230
231 for (i = 1; i <= previewlines; i++) {
232 const float fac = (i / (float(previewlines) + 1));
233 interp_v3_v3v3(verts[tot], v_cos[0], v_cos[1], fac);
234 tot++;
235 }
236
237 psel->verts = verts;
238 psel->verts_len = previewlines;
239}
240
243 BMesh *bm,
244 BMEdge *eed_start,
245 int previewlines,
246 const Span<float3> vert_positions)
247{
248 BMWalker walker;
249 BMEdge *eed, *eed_last;
250 BMVert *v[2][2] = {{nullptr}}, *eve_last;
251 float (*edges)[2][3] = nullptr;
252 BLI_Stack *edge_stack;
253
254 int i, tot = 0;
255
256 BMW_init(&walker,
257 bm,
264
265 edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
266
267 eed_last = nullptr;
268 for (eed = eed_last = static_cast<BMEdge *>(BMW_begin(&walker, eed_start)); eed;
269 eed = static_cast<BMEdge *>(BMW_step(&walker)))
270 {
271 BLI_stack_push(edge_stack, &eed);
272 }
273 BMW_end(&walker);
274
275 eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
276
277 edges = static_cast<float (*)[2][3]>(MEM_mallocN(
278 (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines,
279 __func__));
280
281 eve_last = nullptr;
282 eed_last = nullptr;
283
284 while (!BLI_stack_is_empty(edge_stack)) {
285 BLI_stack_pop(edge_stack, &eed);
286
287 if (eed_last) {
288 if (eve_last) {
289 v[1][0] = v[0][0];
290 v[1][1] = v[0][1];
291 }
292 else {
293 v[1][0] = eed_last->v1;
294 v[1][1] = eed_last->v2;
295 eve_last = eed_last->v1;
296 }
297
298 edgering_find_order(eed_last, eed, eve_last, v);
299 eve_last = v[0][0];
300
301 for (i = 1; i <= previewlines; i++) {
302 const float fac = (i / (float(previewlines) + 1));
303 float v_cos[2][2][3];
304
305 edgering_vcos_get(v, v_cos, vert_positions);
306
307 interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
308 interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
309 tot++;
310 }
311 }
312 eed_last = eed;
313 }
314
315 if ((eed_last != eed_start) &&
316#ifdef BMW_EDGERING_NGON
317 BM_edge_share_face_check(eed_last, eed_start)
318#else
319 BM_edge_share_quad_check(eed_last, eed_start)
320#endif
321 )
322 {
323 v[1][0] = v[0][0];
324 v[1][1] = v[0][1];
325
326 edgering_find_order(eed_last, eed_start, eve_last, v);
327
328 for (i = 1; i <= previewlines; i++) {
329 const float fac = (i / (float(previewlines) + 1));
330 float v_cos[2][2][3];
331
332 if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) {
333 continue;
334 }
335
336 edgering_vcos_get(v, v_cos, vert_positions);
337
338 interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
339 interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
340 tot++;
341 }
342 }
343
344 BLI_stack_free(edge_stack);
345
346 psel->edges = edges;
347 psel->edges_len = tot;
348}
349
351 BMesh *bm,
352 BMEdge *eed_start,
353 int previewlines,
354 const Span<float3> vert_positions)
355{
357
358 if (!vert_positions.is_empty()) {
360 }
361
362 if (BM_edge_is_any_face_len_test(eed_start, 4)) {
364 psel, bm, eed_start, previewlines, vert_positions);
365 }
366 else {
368 psel, bm, eed_start, previewlines, vert_positions);
369 }
370}
371
MINLINE float max_ff(float a, float b)
#define M_SQRT2
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL()
Definition stack.cc:138
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:228
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
Definition stack.cc:132
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:250
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.cc:96
void * BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:169
#define BLI_stack_new(esize, descr)
unsigned int uint
#define ELEM(...)
void immEnd()
void immUniform2fv(const char *name, const float data[2])
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immUniformThemeColor3(int color_id)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void GPU_matrix_push()
#define GPU_matrix_mul(x)
void GPU_matrix_pop()
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR
@ GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA
void GPU_program_point_size(bool enable)
Definition gpu_state.cc:180
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:114
@ GPU_DEPTH_NONE
Definition GPU_state.hh:111
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_depth_test(GPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ TH_VERTEX_SIZE
@ TH_GIZMO_PRIMARY
float UI_GetThemeValuef(int colorid)
#define U
#define BM_elem_index_get(ele)
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_LOOPS_OF_LOOP
BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
#define BM_VERT
BMLoop * BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len)
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
void * BMW_begin(BMWalker *walker, void *start)
void BMW_init(BMWalker *walker, BMesh *bm, int type, short mask_vert, short mask_edge, short mask_face, BMWFlag flag, int layer)
Initialize Walker.
void BMW_end(BMWalker *walker)
End Walker.
void * BMW_step(BMWalker *walker)
Step Walker.
#define BMW_NIL_LAY
@ BMW_FLAG_TEST_HIDDEN
#define BMW_MASK_NOP
@ BMW_EDGERING
constexpr bool is_empty() const
Definition BLI_span.hh:260
nullptr float
void EDBM_preselect_edgering_destroy(EditMesh_PreSelEdgeRing *psel)
static void view3d_preselect_mesh_edgering_update_verts_from_edge(EditMesh_PreSelEdgeRing *psel, BMesh *, BMEdge *eed_start, int previewlines, const Span< float3 > vert_positions)
void EDBM_preselect_edgering_clear(EditMesh_PreSelEdgeRing *psel)
void EDBM_preselect_edgering_draw(EditMesh_PreSelEdgeRing *psel, const float matrix[4][4])
static void edgering_vcos_get_pair(BMVert *v[2], float r_cos[2][3], const Span< float3 > vert_positions)
EditMesh_PreSelEdgeRing * EDBM_preselect_edgering_create()
void EDBM_preselect_edgering_update_from_edge(EditMesh_PreSelEdgeRing *psel, BMesh *bm, BMEdge *eed_start, int previewlines, const Span< float3 > vert_positions)
static void view3d_preselect_mesh_edgering_update_edges_from_edge(EditMesh_PreSelEdgeRing *psel, BMesh *bm, BMEdge *eed_start, int previewlines, const Span< float3 > vert_positions)
static void edgering_find_order(BMEdge *eed_last, BMEdge *eed, BMVert *eve_last, BMVert *v[2][2])
static void edgering_vcos_get(BMVert *v[2][2], float r_cos[2][2][3], const Span< float3 > vert_positions)
static float verts[][3]
uint pos
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
VecBase< float, 3 > float3
BMVert * v1
BMVert * v2
struct BMLoop * l
struct BMVert * v
struct BMLoop * prev
struct BMLoop * next
i
Definition text_draw.cc:230