Merge branch 'blender2.7'
[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 #include "UI_resources.h"
39
40 /* -------------------------------------------------------------------- */
41 /** \name Mesh Edge Ring Pre-Select
42  * Public API:
43  *
44  * #EDBM_preselect_edgering_create
45  * #EDBM_preselect_edgering_destroy
46  * #EDBM_preselect_edgering_clear
47  * #EDBM_preselect_edgering_draw
48  * #EDBM_preselect_edgering_update_from_edge
49  *
50  * \{ */
51
52 static void edgering_vcos_get(BMVert *v[2][2], float r_cos[2][2][3], const float (*coords)[3])
53 {
54         if (coords) {
55                 int j, k;
56                 for (j = 0; j < 2; j++) {
57                         for (k = 0; k < 2; k++) {
58                                 copy_v3_v3(r_cos[j][k], coords[BM_elem_index_get(v[j][k])]);
59                         }
60                 }
61         }
62         else {
63                 int j, k;
64                 for (j = 0; j < 2; j++) {
65                         for (k = 0; k < 2; k++) {
66                                 copy_v3_v3(r_cos[j][k], v[j][k]->co);
67                         }
68                 }
69         }
70 }
71
72 static void edgering_vcos_get_pair(BMVert *v[2], float r_cos[2][3], const float (*coords)[3])
73 {
74         if (coords) {
75                 int j;
76                 for (j = 0; j < 2; j++) {
77                         copy_v3_v3(r_cos[j], coords[BM_elem_index_get(v[j])]);
78                 }
79         }
80         else {
81                 int j;
82                 for (j = 0; j < 2; j++) {
83                         copy_v3_v3(r_cos[j], v[j]->co);
84                 }
85         }
86 }
87
88
89 /**
90  * Given two opposite edges in a face, finds the ordering of their vertices so
91  * that cut preview lines won't cross each other.
92  */
93 static void edgering_find_order(
94         BMEdge *eed_last, BMEdge *eed,
95         BMVert *eve_last, BMVert *v[2][2])
96 {
97         BMLoop *l = eed->l;
98
99         /* find correct order for v[1] */
100         if (!(BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))) {
101                 BMIter liter;
102                 BM_ITER_ELEM (l, &liter, l, BM_LOOPS_OF_LOOP) {
103                         if (BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))
104                                 break;
105                 }
106         }
107
108         /* this should never happen */
109         if (!l) {
110                 v[0][0] = eed->v1;
111                 v[0][1] = eed->v2;
112                 v[1][0] = eed_last->v1;
113                 v[1][1] = eed_last->v2;
114                 return;
115         }
116
117         BMLoop *l_other = BM_loop_other_edge_loop(l, eed->v1);
118         const bool rev = (l_other == l->prev);
119         while (l_other->v != eed_last->v1 && l_other->v != eed_last->v2) {
120                 l_other = rev ? l_other->prev : l_other->next;
121         }
122
123         if (l_other->v == eve_last) {
124                 v[0][0] = eed->v1;
125                 v[0][1] = eed->v2;
126         }
127         else {
128                 v[0][0] = eed->v2;
129                 v[0][1] = eed->v1;
130         }
131 }
132
133 struct EditMesh_PreSelEdgeRing {
134         float (*edges)[2][3];
135         int     edges_len;
136
137         float (*verts)[3];
138         int     verts_len;
139 };
140
141 struct EditMesh_PreSelEdgeRing *EDBM_preselect_edgering_create(void)
142 {
143         struct EditMesh_PreSelEdgeRing *psel = MEM_callocN(sizeof(*psel), __func__);
144         return psel;
145 }
146
147 void EDBM_preselect_edgering_destroy(
148         struct EditMesh_PreSelEdgeRing *psel)
149 {
150         EDBM_preselect_edgering_clear(psel);
151         MEM_freeN(psel);
152 }
153
154 void EDBM_preselect_edgering_clear(
155         struct EditMesh_PreSelEdgeRing *psel)
156 {
157         MEM_SAFE_FREE(psel->edges);
158         psel->edges_len = 0;
159
160         MEM_SAFE_FREE(psel->verts);
161         psel->verts_len = 0;
162 }
163
164 void EDBM_preselect_edgering_draw(
165         struct EditMesh_PreSelEdgeRing *psel, const float matrix[4][4])
166 {
167         if ((psel->edges_len == 0) && (psel->verts_len == 0)) {
168                 return;
169         }
170
171         GPU_depth_test(false);
172
173         GPU_matrix_push();
174         GPU_matrix_mul(matrix);
175
176         uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
177
178         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
179         immUniformThemeColor3(TH_GIZMO_PRIMARY);
180
181         if (psel->edges_len > 0) {
182                 immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
183
184                 for (int i = 0; i < psel->edges_len; i++) {
185                         immVertex3fv(pos, psel->edges[i][0]);
186                         immVertex3fv(pos, psel->edges[i][1]);
187                 }
188
189                 immEnd();
190         }
191
192         if (psel->verts_len > 0) {
193                 GPU_point_size(3.0f);
194
195                 immBegin(GPU_PRIM_POINTS, psel->verts_len);
196
197                 for (int i = 0; i < psel->verts_len; i++) {
198                         immVertex3fv(pos, psel->verts[i]);
199                 }
200
201                 immEnd();
202         }
203
204         immUnbindProgram();
205
206         GPU_matrix_pop();
207
208         /* Reset default */
209         GPU_depth_test(true);
210 }
211
212 static void view3d_preselect_mesh_edgering_update_verts_from_edge(
213         struct EditMesh_PreSelEdgeRing *psel,
214         BMesh *UNUSED(bm), BMEdge *eed_start, int previewlines, const float (*coords)[3])
215 {
216         float v_cos[2][3];
217         float (*verts)[3];
218         int i, tot = 0;
219
220         verts = MEM_mallocN(sizeof(*psel->verts) * previewlines, __func__);
221
222         edgering_vcos_get_pair(&eed_start->v1, v_cos, coords);
223
224         for (i = 1; i <= previewlines; i++) {
225                 const float fac = (i / ((float)previewlines + 1));
226                 interp_v3_v3v3(verts[tot], v_cos[0], v_cos[1], fac);
227                 tot++;
228         }
229
230         psel->verts = verts;
231         psel->verts_len = previewlines;
232 }
233
234 static void view3d_preselect_mesh_edgering_update_edges_from_edge(
235         struct EditMesh_PreSelEdgeRing *psel,
236         BMesh *bm, BMEdge *eed_start, int previewlines, const float (*coords)[3])
237 {
238         BMWalker walker;
239         BMEdge *eed, *eed_last;
240         BMVert *v[2][2] = {{NULL}}, *eve_last;
241         float (*edges)[2][3] = NULL;
242         BLI_Stack *edge_stack;
243
244         int i, tot = 0;
245
246         BMW_init(&walker, bm, BMW_EDGERING,
247                  BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
248                  BMW_FLAG_TEST_HIDDEN,
249                  BMW_NIL_LAY);
250
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
261         eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
262
263         edges = MEM_mallocN(
264                 (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines, __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         {
308                 v[1][0] = v[0][0];
309                 v[1][1] = v[0][1];
310
311                 edgering_find_order(eed_last, eed_start, eve_last, v);
312
313                 for (i = 1; i <= previewlines; i++) {
314                         const float fac = (i / ((float)previewlines + 1));
315                         float v_cos[2][2][3];
316
317                         if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) {
318                                 continue;
319                         }
320
321                         edgering_vcos_get(v, v_cos, coords);
322
323                         interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
324                         interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
325                         tot++;
326                 }
327         }
328
329         BLI_stack_free(edge_stack);
330
331         psel->edges = edges;
332         psel->edges_len = tot;
333 }
334
335 void EDBM_preselect_edgering_update_from_edge(
336         struct EditMesh_PreSelEdgeRing *psel,
337         BMesh *bm, BMEdge *eed_start, int previewlines, const float (*coords)[3])
338 {
339         EDBM_preselect_edgering_clear(psel);
340
341         if (coords) {
342                 BM_mesh_elem_index_ensure(bm, BM_VERT);
343         }
344
345         if (BM_edge_is_wire(eed_start)) {
346                 view3d_preselect_mesh_edgering_update_verts_from_edge(psel, bm, eed_start, previewlines, coords);
347         }
348         else {
349                 view3d_preselect_mesh_edgering_update_edges_from_edge(psel, bm, eed_start, previewlines, coords);
350         }
351
352 }
353
354 /** \} */