doxygen: add newline after \file
[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 /**
86  * Given two opposite edges in a face, finds the ordering of their vertices so
87  * that cut preview lines won't cross each other.
88  */
89 static void edgering_find_order(
90         BMEdge *eed_last, BMEdge *eed,
91         BMVert *eve_last, BMVert *v[2][2])
92 {
93         BMLoop *l = eed->l;
94
95         /* find correct order for v[1] */
96         if (!(BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))) {
97                 BMIter liter;
98                 BM_ITER_ELEM (l, &liter, l, BM_LOOPS_OF_LOOP) {
99                         if (BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))
100                                 break;
101                 }
102         }
103
104         /* this should never happen */
105         if (!l) {
106                 v[0][0] = eed->v1;
107                 v[0][1] = eed->v2;
108                 v[1][0] = eed_last->v1;
109                 v[1][1] = eed_last->v2;
110                 return;
111         }
112
113         BMLoop *l_other = BM_loop_other_edge_loop(l, eed->v1);
114         const bool rev = (l_other == l->prev);
115         while (l_other->v != eed_last->v1 && l_other->v != eed_last->v2) {
116                 l_other = rev ? l_other->prev : l_other->next;
117         }
118
119         if (l_other->v == eve_last) {
120                 v[0][0] = eed->v1;
121                 v[0][1] = eed->v2;
122         }
123         else {
124                 v[0][0] = eed->v2;
125                 v[0][1] = eed->v1;
126         }
127 }
128
129 struct EditMesh_PreSelEdgeRing {
130         float (*edges)[2][3];
131         int     edges_len;
132
133         float (*verts)[3];
134         int     verts_len;
135 };
136
137 struct EditMesh_PreSelEdgeRing *EDBM_preselect_edgering_create(void)
138 {
139         struct EditMesh_PreSelEdgeRing *psel = MEM_callocN(sizeof(*psel), __func__);
140         return psel;
141 }
142
143 void EDBM_preselect_edgering_destroy(
144         struct EditMesh_PreSelEdgeRing *psel)
145 {
146         EDBM_preselect_edgering_clear(psel);
147         MEM_freeN(psel);
148 }
149
150 void EDBM_preselect_edgering_clear(
151         struct EditMesh_PreSelEdgeRing *psel)
152 {
153         MEM_SAFE_FREE(psel->edges);
154         psel->edges_len = 0;
155
156         MEM_SAFE_FREE(psel->verts);
157         psel->verts_len = 0;
158 }
159
160 void EDBM_preselect_edgering_draw(
161         struct EditMesh_PreSelEdgeRing *psel, const float matrix[4][4])
162 {
163         if ((psel->edges_len == 0) && (psel->verts_len == 0)) {
164                 return;
165         }
166
167         GPU_depth_test(false);
168
169         GPU_matrix_push();
170         GPU_matrix_mul(matrix);
171
172         uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
173
174         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
175         immUniformThemeColor3(TH_GIZMO_PRIMARY);
176
177         if (psel->edges_len > 0) {
178                 immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
179
180                 for (int i = 0; i < psel->edges_len; i++) {
181                         immVertex3fv(pos, psel->edges[i][0]);
182                         immVertex3fv(pos, psel->edges[i][1]);
183                 }
184
185                 immEnd();
186         }
187
188         if (psel->verts_len > 0) {
189                 GPU_point_size(3.0f);
190
191                 immBegin(GPU_PRIM_POINTS, psel->verts_len);
192
193                 for (int i = 0; i < psel->verts_len; i++) {
194                         immVertex3fv(pos, psel->verts[i]);
195                 }
196
197                 immEnd();
198         }
199
200         immUnbindProgram();
201
202         GPU_matrix_pop();
203
204         /* Reset default */
205         GPU_depth_test(true);
206 }
207
208 static void view3d_preselect_mesh_edgering_update_verts_from_edge(
209         struct EditMesh_PreSelEdgeRing *psel,
210         BMesh *UNUSED(bm), BMEdge *eed_start, int previewlines, const float (*coords)[3])
211 {
212         float v_cos[2][3];
213         float (*verts)[3];
214         int i, tot = 0;
215
216         verts = MEM_mallocN(sizeof(*psel->verts) * previewlines, __func__);
217
218         edgering_vcos_get_pair(&eed_start->v1, v_cos, coords);
219
220         for (i = 1; i <= previewlines; i++) {
221                 const float fac = (i / ((float)previewlines + 1));
222                 interp_v3_v3v3(verts[tot], v_cos[0], v_cos[1], fac);
223                 tot++;
224         }
225
226         psel->verts = verts;
227         psel->verts_len = previewlines;
228 }
229
230 static void view3d_preselect_mesh_edgering_update_edges_from_edge(
231         struct EditMesh_PreSelEdgeRing *psel,
232         BMesh *bm, BMEdge *eed_start, int previewlines, const float (*coords)[3])
233 {
234         BMWalker walker;
235         BMEdge *eed, *eed_last;
236         BMVert *v[2][2] = {{NULL}}, *eve_last;
237         float (*edges)[2][3] = NULL;
238         BLI_Stack *edge_stack;
239
240         int i, tot = 0;
241
242         BMW_init(&walker, bm, BMW_EDGERING,
243                  BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
244                  BMW_FLAG_TEST_HIDDEN,
245                  BMW_NIL_LAY);
246
247
248         edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
249
250         eed_last = NULL;
251         for (eed = eed_last = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
252                 BLI_stack_push(edge_stack, &eed);
253         }
254         BMW_end(&walker);
255
256
257         eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
258
259         edges = MEM_mallocN(
260                 (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines, __func__);
261
262         eve_last = NULL;
263         eed_last = NULL;
264
265         while (!BLI_stack_is_empty(edge_stack)) {
266                 BLI_stack_pop(edge_stack, &eed);
267
268                 if (eed_last) {
269                         if (eve_last) {
270                                 v[1][0] = v[0][0];
271                                 v[1][1] = v[0][1];
272                         }
273                         else {
274                                 v[1][0] = eed_last->v1;
275                                 v[1][1] = eed_last->v2;
276                                 eve_last  = eed_last->v1;
277                         }
278
279                         edgering_find_order(eed_last, eed, eve_last, v);
280                         eve_last = v[0][0];
281
282                         for (i = 1; i <= previewlines; i++) {
283                                 const float fac = (i / ((float)previewlines + 1));
284                                 float v_cos[2][2][3];
285
286                                 edgering_vcos_get(v, v_cos, coords);
287
288                                 interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
289                                 interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
290                                 tot++;
291                         }
292                 }
293                 eed_last = eed;
294         }
295
296         if ((eed_last != eed_start) &&
297 #ifdef BMW_EDGERING_NGON
298             BM_edge_share_face_check(eed_last, eed_start)
299 #else
300             BM_edge_share_quad_check(eed_last, eed_start)
301 #endif
302             )
303         {
304                 v[1][0] = v[0][0];
305                 v[1][1] = v[0][1];
306
307                 edgering_find_order(eed_last, eed_start, eve_last, v);
308
309                 for (i = 1; i <= previewlines; i++) {
310                         const float fac = (i / ((float)previewlines + 1));
311                         float v_cos[2][2][3];
312
313                         if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) {
314                                 continue;
315                         }
316
317                         edgering_vcos_get(v, v_cos, coords);
318
319                         interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
320                         interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
321                         tot++;
322                 }
323         }
324
325         BLI_stack_free(edge_stack);
326
327         psel->edges = edges;
328         psel->edges_len = tot;
329 }
330
331 void EDBM_preselect_edgering_update_from_edge(
332         struct EditMesh_PreSelEdgeRing *psel,
333         BMesh *bm, BMEdge *eed_start, int previewlines, const float (*coords)[3])
334 {
335         EDBM_preselect_edgering_clear(psel);
336
337         if (coords) {
338                 BM_mesh_elem_index_ensure(bm, BM_VERT);
339         }
340
341         if (BM_edge_is_wire(eed_start)) {
342                 view3d_preselect_mesh_edgering_update_verts_from_edge(psel, bm, eed_start, previewlines, coords);
343         }
344         else {
345                 view3d_preselect_mesh_edgering_update_edges_from_edge(psel, bm, eed_start, previewlines, coords);
346         }
347
348 }
349
350 /** \} */