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