Pass EvaluationContext argument everywhere
[blender.git] / source / blender / editors / space_view3d / view3d_iterators.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  * Contributor(s): Blender Foundation, full recode and added functions
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/space_view3d/view3d_iterators.c
24  *  \ingroup spview3d
25  */
26
27 #include "DNA_curve_types.h"
28 #include "DNA_lattice_types.h"
29 #include "DNA_meta_types.h"
30 #include "DNA_mesh_types.h"
31 #include "DNA_armature_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_scene_types.h"
34
35 #include "BLI_utildefines.h"
36 #include "BLI_rect.h"
37
38 #include "BKE_armature.h"
39 #include "BKE_curve.h"
40 #include "BKE_DerivedMesh.h"
41 #include "BKE_displist.h"
42 #include "BKE_editmesh.h"
43 #include "BKE_context.h"
44
45 #include "DEG_depsgraph.h"
46
47 #include "bmesh.h"
48
49 #include "ED_screen.h"
50 #include "ED_armature.h"
51 #include "ED_view3d.h"
52
53 typedef struct foreachScreenObjectVert_userData {
54         void (*func)(void *userData, MVert *mv, const float screen_co_b[2], int index);
55         void *userData;
56         ViewContext vc;
57         eV3DProjTest clip_flag;
58 } foreachScreenObjectVert_userData;
59
60 typedef struct foreachScreenVert_userData {
61         void (*func)(void *userData, BMVert *eve, const float screen_co_b[2], int index);
62         void *userData;
63         ViewContext vc;
64         eV3DProjTest clip_flag;
65 } foreachScreenVert_userData;
66
67 /* user data structures for derived mesh callbacks */
68 typedef struct foreachScreenEdge_userData {
69         void (*func)(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index);
70         void *userData;
71         ViewContext vc;
72         rctf win_rect; /* copy of: vc.ar->winx/winy, use for faster tests, minx/y will always be 0 */
73         eV3DProjTest clip_flag;
74 } foreachScreenEdge_userData;
75
76 typedef struct foreachScreenFace_userData {
77         void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index);
78         void *userData;
79         ViewContext vc;
80         eV3DProjTest clip_flag;
81 } foreachScreenFace_userData;
82
83
84 /* Note! - foreach funcs should be called while drawing or directly after
85  * if not, ED_view3d_init_mats_rv3d() can be used for selection tools
86  * but would not give correct results with dupli's for eg. which don't
87  * use the object matrix in the usual way */
88
89 /* ------------------------------------------------------------------------ */
90
91
92 static void meshobject_foreachScreenVert__mapFunc(void *userData, int index, const float co[3],
93                                             const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
94 {
95         foreachScreenObjectVert_userData *data = userData;
96         struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index];
97
98         if (!(mv->flag & ME_HIDE)) {
99                 float screen_co[2];
100
101                 if (ED_view3d_project_float_object(data->vc.ar, co, screen_co, data->clip_flag) != V3D_PROJ_RET_OK) {
102                         return;
103                 }
104
105                 data->func(data->userData, mv, screen_co, index);
106         }
107 }
108
109 void meshobject_foreachScreenVert(
110         const bContext *C, ViewContext *vc,
111         void (*func)(void *userData, MVert *eve, const float screen_co[2], int index),
112         void *userData, eV3DProjTest clip_flag)
113 {
114         foreachScreenObjectVert_userData data;
115         EvaluationContext eval_ctx;
116         DerivedMesh *dm;
117
118         CTX_data_eval_ctx(C, &eval_ctx);
119
120         dm = mesh_get_derived_deform(&eval_ctx, vc->scene, vc->obact, CD_MASK_BAREMESH);
121
122         ED_view3d_check_mats_rv3d(vc->rv3d);
123
124         data.vc = *vc;
125         data.func = func;
126         data.userData = userData;
127         data.clip_flag = clip_flag;
128
129         if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
130                 ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat);
131         }
132
133         dm->foreachMappedVert(dm, meshobject_foreachScreenVert__mapFunc, &data, DM_FOREACH_NOP);
134
135         dm->release(dm);
136 }
137
138 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3],
139                                             const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
140 {
141         foreachScreenVert_userData *data = userData;
142         BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
143
144         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
145                 float screen_co[2];
146
147                 if (ED_view3d_project_float_object(data->vc.ar, co, screen_co, data->clip_flag) != V3D_PROJ_RET_OK) {
148                         return;
149                 }
150
151                 data->func(data->userData, eve, screen_co, index);
152         }
153 }
154
155 void mesh_foreachScreenVert(
156         const bContext *C, ViewContext *vc,
157         void (*func)(void *userData, BMVert *eve, const float screen_co[2], int index),
158         void *userData, eV3DProjTest clip_flag)
159 {
160         foreachScreenVert_userData data;
161         EvaluationContext eval_ctx;
162         DerivedMesh *dm;
163
164         CTX_data_eval_ctx(C, &eval_ctx);
165
166         dm = editbmesh_get_derived_cage(&eval_ctx, vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
167
168         ED_view3d_check_mats_rv3d(vc->rv3d);
169
170         data.vc = *vc;
171         data.func = func;
172         data.userData = userData;
173         data.clip_flag = clip_flag;
174
175         if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
176                 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat);  /* for local clipping lookups */
177         }
178
179         BM_mesh_elem_table_ensure(vc->em->bm, BM_VERT);
180         dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data, DM_FOREACH_NOP);
181
182         dm->release(dm);
183 }
184
185 /* ------------------------------------------------------------------------ */
186
187 static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, const float v0co[3], const float v1co[3])
188 {
189         foreachScreenEdge_userData *data = userData;
190         BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index);
191
192         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
193                 float screen_co_a[2];
194                 float screen_co_b[2];
195                 eV3DProjTest clip_flag_nowin = data->clip_flag &= ~V3D_PROJ_TEST_CLIP_WIN;
196
197                 if (ED_view3d_project_float_object(data->vc.ar, v0co, screen_co_a, clip_flag_nowin) != V3D_PROJ_RET_OK) {
198                         return;
199                 }
200                 if (ED_view3d_project_float_object(data->vc.ar, v1co, screen_co_b, clip_flag_nowin) != V3D_PROJ_RET_OK) {
201                         return;
202                 }
203
204                 if (data->clip_flag & V3D_PROJ_TEST_CLIP_WIN) {
205                         if (!BLI_rctf_isect_segment(&data->win_rect, screen_co_a, screen_co_b)) {
206                                 return;
207                         }
208                 }
209
210                 data->func(data->userData, eed, screen_co_a, screen_co_b, index);
211         }
212 }
213
214 void mesh_foreachScreenEdge(
215         const bContext *C, ViewContext *vc,
216         void (*func)(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index),
217         void *userData, eV3DProjTest clip_flag)
218 {
219         foreachScreenEdge_userData data;
220         EvaluationContext eval_ctx;
221         DerivedMesh *dm;
222
223         CTX_data_eval_ctx(C, &eval_ctx);
224
225         dm = editbmesh_get_derived_cage(&eval_ctx, vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
226
227         ED_view3d_check_mats_rv3d(vc->rv3d);
228
229         data.vc = *vc;
230
231         data.win_rect.xmin = 0;
232         data.win_rect.ymin = 0;
233         data.win_rect.xmax = vc->ar->winx;
234         data.win_rect.ymax = vc->ar->winy;
235
236         data.func = func;
237         data.userData = userData;
238         data.clip_flag = clip_flag;
239
240         if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
241                 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat);  /* for local clipping lookups */
242         }
243
244         BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE);
245         dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
246
247         dm->release(dm);
248 }
249
250 /* ------------------------------------------------------------------------ */
251
252 static void mesh_foreachScreenFace__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
253 {
254         foreachScreenFace_userData *data = userData;
255         BMFace *efa = BM_face_at_index(data->vc.em->bm, index);
256
257         if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
258                 float screen_co[2];
259                 if (ED_view3d_project_float_object(data->vc.ar, cent, screen_co, data->clip_flag) == V3D_PROJ_RET_OK) {
260                         data->func(data->userData, efa, screen_co, index);
261                 }
262         }
263 }
264
265 void mesh_foreachScreenFace(
266         const bContext *C, ViewContext *vc,
267         void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index),
268         void *userData, const eV3DProjTest clip_flag)
269 {
270         foreachScreenFace_userData data;
271         EvaluationContext eval_ctx;
272         DerivedMesh *dm;
273
274         CTX_data_eval_ctx(C, &eval_ctx);
275
276         dm = editbmesh_get_derived_cage(&eval_ctx, vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
277
278         ED_view3d_check_mats_rv3d(vc->rv3d);
279
280         data.vc = *vc;
281         data.func = func;
282         data.userData = userData;
283         data.clip_flag = clip_flag;
284
285         BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE);
286         dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data, DM_FOREACH_NOP);
287
288         dm->release(dm);
289 }
290
291 /* ------------------------------------------------------------------------ */
292
293 void nurbs_foreachScreenVert(
294         ViewContext *vc,
295         void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co_b[2]),
296         void *userData, const eV3DProjTest clip_flag)
297 {
298         Curve *cu = vc->obedit->data;
299         Nurb *nu;
300         int i;
301         ListBase *nurbs = BKE_curve_editNurbs_get(cu);
302
303         ED_view3d_check_mats_rv3d(vc->rv3d);
304
305         if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
306                 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
307         }
308
309         for (nu = nurbs->first; nu; nu = nu->next) {
310                 if (nu->type == CU_BEZIER) {
311                         for (i = 0; i < nu->pntsu; i++) {
312                                 BezTriple *bezt = &nu->bezt[i];
313
314                                 if (bezt->hide == 0) {
315                                         float screen_co[2];
316
317                                         if (cu->drawflag & CU_HIDE_HANDLES) {
318                                                 if (ED_view3d_project_float_object(vc->ar, bezt->vec[1], screen_co,
319                                                                                    V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK)
320                                                 {
321                                                         func(userData, nu, NULL, bezt, 1, screen_co);
322                                                 }
323                                         }
324                                         else {
325                                                 if (ED_view3d_project_float_object(vc->ar, bezt->vec[0], screen_co,
326                                                                                    V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK)
327                                                 {
328                                                         func(userData, nu, NULL, bezt, 0, screen_co);
329                                                 }
330                                                 if (ED_view3d_project_float_object(vc->ar, bezt->vec[1], screen_co,
331                                                                                    V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK)
332                                                 {
333                                                         func(userData, nu, NULL, bezt, 1, screen_co);
334                                                 }
335                                                 if (ED_view3d_project_float_object(vc->ar, bezt->vec[2], screen_co,
336                                                                                    V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK)
337                                                 {
338                                                         func(userData, nu, NULL, bezt, 2, screen_co);
339                                                 }
340                                         }
341                                 }
342                         }
343                 }
344                 else {
345                         for (i = 0; i < nu->pntsu * nu->pntsv; i++) {
346                                 BPoint *bp = &nu->bp[i];
347
348                                 if (bp->hide == 0) {
349                                         float screen_co[2];
350                                         if (ED_view3d_project_float_object(vc->ar, bp->vec, screen_co,
351                                                                            V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK)
352                                         {
353                                                 func(userData, nu, bp, NULL, -1, screen_co);
354                                         }
355                                 }
356                         }
357                 }
358         }
359 }
360
361 /* ------------------------------------------------------------------------ */
362
363 /* ED_view3d_init_mats_rv3d must be called first */
364 void mball_foreachScreenElem(
365         struct ViewContext *vc,
366         void (*func)(void *userData, struct MetaElem *ml, const float screen_co_b[2]),
367         void *userData, const eV3DProjTest clip_flag)
368 {
369         MetaBall *mb = (MetaBall *)vc->obedit->data;
370         MetaElem *ml;
371
372         ED_view3d_check_mats_rv3d(vc->rv3d);
373
374         for (ml = mb->editelems->first; ml; ml = ml->next) {
375                 float screen_co[2];
376                 if (ED_view3d_project_float_object(vc->ar, &ml->x, screen_co, clip_flag) == V3D_PROJ_RET_OK) {
377                         func(userData, ml, screen_co);
378                 }
379         }
380 }
381
382 /* ------------------------------------------------------------------------ */
383
384 void lattice_foreachScreenVert(
385         ViewContext *vc,
386         void (*func)(void *userData, BPoint *bp, const float screen_co[2]),
387         void *userData, const eV3DProjTest clip_flag)
388 {
389         Object *obedit = vc->obedit;
390         Lattice *lt = obedit->data;
391         BPoint *bp = lt->editlatt->latt->def;
392         DispList *dl = obedit->curve_cache ? BKE_displist_find(&obedit->curve_cache->disp, DL_VERTS) : NULL;
393         const float *co = dl ? dl->verts : NULL;
394         int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
395
396         ED_view3d_check_mats_rv3d(vc->rv3d);
397
398         if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
399                 ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */
400         }
401
402         for (i = 0; i < N; i++, bp++, co += 3) {
403                 if (bp->hide == 0) {
404                         float screen_co[2];
405                         if (ED_view3d_project_float_object(vc->ar, dl ? co : bp->vec, screen_co, clip_flag) == V3D_PROJ_RET_OK) {
406                                 func(userData, bp, screen_co);
407                         }
408                 }
409         }
410 }
411
412 /* ------------------------------------------------------------------------ */
413
414 /* ED_view3d_init_mats_rv3d must be called first */
415 void armature_foreachScreenBone(
416         struct ViewContext *vc,
417         void (*func)(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2]),
418         void *userData, const eV3DProjTest clip_flag)
419 {
420         bArmature *arm = vc->obedit->data;
421         EditBone *ebone;
422
423         ED_view3d_check_mats_rv3d(vc->rv3d);
424
425         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
426                 if (EBONE_VISIBLE(arm, ebone)) {
427                         float screen_co_a[2], screen_co_b[2];
428                         int points_proj_tot = 0;
429
430                         /* project head location to screenspace */
431                         if (ED_view3d_project_float_object(vc->ar, ebone->head, screen_co_a, clip_flag) == V3D_PROJ_RET_OK) {
432                                 points_proj_tot++;
433                         }
434                         else {
435                                 screen_co_a[0] = IS_CLIPPED;  /* weak */
436                                 /* screen_co_a[1]: intentionally dont set this so we get errors on misuse */
437                         }
438
439                         /* project tail location to screenspace */
440                         if (ED_view3d_project_float_object(vc->ar, ebone->tail, screen_co_b, clip_flag) == V3D_PROJ_RET_OK) {
441                                 points_proj_tot++;
442                         }
443                         else {
444                                 screen_co_b[0] = IS_CLIPPED;  /* weak */
445                                 /* screen_co_b[1]: intentionally dont set this so we get errors on misuse */
446                         }
447
448                         if (points_proj_tot) {  /* at least one point's projection worked */
449                                 func(userData, ebone, screen_co_a, screen_co_b);
450                         }
451                 }
452         }
453 }
454
455 /* ------------------------------------------------------------------------ */
456
457 /* ED_view3d_init_mats_rv3d must be called first */
458 /* almost _exact_ copy of #armature_foreachScreenBone */
459 void pose_foreachScreenBone(
460         struct ViewContext *vc,
461         void (*func)(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]),
462         void *userData, const eV3DProjTest clip_flag)
463 {
464         bArmature *arm = vc->obact->data;
465         bPose *pose = vc->obact->pose;
466         bPoseChannel *pchan;
467
468         ED_view3d_check_mats_rv3d(vc->rv3d);
469
470         for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
471                 if (PBONE_VISIBLE(arm, pchan->bone)) {
472                         float screen_co_a[2], screen_co_b[2];
473                         int points_proj_tot = 0;
474
475                         /* project head location to screenspace */
476                         if (ED_view3d_project_float_object(vc->ar, pchan->pose_head, screen_co_a, clip_flag) == V3D_PROJ_RET_OK) {
477                                 points_proj_tot++;
478                         }
479                         else {
480                                 screen_co_a[0] = IS_CLIPPED;  /* weak */
481                                 /* screen_co_a[1]: intentionally dont set this so we get errors on misuse */
482                         }
483
484                         /* project tail location to screenspace */
485                         if (ED_view3d_project_float_object(vc->ar, pchan->pose_tail, screen_co_b, clip_flag) == V3D_PROJ_RET_OK) {
486                                 points_proj_tot++;
487                         }
488                         else {
489                                 screen_co_b[0] = IS_CLIPPED;  /* weak */
490                                 /* screen_co_b[1]: intentionally dont set this so we get errors on misuse */
491                         }
492
493                         if (points_proj_tot) {  /* at least one point's projection worked */
494                                 func(userData, pchan, screen_co_a, screen_co_b);
495                         }
496                 }
497         }
498 }