Blender V4.5
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
125 float (*edges)[2][3];
127
128 float (*verts)[3];
130};
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
168 if (psel->edges_len > 0) {
169 float viewport[4];
170 GPU_viewport_size_get_f(viewport);
171
173 immUniform2fv("viewportSize", &viewport[2]);
175 immUniform1f("lineWidth", U.pixelsize);
177
178 for (int i = 0; i < psel->edges_len; i++) {
179 immVertex3fv(pos, psel->edges[i][0]);
180 immVertex3fv(pos, psel->edges[i][1]);
181 }
182
183 immEnd();
185 }
186
187 if (psel->verts_len > 0) {
191
192 /* Same size as an edit mode vertex */
193 immUniform1f("size",
194 2.0 * U.pixelsize *
195 max_ff(1.0f, UI_GetThemeValuef(TH_VERTEX_SIZE) * float(M_SQRT2) / 2.0f));
196
198
199 for (int i = 0; i < psel->verts_len; i++) {
200 immVertex3fv(pos, psel->verts[i]);
201 }
202
203 immEnd();
206 }
207
209
210 /* Reset default */
213}
214
217 BMesh * /*bm*/,
218 BMEdge *eed_start,
219 int previewlines,
220 const Span<float3> vert_positions)
221{
222 float v_cos[2][3];
223 float(*verts)[3];
224 int i, tot = 0;
225
226 verts = static_cast<float(*)[3]>(MEM_mallocN(sizeof(*psel->verts) * previewlines, __func__));
227
228 edgering_vcos_get_pair(&eed_start->v1, v_cos, vert_positions);
229
230 for (i = 1; i <= previewlines; i++) {
231 const float fac = (i / (float(previewlines) + 1));
232 interp_v3_v3v3(verts[tot], v_cos[0], v_cos[1], fac);
233 tot++;
234 }
235
236 psel->verts = verts;
237 psel->verts_len = previewlines;
238}
239
242 BMesh *bm,
243 BMEdge *eed_start,
244 int previewlines,
245 const Span<float3> vert_positions)
246{
247 BMWalker walker;
248 BMEdge *eed, *eed_last;
249 BMVert *v[2][2] = {{nullptr}}, *eve_last;
250 float(*edges)[2][3] = nullptr;
251 BLI_Stack *edge_stack;
252
253 int i, tot = 0;
254
255 BMW_init(&walker,
256 bm,
263
264 edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
265
266 eed_last = nullptr;
267 for (eed = eed_last = static_cast<BMEdge *>(BMW_begin(&walker, eed_start)); eed;
268 eed = static_cast<BMEdge *>(BMW_step(&walker)))
269 {
270 BLI_stack_push(edge_stack, &eed);
271 }
272 BMW_end(&walker);
273
274 eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
275
276 edges = static_cast<float(*)[2][3]>(MEM_mallocN(
277 (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines,
278 __func__));
279
280 eve_last = nullptr;
281 eed_last = nullptr;
282
283 while (!BLI_stack_is_empty(edge_stack)) {
284 BLI_stack_pop(edge_stack, &eed);
285
286 if (eed_last) {
287 if (eve_last) {
288 v[1][0] = v[0][0];
289 v[1][1] = v[0][1];
290 }
291 else {
292 v[1][0] = eed_last->v1;
293 v[1][1] = eed_last->v2;
294 eve_last = eed_last->v1;
295 }
296
297 edgering_find_order(eed_last, eed, eve_last, v);
298 eve_last = v[0][0];
299
300 for (i = 1; i <= previewlines; i++) {
301 const float fac = (i / (float(previewlines) + 1));
302 float v_cos[2][2][3];
303
304 edgering_vcos_get(v, v_cos, vert_positions);
305
306 interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
307 interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
308 tot++;
309 }
310 }
311 eed_last = eed;
312 }
313
314 if ((eed_last != eed_start) &&
315#ifdef BMW_EDGERING_NGON
316 BM_edge_share_face_check(eed_last, eed_start)
317#else
318 BM_edge_share_quad_check(eed_last, eed_start)
319#endif
320 )
321 {
322 v[1][0] = v[0][0];
323 v[1][1] = v[0][1];
324
325 edgering_find_order(eed_last, eed_start, eve_last, v);
326
327 for (i = 1; i <= previewlines; i++) {
328 const float fac = (i / (float(previewlines) + 1));
329 float v_cos[2][2][3];
330
331 if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) {
332 continue;
333 }
334
335 edgering_vcos_get(v, v_cos, vert_positions);
336
337 interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
338 interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
339 tot++;
340 }
341 }
342
343 BLI_stack_free(edge_stack);
344
345 psel->edges = edges;
346 psel->edges_len = tot;
347}
348
350 BMesh *bm,
351 BMEdge *eed_start,
352 int previewlines,
353 const Span<float3> vert_positions)
354{
356
357 if (!vert_positions.is_empty()) {
359 }
360
361 if (BM_edge_is_any_face_len_test(eed_start, 4)) {
363 psel, bm, eed_start, previewlines, vert_positions);
364 }
365 else {
367 psel, bm, eed_start, previewlines, vert_positions);
368 }
369}
370
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(eGPUBuiltinShader 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_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:114
@ GPU_DEPTH_NONE
Definition GPU_state.hh:111
void GPU_depth_test(eGPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
@ 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.
@ BMW_EDGERING
#define BMW_NIL_LAY
@ BMW_FLAG_TEST_HIDDEN
#define BMW_MASK_NOP
constexpr bool is_empty() const
Definition BLI_span.hh:260
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
#define MEM_SAFE_FREE(v)
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