1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 /** \file
18 * \ingroup spview3d
19 */
20
21 #include "DNA_armature_types.h"
22 #include "DNA_curve_types.h"
23 #include "DNA_lattice_types.h"
24 #include "DNA_mesh_types.h"
25 #include "DNA_meshdata_types.h"
26 #include "DNA_meta_types.h"
27 #include "DNA_object_types.h"
28 #include "DNA_scene_types.h"
29
30 #include "BLI_math_geom.h"
31 #include "BLI_rect.h"
32 #include "BLI_utildefines.h"
33
34 #include "BKE_DerivedMesh.h"
35 #include "BKE_action.h"
36 #include "BKE_armature.h"
37 #include "BKE_curve.h"
38 #include "BKE_displist.h"
39 #include "BKE_editmesh.h"
40 #include "BKE_mesh_iterators.h"
41 #include "BKE_mesh_runtime.h"
42 #include "BKE_modifier.h"
43
44 #include "DEG_depsgraph.h"
45 #include "DEG_depsgraph_query.h"
46
47 #include "bmesh.h"
48
49 #include "ED_armature.h"
50 #include "ED_screen.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,
70 BMEdge *eed,
71 const float screen_co_a[2],
72 const float screen_co_b[2],
73 int index);
74 void *userData;
75 ViewContext vc;
76 rctf win_rect; /* copy of: vc.region->winx/winy, use for faster tests, minx/y will always be 0 */
77 eV3DProjTest clip_flag;
78 } foreachScreenEdge_userData;
79
80 typedef struct foreachScreenFace_userData {
81 void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index);
82 void *userData;
83 ViewContext vc;
84 eV3DProjTest clip_flag;
85 } foreachScreenFace_userData;
86
87 /**
88 * \note foreach funcs should be called while drawing or directly after
89 * if not, #ED_view3d_init_mats_rv3d() can be used for selection tools
90 * but would not give correct results with dupli's for eg. which don't
91 * use the object matrix in the usual way.
92 */
93
94 /* ------------------------------------------------------------------------ */
95
meshobject_foreachScreenVert__mapFunc(void * userData,int index,const float co[3],const float UNUSED (no_f[3]),const short UNUSED (no_s[3]))96 static void meshobject_foreachScreenVert__mapFunc(void *userData,
97 int index,
98 const float co[3],
99 const float UNUSED(no_f[3]),
100 const short UNUSED(no_s[3]))
101 {
102 foreachScreenObjectVert_userData *data = userData;
103 struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index];
104
105 if (!(mv->flag & ME_HIDE)) {
106 float screen_co[2];
107
108 if (ED_view3d_project_float_object(data->vc.region, co, screen_co, data->clip_flag) !=
109 V3D_PROJ_RET_OK) {
110 return;
111 }
112
113 data->func(data->userData, mv, screen_co, index);
114 }
115 }
116
meshobject_foreachScreenVert(ViewContext * vc,void (* func)(void * userData,MVert * eve,const float screen_co[2],int index),void * userData,eV3DProjTest clip_flag)117 void meshobject_foreachScreenVert(
118 ViewContext *vc,
119 void (*func)(void *userData, MVert *eve, const float screen_co[2], int index),
120 void *userData,
121 eV3DProjTest clip_flag)
122 {
123 foreachScreenObjectVert_userData data;
124 Mesh *me;
125
126 Scene *scene_eval = DEG_get_evaluated_scene(vc->depsgraph);
127 Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
128
129 me = mesh_get_eval_final(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
130
131 ED_view3d_check_mats_rv3d(vc->rv3d);
132
133 data.vc = *vc;
134 data.func = func;
135 data.userData = userData;
136 data.clip_flag = clip_flag;
137
138 if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
139 ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat);
140 }
141
142 BKE_mesh_foreach_mapped_vert(me, meshobject_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP);
143 }
144
mesh_foreachScreenVert__mapFunc(void * userData,int index,const float co[3],const float UNUSED (no_f[3]),const short UNUSED (no_s[3]))145 static void mesh_foreachScreenVert__mapFunc(void *userData,
146 int index,
147 const float co[3],
148 const float UNUSED(no_f[3]),
149 const short UNUSED(no_s[3]))
150 {
151 foreachScreenVert_userData *data = userData;
152 BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
153
154 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
155 float screen_co[2];
156
157 if (ED_view3d_project_float_object(data->vc.region, co, screen_co, data->clip_flag) !=
158 V3D_PROJ_RET_OK) {
159 return;
160 }
161
162 data->func(data->userData, eve, screen_co, index);
163 }
164 }
165
mesh_foreachScreenVert(ViewContext * vc,void (* func)(void * userData,BMVert * eve,const float screen_co[2],int index),void * userData,eV3DProjTest clip_flag)166 void mesh_foreachScreenVert(
167 ViewContext *vc,
168 void (*func)(void *userData, BMVert *eve, const float screen_co[2], int index),
169 void *userData,
170 eV3DProjTest clip_flag)
171 {
172 foreachScreenVert_userData data;
173
174 Mesh *me = editbmesh_get_eval_cage_from_orig(
175 vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
176
177 ED_view3d_check_mats_rv3d(vc->rv3d);
178
179 data.vc = *vc;
180 data.func = func;
181 data.userData = userData;
182 data.clip_flag = clip_flag;
183
184 if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
185 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
186 }
187
188 BM_mesh_elem_table_ensure(vc->em->bm, BM_VERT);
189 BKE_mesh_foreach_mapped_vert(me, mesh_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP);
190 }
191
192 /* ------------------------------------------------------------------------ */
193
mesh_foreachScreenEdge__mapFunc(void * userData,int index,const float v0co[3],const float v1co[3])194 static void mesh_foreachScreenEdge__mapFunc(void *userData,
195 int index,
196 const float v0co[3],
197 const float v1co[3])
198 {
199 foreachScreenEdge_userData *data = userData;
200 BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index);
201
202 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
203 float screen_co_a[2];
204 float screen_co_b[2];
205 eV3DProjTest clip_flag_nowin = data->clip_flag & ~V3D_PROJ_TEST_CLIP_WIN;
206
207 if (ED_view3d_project_float_object(data->vc.region, v0co, screen_co_a, clip_flag_nowin) !=
208 V3D_PROJ_RET_OK) {
209 return;
210 }
211 if (ED_view3d_project_float_object(data->vc.region, v1co, screen_co_b, clip_flag_nowin) !=
212 V3D_PROJ_RET_OK) {
213 return;
214 }
215
216 if (data->clip_flag & V3D_PROJ_TEST_CLIP_WIN) {
217 if (!BLI_rctf_isect_segment(&data->win_rect, screen_co_a, screen_co_b)) {
218 return;
219 }
220 }
221
222 data->func(data->userData, eed, screen_co_a, screen_co_b, index);
223 }
224 }
225
mesh_foreachScreenEdge(ViewContext * vc,void (* func)(void * userData,BMEdge * eed,const float screen_co_a[2],const float screen_co_b[2],int index),void * userData,eV3DProjTest clip_flag)226 void mesh_foreachScreenEdge(ViewContext *vc,
227 void (*func)(void *userData,
228 BMEdge *eed,
229 const float screen_co_a[2],
230 const float screen_co_b[2],
231 int index),
232 void *userData,
233 eV3DProjTest clip_flag)
234 {
235 foreachScreenEdge_userData data;
236
237 Mesh *me = editbmesh_get_eval_cage_from_orig(
238 vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
239
240 ED_view3d_check_mats_rv3d(vc->rv3d);
241
242 data.vc = *vc;
243
244 data.win_rect.xmin = 0;
245 data.win_rect.ymin = 0;
246 data.win_rect.xmax = vc->region->winx;
247 data.win_rect.ymax = vc->region->winy;
248
249 data.func = func;
250 data.userData = userData;
251 data.clip_flag = clip_flag;
252
253 if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
254 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
255 }
256
257 BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE);
258 BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data);
259 }
260
261 /* ------------------------------------------------------------------------ */
262
263 /**
264 * Only call for bound-box clipping.
265 * Otherwise call #mesh_foreachScreenEdge__mapFunc
266 */
mesh_foreachScreenEdge_clip_bb_segment__mapFunc(void * userData,int index,const float v0co[3],const float v1co[3])267 static void mesh_foreachScreenEdge_clip_bb_segment__mapFunc(void *userData,
268 int index,
269 const float v0co[3],
270 const float v1co[3])
271 {
272 foreachScreenEdge_userData *data = userData;
273 BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index);
274
275 BLI_assert(data->clip_flag & V3D_PROJ_TEST_CLIP_BB);
276
277 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
278 float v0co_clip[3];
279 float v1co_clip[3];
280
281 if (!clip_segment_v3_plane_n(v0co, v1co, data->vc.rv3d->clip_local, 4, v0co_clip, v1co_clip)) {
282 return;
283 }
284
285 float screen_co_a[2];
286 float screen_co_b[2];
287
288 /* Clipping already handled, no need to check in projection. */
289 eV3DProjTest clip_flag_nowin = data->clip_flag &
290 ~(V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_BB);
291
292 if (ED_view3d_project_float_object(data->vc.region, v0co_clip, screen_co_a, clip_flag_nowin) !=
293 V3D_PROJ_RET_OK) {
294 return;
295 }
296 if (ED_view3d_project_float_object(data->vc.region, v1co_clip, screen_co_b, clip_flag_nowin) !=
297 V3D_PROJ_RET_OK) {
298 return;
299 }
300
301 if (data->clip_flag & V3D_PROJ_TEST_CLIP_WIN) {
302 if (!BLI_rctf_isect_segment(&data->win_rect, screen_co_a, screen_co_b)) {
303 return;
304 }
305 }
306
307 data->func(data->userData, eed, screen_co_a, screen_co_b, index);
308 }
309 }
310
311 /**
312 * A version of #mesh_foreachScreenEdge that clips the segment when
313 * there is a clipping bounding box.
314 */
mesh_foreachScreenEdge_clip_bb_segment(ViewContext * vc,void (* func)(void * userData,BMEdge * eed,const float screen_co_a[2],const float screen_co_b[2],int index),void * userData,eV3DProjTest clip_flag)315 void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
316 void (*func)(void *userData,
317 BMEdge *eed,
318 const float screen_co_a[2],
319 const float screen_co_b[2],
320 int index),
321 void *userData,
322 eV3DProjTest clip_flag)
323 {
324 foreachScreenEdge_userData data;
325
326 Mesh *me = editbmesh_get_eval_cage_from_orig(
327 vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
328
329 ED_view3d_check_mats_rv3d(vc->rv3d);
330
331 data.vc = *vc;
332
333 data.win_rect.xmin = 0;
334 data.win_rect.ymin = 0;
335 data.win_rect.xmax = vc->region->winx;
336 data.win_rect.ymax = vc->region->winy;
337
338 data.func = func;
339 data.userData = userData;
340 data.clip_flag = clip_flag;
341
342 BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE);
343
344 if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != NULL)) {
345 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups. */
346 BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data);
347 }
348 else {
349 BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data);
350 }
351 }
352
353 /* ------------------------------------------------------------------------ */
354
mesh_foreachScreenFace__mapFunc(void * userData,int index,const float cent[3],const float UNUSED (no[3]))355 static void mesh_foreachScreenFace__mapFunc(void *userData,
356 int index,
357 const float cent[3],
358 const float UNUSED(no[3]))
359 {
360 foreachScreenFace_userData *data = userData;
361 BMFace *efa = BM_face_at_index(data->vc.em->bm, index);
362
363 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
364 float screen_co[2];
365 if (ED_view3d_project_float_object(data->vc.region, cent, screen_co, data->clip_flag) ==
366 V3D_PROJ_RET_OK) {
367 data->func(data->userData, efa, screen_co, index);
368 }
369 }
370 }
371
mesh_foreachScreenFace(ViewContext * vc,void (* func)(void * userData,BMFace * efa,const float screen_co_b[2],int index),void * userData,const eV3DProjTest clip_flag)372 void mesh_foreachScreenFace(
373 ViewContext *vc,
374 void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index),
375 void *userData,
376 const eV3DProjTest clip_flag)
377 {
378 foreachScreenFace_userData data;
379
380 Mesh *me = editbmesh_get_eval_cage_from_orig(
381 vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
382 ED_view3d_check_mats_rv3d(vc->rv3d);
383
384 data.vc = *vc;
385 data.func = func;
386 data.userData = userData;
387 data.clip_flag = clip_flag;
388
389 BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE);
390
391 if (BKE_modifiers_uses_subsurf_facedots(vc->scene, vc->obedit)) {
392 BKE_mesh_foreach_mapped_subdiv_face_center(
393 me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
394 }
395 else {
396 BKE_mesh_foreach_mapped_face_center(
397 me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
398 }
399 }
400
401 /* ------------------------------------------------------------------------ */
402
nurbs_foreachScreenVert(ViewContext * vc,void (* func)(void * userData,Nurb * nu,BPoint * bp,BezTriple * bezt,int beztindex,bool handles_visible,const float screen_co_b[2]),void * userData,const eV3DProjTest clip_flag)403 void nurbs_foreachScreenVert(ViewContext *vc,
404 void (*func)(void *userData,
405 Nurb *nu,
406 BPoint *bp,
407 BezTriple *bezt,
408 int beztindex,
409 bool handles_visible,
410 const float screen_co_b[2]),
411 void *userData,
412 const eV3DProjTest clip_flag)
413 {
414 Curve *cu = vc->obedit->data;
415 Nurb *nu;
416 int i;
417 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
418 /* If no point in the triple is selected, the handles are invisible. */
419 const bool only_selected = (vc->v3d->overlay.handle_display == CURVE_HANDLE_SELECTED);
420
421 ED_view3d_check_mats_rv3d(vc->rv3d);
422
423 if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
424 ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
425 }
426
427 for (nu = nurbs->first; nu; nu = nu->next) {
428 if (nu->type == CU_BEZIER) {
429 for (i = 0; i < nu->pntsu; i++) {
430 BezTriple *bezt = &nu->bezt[i];
431
432 if (bezt->hide == 0) {
433 const bool handles_visible = (vc->v3d->overlay.handle_display != CURVE_HANDLE_NONE) &&
434 (!only_selected || BEZT_ISSEL_ANY(bezt));
435 float screen_co[2];
436
437 if (!handles_visible) {
438 if (ED_view3d_project_float_object(vc->region,
439 bezt->vec[1],
440 screen_co,
441 V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
442 V3D_PROJ_RET_OK) {
443 func(userData, nu, NULL, bezt, 1, false, screen_co);
444 }
445 }
446 else {
447 if (ED_view3d_project_float_object(vc->region,
448 bezt->vec[0],
449 screen_co,
450 V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
451 V3D_PROJ_RET_OK) {
452 func(userData, nu, NULL, bezt, 0, true, screen_co);
453 }
454 if (ED_view3d_project_float_object(vc->region,
455 bezt->vec[1],
456 screen_co,
457 V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
458 V3D_PROJ_RET_OK) {
459 func(userData, nu, NULL, bezt, 1, true, screen_co);
460 }
461 if (ED_view3d_project_float_object(vc->region,
462 bezt->vec[2],
463 screen_co,
464 V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
465 V3D_PROJ_RET_OK) {
466 func(userData, nu, NULL, bezt, 2, true, screen_co);
467 }
468 }
469 }
470 }
471 }
472 else {
473 for (i = 0; i < nu->pntsu * nu->pntsv; i++) {
474 BPoint *bp = &nu->bp[i];
475
476 if (bp->hide == 0) {
477 float screen_co[2];
478 if (ED_view3d_project_float_object(
479 vc->region, bp->vec, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
480 V3D_PROJ_RET_OK) {
481 func(userData, nu, bp, NULL, -1, false, screen_co);
482 }
483 }
484 }
485 }
486 }
487 }
488
489 /* ------------------------------------------------------------------------ */
490
491 /* ED_view3d_init_mats_rv3d must be called first */
mball_foreachScreenElem(struct ViewContext * vc,void (* func)(void * userData,struct MetaElem * ml,const float screen_co_b[2]),void * userData,const eV3DProjTest clip_flag)492 void mball_foreachScreenElem(struct ViewContext *vc,
493 void (*func)(void *userData,
494 struct MetaElem *ml,
495 const float screen_co_b[2]),
496 void *userData,
497 const eV3DProjTest clip_flag)
498 {
499 MetaBall *mb = (MetaBall *)vc->obedit->data;
500 MetaElem *ml;
501
502 ED_view3d_check_mats_rv3d(vc->rv3d);
503
504 for (ml = mb->editelems->first; ml; ml = ml->next) {
505 float screen_co[2];
506 if (ED_view3d_project_float_object(vc->region, &ml->x, screen_co, clip_flag) ==
507 V3D_PROJ_RET_OK) {
508 func(userData, ml, screen_co);
509 }
510 }
511 }
512
513 /* ------------------------------------------------------------------------ */
514
lattice_foreachScreenVert(ViewContext * vc,void (* func)(void * userData,BPoint * bp,const float screen_co[2]),void * userData,const eV3DProjTest clip_flag)515 void lattice_foreachScreenVert(ViewContext *vc,
516 void (*func)(void *userData, BPoint *bp, const float screen_co[2]),
517 void *userData,
518 const eV3DProjTest clip_flag)
519 {
520 Object *obedit = vc->obedit;
521 Lattice *lt = obedit->data;
522 BPoint *bp = lt->editlatt->latt->def;
523 DispList *dl = obedit->runtime.curve_cache ?
524 BKE_displist_find(&obedit->runtime.curve_cache->disp, DL_VERTS) :
525 NULL;
526 const float *co = dl ? dl->verts : NULL;
527 int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
528
529 ED_view3d_check_mats_rv3d(vc->rv3d);
530
531 if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
532 ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */
533 }
534
535 for (i = 0; i < N; i++, bp++, co += 3) {
536 if (bp->hide == 0) {
537 float screen_co[2];
538 if (ED_view3d_project_float_object(vc->region, dl ? co : bp->vec, screen_co, clip_flag) ==
539 V3D_PROJ_RET_OK) {
540 func(userData, bp, screen_co);
541 }
542 }
543 }
544 }
545
546 /* ------------------------------------------------------------------------ */
547
548 /* ED_view3d_init_mats_rv3d must be called first */
armature_foreachScreenBone(struct ViewContext * vc,void (* func)(void * userData,struct EditBone * ebone,const float screen_co_a[2],const float screen_co_b[2]),void * userData,const eV3DProjTest clip_flag)549 void armature_foreachScreenBone(struct ViewContext *vc,
550 void (*func)(void *userData,
551 struct EditBone *ebone,
552 const float screen_co_a[2],
553 const float screen_co_b[2]),
554 void *userData,
555 const eV3DProjTest clip_flag)
556 {
557 bArmature *arm = vc->obedit->data;
558 EditBone *ebone;
559
560 ED_view3d_check_mats_rv3d(vc->rv3d);
561
562 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
563 if (EBONE_VISIBLE(arm, ebone)) {
564 float screen_co_a[2], screen_co_b[2];
565 int points_proj_tot = 0;
566
567 /* project head location to screenspace */
568 if (ED_view3d_project_float_object(vc->region, ebone->head, screen_co_a, clip_flag) ==
569 V3D_PROJ_RET_OK) {
570 points_proj_tot++;
571 }
572 else {
573 screen_co_a[0] = IS_CLIPPED; /* weak */
574 /* screen_co_a[1]: intentionally dont set this so we get errors on misuse */
575 }
576
577 /* project tail location to screenspace */
578 if (ED_view3d_project_float_object(vc->region, ebone->tail, screen_co_b, clip_flag) ==
579 V3D_PROJ_RET_OK) {
580 points_proj_tot++;
581 }
582 else {
583 screen_co_b[0] = IS_CLIPPED; /* weak */
584 /* screen_co_b[1]: intentionally dont set this so we get errors on misuse */
585 }
586
587 if (points_proj_tot) { /* at least one point's projection worked */
588 func(userData, ebone, screen_co_a, screen_co_b);
589 }
590 }
591 }
592 }
593
594 /* ------------------------------------------------------------------------ */
595
596 /* ED_view3d_init_mats_rv3d must be called first */
597 /* almost _exact_ copy of #armature_foreachScreenBone */
pose_foreachScreenBone(struct ViewContext * vc,void (* func)(void * userData,struct bPoseChannel * pchan,const float screen_co_a[2],const float screen_co_b[2]),void * userData,const eV3DProjTest clip_flag)598 void pose_foreachScreenBone(struct ViewContext *vc,
599 void (*func)(void *userData,
600 struct bPoseChannel *pchan,
601 const float screen_co_a[2],
602 const float screen_co_b[2]),
603 void *userData,
604 const eV3DProjTest clip_flag)
605 {
606 const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
607 const bArmature *arm_eval = ob_eval->data;
608 bPose *pose = vc->obact->pose;
609 bPoseChannel *pchan;
610
611 ED_view3d_check_mats_rv3d(vc->rv3d);
612
613 for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
614 if (PBONE_VISIBLE(arm_eval, pchan->bone)) {
615 bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
616 float screen_co_a[2], screen_co_b[2];
617 int points_proj_tot = 0;
618
619 /* project head location to screenspace */
620 if (ED_view3d_project_float_object(
621 vc->region, pchan_eval->pose_head, screen_co_a, clip_flag) == V3D_PROJ_RET_OK) {
622 points_proj_tot++;
623 }
624 else {
625 screen_co_a[0] = IS_CLIPPED; /* weak */
626 /* screen_co_a[1]: intentionally dont set this so we get errors on misuse */
627 }
628
629 /* project tail location to screenspace */
630 if (ED_view3d_project_float_object(
631 vc->region, pchan_eval->pose_tail, screen_co_b, clip_flag) == V3D_PROJ_RET_OK) {
632 points_proj_tot++;
633 }
634 else {
635 screen_co_b[0] = IS_CLIPPED; /* weak */
636 /* screen_co_b[1]: intentionally dont set this so we get errors on misuse */
637 }
638
639 if (points_proj_tot) { /* at least one point's projection worked */
640 func(userData, pchan, screen_co_a, screen_co_b);
641 }
642 }
643 }
644 }
645