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