Cleanup: use 'mesh' in preselect identifiers
[blender.git] / source / blender / editors / space_view3d / view3d_gizmo_preselect_type.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 view3d_gizmo_preselect_type.c
22  *  \ingroup wm
23  *
24  * \name Preselection Gizmo
25  *
26  * Use for tools to hover over data before activation.
27  *
28  * \note This is a slight mis-use of gizmo's, since clicking performs no action.
29  */
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_math.h"
34
35 #include "DNA_mesh_types.h"
36
37 #include "BKE_context.h"
38 #include "BKE_layer.h"
39 #include "BKE_editmesh.h"
40
41 #include "DEG_depsgraph.h"
42 #include "DEG_depsgraph_query.h"
43
44 #include "RNA_access.h"
45 #include "RNA_define.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "bmesh.h"
51
52 #include "ED_screen.h"
53 #include "ED_mesh.h"
54 #include "ED_view3d.h"
55 #include "ED_gizmo_library.h"
56
57 /* -------------------------------------------------------------------- */
58 /** \name Mesh Element (Vert/Edge/Face) Pre-Select Gizmo API
59  *
60  * \{ */
61
62
63 typedef struct MeshElemGizmo3D {
64         wmGizmo gizmo;
65         Object **objects;
66         uint     objects_len;
67         int object_index;
68         int vert_index;
69         int edge_index;
70         int face_index;
71         struct EditMesh_PreSelElem *psel;
72 } MeshElemGizmo3D;
73
74 static void gizmo_preselect_elem_draw(const bContext *UNUSED(C), wmGizmo *gz)
75 {
76         MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
77         if (gz_ele->object_index != -1) {
78                 Object *ob = gz_ele->objects[gz_ele->object_index];
79                 EDBM_preselect_elem_draw(gz_ele->psel, ob->obmat);
80         }
81 }
82
83 static int gizmo_preselect_elem_test_select(
84         bContext *C, wmGizmo *gz, const int mval[2])
85 {
86         MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
87         struct {
88                 Object *ob;
89                 BMElem *ele;
90                 float dist;
91                 int ob_index;
92         } best = {
93                 .dist = ED_view3d_select_dist_px(),
94         };
95
96         struct {
97                 int object_index;
98                 int vert_index;
99                 int edge_index;
100                 int face_index;
101         } prev = {
102                 .object_index = gz_ele->object_index,
103                 .vert_index = gz_ele->vert_index,
104                 .edge_index = gz_ele->edge_index,
105                 .face_index = gz_ele->face_index,
106         };
107
108         {
109                 ViewLayer *view_layer = CTX_data_view_layer(C);
110                 if (((gz_ele->objects)) == NULL ||
111                     (gz_ele->objects[0] != OBEDIT_FROM_VIEW_LAYER(view_layer)))
112                 {
113                         gz_ele->objects = BKE_view_layer_array_from_objects_in_edit_mode(
114                                 view_layer, &gz_ele->objects_len);
115                 }
116         }
117
118         ViewContext vc;
119         em_setup_viewcontext(C, &vc);
120         copy_v2_v2_int(vc.mval, mval);
121
122         {
123                 /* TODO: support faces. */
124                 Base *base = NULL;
125                 BMVert *eve_test;
126                 BMEdge *eed_test;
127
128                 if (EDBM_unified_findnearest_from_raycast(&vc, true, &base, &eve_test, &eed_test, NULL)) {
129                         best.ob = base->object;
130                         if (eve_test) {
131                                 best.ele = (BMElem *)eve_test;
132                         }
133                         else if (eed_test) {
134                                 best.ele = (BMElem *)eed_test;
135                         }
136                         else {
137                                 BLI_assert(0);
138                         }
139                         best.ob_index = -1;
140                         /* weak, we could ensure the arrays are aligned,
141                          * or allow EDBM_unified_findnearest_from_raycast to take an array arg. */
142                         for (int ob_index = 0; ob_index < gz_ele->objects_len; ob_index++) {
143                                 if (best.ob == gz_ele->objects[ob_index]) {
144                                         best.ob_index = ob_index;
145                                         break;
146                                 }
147                         }
148                         /* Check above should never fail, if it does it's an internal error. */
149                         BLI_assert(best.ob_index != -1);
150                 }
151         }
152
153         BMesh *bm = NULL;
154
155         gz_ele->object_index = -1;
156         gz_ele->vert_index = -1;
157         gz_ele->edge_index = -1;
158         gz_ele->face_index = -1;
159
160         if (best.ele) {
161                 gz_ele->object_index = best.ob_index;
162                 bm = BKE_editmesh_from_object(gz_ele->objects[gz_ele->object_index])->bm;
163                 BM_mesh_elem_index_ensure(bm, best.ele->head.htype);
164
165                 if (best.ele->head.htype == BM_VERT) {
166                         gz_ele->vert_index = BM_elem_index_get(best.ele);
167                 }
168                 else if (best.ele->head.htype == BM_EDGE) {
169                         gz_ele->edge_index = BM_elem_index_get(best.ele);
170                 }
171                 else if (best.ele->head.htype == BM_FACE) {
172                         gz_ele->face_index = BM_elem_index_get(best.ele);
173                 }
174         }
175
176         if ((prev.object_index == gz_ele->object_index) &&
177             (prev.vert_index == gz_ele->vert_index) &&
178             (prev.edge_index == gz_ele->edge_index) &&
179             (prev.face_index == gz_ele->face_index))
180         {
181                 /* pass (only recalculate on change) */
182         }
183         else {
184                 if (best.ele) {
185                         const float (*coords)[3] = NULL;
186                         {
187                                 Object *ob = gz_ele->objects[gz_ele->object_index];
188                                 Depsgraph *depsgraph = CTX_data_depsgraph(C);
189                                 Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
190                                 if (me_eval->runtime.edit_data) {
191                                         coords = me_eval->runtime.edit_data->vertexCos;
192                                 }
193                         }
194                         EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
195                 }
196                 else {
197                         EDBM_preselect_elem_clear(gz_ele->psel);
198                 }
199
200                 RNA_int_set(gz->ptr, "object_index", gz_ele->object_index);
201                 RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index);
202                 RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index);
203                 RNA_int_set(gz->ptr, "face_index", gz_ele->face_index);
204
205                 ARegion *ar = CTX_wm_region(C);
206                 ED_region_tag_redraw(ar);
207         }
208
209         // return best.eed ? 0 : -1;
210         return -1;
211 }
212
213 static void gizmo_preselect_elem_setup(wmGizmo *gz)
214 {
215         MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
216         if (gz_ele->psel == NULL) {
217                 gz_ele->psel = EDBM_preselect_elem_create();
218         }
219         gz_ele->object_index = -1;
220 }
221
222 static void gizmo_preselect_elem_free(wmGizmo *gz)
223 {
224         MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
225         EDBM_preselect_elem_destroy(gz_ele->psel);
226         gz_ele->psel = NULL;
227         MEM_SAFE_FREE(gz_ele->objects);
228 }
229
230 static int gizmo_preselect_elem_invoke(
231         bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event))
232 {
233         return OPERATOR_PASS_THROUGH;
234 }
235
236 static void GIZMO_GT_mesh_preselect_elem_3d(wmGizmoType *gzt)
237 {
238         /* identifiers */
239         gzt->idname = "GIZMO_GT_mesh_preselect_elem_3d";
240
241         /* api callbacks */
242         gzt->invoke = gizmo_preselect_elem_invoke;
243         gzt->draw = gizmo_preselect_elem_draw;
244         gzt->test_select = gizmo_preselect_elem_test_select;
245         gzt->setup = gizmo_preselect_elem_setup;
246         gzt->free = gizmo_preselect_elem_free;
247
248         gzt->struct_size = sizeof(MeshElemGizmo3D);
249
250         RNA_def_int(gzt->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", -1, INT_MAX);
251         RNA_def_int(gzt->srna, "vert_index", -1, -1, INT_MAX, "Vert Index", "", -1, INT_MAX);
252         RNA_def_int(gzt->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", -1, INT_MAX);
253         RNA_def_int(gzt->srna, "face_index", -1, -1, INT_MAX, "Face Index", "", -1, INT_MAX);
254 }
255
256 /** \} */
257
258 /* -------------------------------------------------------------------- */
259 /** \name Mesh Edge-Ring Pre-Select Gizmo API
260  *
261  * \{ */
262
263 typedef struct MeshEdgeRingGizmo3D {
264         wmGizmo gizmo;
265         Object **objects;
266         uint     objects_len;
267         int object_index;
268         int edge_index;
269         struct EditMesh_PreSelEdgeRing *psel;
270 } MeshEdgeRingGizmo3D;
271
272 static void gizmo_preselect_edgering_draw(const bContext *UNUSED(C), wmGizmo *gz)
273 {
274         MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
275         if (gz_ring->object_index != -1) {
276                 Object *ob = gz_ring->objects[gz_ring->object_index];
277                 EDBM_preselect_edgering_draw(gz_ring->psel, ob->obmat);
278         }
279 }
280
281 static int gizmo_preselect_edgering_test_select(
282         bContext *C, wmGizmo *gz, const int mval[2])
283 {
284         MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
285         struct {
286                 Object *ob;
287                 BMEdge *eed;
288                 float dist;
289                 int ob_index;
290         } best = {
291                 .dist = ED_view3d_select_dist_px(),
292         };
293
294         struct {
295                 int object_index;
296                 int edge_index;
297         } prev = {
298                 .object_index = gz_ring->object_index,
299                 .edge_index = gz_ring->edge_index,
300         };
301
302         {
303                 ViewLayer *view_layer = CTX_data_view_layer(C);
304                 if (((gz_ring->objects)) == NULL ||
305                     (gz_ring->objects[0] != OBEDIT_FROM_VIEW_LAYER(view_layer)))
306                 {
307                         gz_ring->objects = BKE_view_layer_array_from_objects_in_edit_mode(
308                                 view_layer, &gz_ring->objects_len);
309                 }
310         }
311
312         ViewContext vc;
313         em_setup_viewcontext(C, &vc);
314         copy_v2_v2_int(vc.mval, mval);
315
316         for (uint ob_index = 0; ob_index < gz_ring->objects_len; ob_index++) {
317                 Object *ob_iter = gz_ring->objects[ob_index];
318                 ED_view3d_viewcontext_init_object(&vc, ob_iter);
319                 BMEdge *eed_test = EDBM_edge_find_nearest_ex(&vc, &best.dist, NULL, false, false, NULL);
320                 if (eed_test) {
321                         best.ob = ob_iter;
322                         best.eed = eed_test;
323                         best.ob_index = ob_index;
324                 }
325         }
326
327         BMesh *bm = NULL;
328         if (best.eed) {
329                 gz_ring->object_index = best.ob_index;
330                 bm = BKE_editmesh_from_object(gz_ring->objects[gz_ring->object_index])->bm;
331                 BM_mesh_elem_index_ensure(bm, BM_EDGE);
332                 gz_ring->edge_index = BM_elem_index_get(best.eed);
333         }
334         else {
335                 gz_ring->object_index = -1;
336                 gz_ring->edge_index = -1;
337         }
338
339
340         if ((prev.object_index == gz_ring->object_index) &&
341             (prev.edge_index == gz_ring->edge_index))
342         {
343                 /* pass (only recalculate on change) */
344         }
345         else {
346                 if (best.eed) {
347                         const float (*coords)[3] = NULL;
348                         {
349                                 Object *ob = gz_ring->objects[gz_ring->object_index];
350                                 Depsgraph *depsgraph = CTX_data_depsgraph(C);
351                                 Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
352                                 if (me_eval->runtime.edit_data) {
353                                         coords = me_eval->runtime.edit_data->vertexCos;
354                                 }
355                         }
356                         EDBM_preselect_edgering_update_from_edge(gz_ring->psel, bm, best.eed, 1, coords);
357                 }
358                 else {
359                         EDBM_preselect_edgering_clear(gz_ring->psel);
360                 }
361
362                 RNA_int_set(gz->ptr, "object_index", gz_ring->object_index);
363                 RNA_int_set(gz->ptr, "edge_index", gz_ring->edge_index);
364
365                 ARegion *ar = CTX_wm_region(C);
366                 ED_region_tag_redraw(ar);
367         }
368
369         // return best.eed ? 0 : -1;
370         return -1;
371 }
372
373 static void gizmo_preselect_edgering_setup(wmGizmo *gz)
374 {
375         MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
376         if (gz_ring->psel == NULL) {
377                 gz_ring->psel = EDBM_preselect_edgering_create();
378         }
379         gz_ring->object_index = -1;
380 }
381
382 static void gizmo_preselect_edgering_free(wmGizmo *gz)
383 {
384         MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
385         EDBM_preselect_edgering_destroy(gz_ring->psel);
386         gz_ring->psel = NULL;
387         MEM_SAFE_FREE(gz_ring->objects);
388 }
389
390 static int gizmo_preselect_edgering_invoke(
391         bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event))
392 {
393         return OPERATOR_PASS_THROUGH;
394 }
395
396
397 static void GIZMO_GT_mesh_preselect_edgering_3d(wmGizmoType *gzt)
398 {
399         /* identifiers */
400         gzt->idname = "GIZMO_GT_mesh_preselect_edgering_3d";
401
402         /* api callbacks */
403         gzt->invoke = gizmo_preselect_edgering_invoke;
404         gzt->draw = gizmo_preselect_edgering_draw;
405         gzt->test_select = gizmo_preselect_edgering_test_select;
406         gzt->setup = gizmo_preselect_edgering_setup;
407         gzt->free = gizmo_preselect_edgering_free;
408
409         gzt->struct_size = sizeof(MeshEdgeRingGizmo3D);
410
411         RNA_def_int(gzt->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", -1, INT_MAX);
412         RNA_def_int(gzt->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", -1, INT_MAX);
413 }
414
415 /** \} */
416
417
418 /* -------------------------------------------------------------------- */
419 /** \name Gizmo API
420  *
421  * \{ */
422
423 void ED_gizmotypes_preselect_3d(void)
424 {
425         WM_gizmotype_append(GIZMO_GT_mesh_preselect_elem_3d);
426         WM_gizmotype_append(GIZMO_GT_mesh_preselect_edgering_3d);
427 }
428
429 /** \} */