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