Fix T66983 Wireframe Display in edit mode edges missing when overlays are disabled
[blender.git] / source / blender / editors / mesh / editmesh_preselect_edgering.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup edmesh
19  */
20
21 #include "MEM_guardedalloc.h"
22
23 #include "BLI_stack.h"
24 #include "BLI_math.h"
25
26 #include "BKE_editmesh.h"
27
28 #include "GPU_immediate.h"
29 #include "GPU_matrix.h"
30 #include "GPU_state.h"
31
32 #include "ED_mesh.h"
33
34 #include "UI_resources.h"
35
36 /* -------------------------------------------------------------------- */
37 /** \name Mesh Edge Ring Pre-Select
38  * Public API:
39  *
40  * #EDBM_preselect_edgering_create
41  * #EDBM_preselect_edgering_destroy
42  * #EDBM_preselect_edgering_clear
43  * #EDBM_preselect_edgering_draw
44  * #EDBM_preselect_edgering_update_from_edge
45  *
46  * \{ */
47
48 static void edgering_vcos_get(BMVert *v[2][2], float r_cos[2][2][3], const float (*coords)[3])
49 {
50   if (coords) {
51     int j, k;
52     for (j = 0; j < 2; j++) {
53       for (k = 0; k < 2; k++) {
54         copy_v3_v3(r_cos[j][k], coords[BM_elem_index_get(v[j][k])]);
55       }
56     }
57   }
58   else {
59     int j, k;
60     for (j = 0; j < 2; j++) {
61       for (k = 0; k < 2; k++) {
62         copy_v3_v3(r_cos[j][k], v[j][k]->co);
63       }
64     }
65   }
66 }
67
68 static void edgering_vcos_get_pair(BMVert *v[2], float r_cos[2][3], const float (*coords)[3])
69 {
70   if (coords) {
71     int j;
72     for (j = 0; j < 2; j++) {
73       copy_v3_v3(r_cos[j], coords[BM_elem_index_get(v[j])]);
74     }
75   }
76   else {
77     int j;
78     for (j = 0; j < 2; j++) {
79       copy_v3_v3(r_cos[j], v[j]->co);
80     }
81   }
82 }
83
84 /**
85  * Given two opposite edges in a face, finds the ordering of their vertices so
86  * that cut preview lines won't cross each other.
87  */
88 static void edgering_find_order(BMEdge *eed_last, BMEdge *eed, BMVert *eve_last, BMVert *v[2][2])
89 {
90   BMLoop *l = eed->l;
91
92   /* find correct order for v[1] */
93   if (!(BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))) {
94     BMIter liter;
95     BM_ITER_ELEM (l, &liter, l, BM_LOOPS_OF_LOOP) {
96       if (BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f)) {
97         break;
98       }
99     }
100   }
101
102   /* this should never happen */
103   if (!l) {
104     v[0][0] = eed->v1;
105     v[0][1] = eed->v2;
106     v[1][0] = eed_last->v1;
107     v[1][1] = eed_last->v2;
108     return;
109   }
110
111   BMLoop *l_other = BM_loop_other_edge_loop(l, eed->v1);
112   const bool rev = (l_other == l->prev);
113   while (l_other->v != eed_last->v1 && l_other->v != eed_last->v2) {
114     l_other = rev ? l_other->prev : l_other->next;
115   }
116
117   if (l_other->v == eve_last) {
118     v[0][0] = eed->v1;
119     v[0][1] = eed->v2;
120   }
121   else {
122     v[0][0] = eed->v2;
123     v[0][1] = eed->v1;
124   }
125 }
126
127 struct EditMesh_PreSelEdgeRing {
128   float (*edges)[2][3];
129   int edges_len;
130
131   float (*verts)[3];
132   int verts_len;
133 };
134
135 struct EditMesh_PreSelEdgeRing *EDBM_preselect_edgering_create(void)
136 {
137   struct EditMesh_PreSelEdgeRing *psel = MEM_callocN(sizeof(*psel), __func__);
138   return psel;
139 }
140
141 void EDBM_preselect_edgering_destroy(struct EditMesh_PreSelEdgeRing *psel)
142 {
143   EDBM_preselect_edgering_clear(psel);
144   MEM_freeN(psel);
145 }
146
147 void EDBM_preselect_edgering_clear(struct EditMesh_PreSelEdgeRing *psel)
148 {
149   MEM_SAFE_FREE(psel->edges);
150   psel->edges_len = 0;
151
152   MEM_SAFE_FREE(psel->verts);
153   psel->verts_len = 0;
154 }
155
156 void EDBM_preselect_edgering_draw(struct EditMesh_PreSelEdgeRing *psel, const float matrix[4][4])
157 {
158   if ((psel->edges_len == 0) && (psel->verts_len == 0)) {
159     return;
160   }
161
162   GPU_depth_test(false);
163
164   GPU_matrix_push();
165   GPU_matrix_mul(matrix);
166
167   uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
168
169   immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
170   immUniformThemeColor3(TH_GIZMO_PRIMARY);
171
172   if (psel->edges_len > 0) {
173     immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
174
175     for (int i = 0; i < psel->edges_len; i++) {
176       immVertex3fv(pos, psel->edges[i][0]);
177       immVertex3fv(pos, psel->edges[i][1]);
178     }
179
180     immEnd();
181   }
182
183   if (psel->verts_len > 0) {
184     GPU_point_size(3.0f);
185
186     immBegin(GPU_PRIM_POINTS, psel->verts_len);
187
188     for (int i = 0; i < psel->verts_len; i++) {
189       immVertex3fv(pos, psel->verts[i]);
190     }
191
192     immEnd();
193   }
194
195   immUnbindProgram();
196
197   GPU_matrix_pop();
198
199   /* Reset default */
200   GPU_depth_test(true);
201 }
202
203 static void view3d_preselect_mesh_edgering_update_verts_from_edge(
204     struct EditMesh_PreSelEdgeRing *psel,
205     BMesh *UNUSED(bm),
206     BMEdge *eed_start,
207     int previewlines,
208     const float (*coords)[3])
209 {
210   float v_cos[2][3];
211   float(*verts)[3];
212   int i, tot = 0;
213
214   verts = MEM_mallocN(sizeof(*psel->verts) * previewlines, __func__);
215
216   edgering_vcos_get_pair(&eed_start->v1, v_cos, coords);
217
218   for (i = 1; i <= previewlines; i++) {
219     const float fac = (i / ((float)previewlines + 1));
220     interp_v3_v3v3(verts[tot], v_cos[0], v_cos[1], fac);
221     tot++;
222   }
223
224   psel->verts = verts;
225   psel->verts_len = previewlines;
226 }
227
228 static void view3d_preselect_mesh_edgering_update_edges_from_edge(
229     struct EditMesh_PreSelEdgeRing *psel,
230     BMesh *bm,
231     BMEdge *eed_start,
232     int previewlines,
233     const float (*coords)[3])
234 {
235   BMWalker walker;
236   BMEdge *eed, *eed_last;
237   BMVert *v[2][2] = {{NULL}}, *eve_last;
238   float(*edges)[2][3] = NULL;
239   BLI_Stack *edge_stack;
240
241   int i, tot = 0;
242
243   BMW_init(&walker,
244            bm,
245            BMW_EDGERING,
246            BMW_MASK_NOP,
247            BMW_MASK_NOP,
248            BMW_MASK_NOP,
249            BMW_FLAG_TEST_HIDDEN,
250            BMW_NIL_LAY);
251
252   edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
253
254   eed_last = NULL;
255   for (eed = eed_last = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
256     BLI_stack_push(edge_stack, &eed);
257   }
258   BMW_end(&walker);
259
260   eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
261
262   edges = MEM_mallocN((sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) *
263                           previewlines,
264                       __func__);
265
266   eve_last = NULL;
267   eed_last = NULL;
268
269   while (!BLI_stack_is_empty(edge_stack)) {
270     BLI_stack_pop(edge_stack, &eed);
271
272     if (eed_last) {
273       if (eve_last) {
274         v[1][0] = v[0][0];
275         v[1][1] = v[0][1];
276       }
277       else {
278         v[1][0] = eed_last->v1;
279         v[1][1] = eed_last->v2;
280         eve_last = eed_last->v1;
281       }
282
283       edgering_find_order(eed_last, eed, eve_last, v);
284       eve_last = v[0][0];
285
286       for (i = 1; i <= previewlines; i++) {
287         const float fac = (i / ((float)previewlines + 1));
288         float v_cos[2][2][3];
289
290         edgering_vcos_get(v, v_cos, coords);
291
292         interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
293         interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
294         tot++;
295       }
296     }
297     eed_last = eed;
298   }
299
300   if ((eed_last != eed_start) &&
301 #ifdef BMW_EDGERING_NGON
302       BM_edge_share_face_check(eed_last, eed_start)
303 #else
304       BM_edge_share_quad_check(eed_last, eed_start)
305 #endif
306   ) {
307     v[1][0] = v[0][0];
308     v[1][1] = v[0][1];
309
310     edgering_find_order(eed_last, eed_start, eve_last, v);
311
312     for (i = 1; i <= previewlines; i++) {
313       const float fac = (i / ((float)previewlines + 1));
314       float v_cos[2][2][3];
315
316       if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) {
317         continue;
318       }
319
320       edgering_vcos_get(v, v_cos, coords);
321
322       interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
323       interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
324       tot++;
325     }
326   }
327
328   BLI_stack_free(edge_stack);
329
330   psel->edges = edges;
331   psel->edges_len = tot;
332 }
333
334 void EDBM_preselect_edgering_update_from_edge(struct EditMesh_PreSelEdgeRing *psel,
335                                               BMesh *bm,
336                                               BMEdge *eed_start,
337                                               int previewlines,
338                                               const float (*coords)[3])
339 {
340   EDBM_preselect_edgering_clear(psel);
341
342   if (coords) {
343     BM_mesh_elem_index_ensure(bm, BM_VERT);
344   }
345
346   if (BM_edge_is_wire(eed_start)) {
347     view3d_preselect_mesh_edgering_update_verts_from_edge(
348         psel, bm, eed_start, previewlines, coords);
349   }
350   else {
351     view3d_preselect_mesh_edgering_update_edges_from_edge(
352         psel, bm, eed_start, previewlines, coords);
353   }
354 }
355
356 /** \} */