2012-10-10 03:13:02 +00:00
|
|
|
/*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup spview3d
|
2012-10-10 03:13:02 +00:00
|
|
|
*/
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_armature_types.h"
|
2012-10-10 03:13:02 +00:00
|
|
|
#include "DNA_curve_types.h"
|
|
|
|
#include "DNA_lattice_types.h"
|
2012-12-23 03:04:19 +00:00
|
|
|
#include "DNA_mesh_types.h"
|
2018-10-15 14:29:46 +11:00
|
|
|
#include "DNA_meshdata_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_meta_types.h"
|
2012-10-10 03:13:02 +00:00
|
|
|
#include "DNA_object_types.h"
|
2013-06-25 09:27:31 +00:00
|
|
|
#include "DNA_scene_types.h"
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2019-08-02 22:53:27 +10:00
|
|
|
#include "BLI_math_geom.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_rect.h"
|
|
|
|
#include "BLI_utildefines.h"
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_DerivedMesh.h"
|
2018-05-24 19:12:41 +02:00
|
|
|
#include "BKE_action.h"
|
2012-10-10 03:13:02 +00:00
|
|
|
#include "BKE_armature.h"
|
|
|
|
#include "BKE_curve.h"
|
|
|
|
#include "BKE_displist.h"
|
2013-10-28 02:05:33 +00:00
|
|
|
#include "BKE_editmesh.h"
|
2018-10-09 16:52:46 +11:00
|
|
|
#include "BKE_mesh_iterators.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_mesh_runtime.h"
|
2019-07-07 18:58:11 +02:00
|
|
|
#include "BKE_modifier.h"
|
2017-07-21 11:53:13 +02:00
|
|
|
|
|
|
|
#include "DEG_depsgraph.h"
|
2018-05-24 19:12:41 +02:00
|
|
|
#include "DEG_depsgraph_query.h"
|
2012-10-10 03:13:02 +00:00
|
|
|
|
|
|
|
#include "bmesh.h"
|
|
|
|
|
|
|
|
#include "ED_armature.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "ED_screen.h"
|
2012-10-10 03:13:02 +00:00
|
|
|
#include "ED_view3d.h"
|
|
|
|
|
2021-06-21 17:25:10 +10:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Clipping Plane Utility
|
|
|
|
*
|
|
|
|
* Calculate clipping planes to use when #V3D_PROJ_TEST_CLIP_CONTENT is enabled.
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate clip planes from the viewpoint using `clip_flag`
|
|
|
|
* to detect which planes should be applied (maximum 6).
|
|
|
|
*
|
|
|
|
* \return The number of planes written into `planes`.
|
|
|
|
*/
|
|
|
|
static int content_planes_from_clip_flag(const ARegion *region,
|
|
|
|
const Object *ob,
|
|
|
|
const eV3DProjTest clip_flag,
|
|
|
|
float planes[6][4])
|
|
|
|
{
|
|
|
|
float *clip_xmin = NULL, *clip_xmax = NULL;
|
|
|
|
float *clip_ymin = NULL, *clip_ymax = NULL;
|
|
|
|
float *clip_zmin = NULL, *clip_zmax = NULL;
|
|
|
|
|
|
|
|
int planes_len = 0;
|
|
|
|
|
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_NEAR) {
|
|
|
|
clip_zmin = planes[planes_len++];
|
|
|
|
}
|
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_FAR) {
|
|
|
|
clip_zmax = planes[planes_len++];
|
|
|
|
}
|
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_WIN) {
|
|
|
|
/* The order in `planes` doesn't matter as all planes are looped over. */
|
|
|
|
clip_xmin = planes[planes_len++];
|
|
|
|
clip_xmax = planes[planes_len++];
|
|
|
|
clip_ymin = planes[planes_len++];
|
|
|
|
clip_ymax = planes[planes_len++];
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_assert(planes_len <= 6);
|
|
|
|
if (planes_len != 0) {
|
|
|
|
RegionView3D *rv3d = region->regiondata;
|
|
|
|
float projmat[4][4];
|
|
|
|
ED_view3d_ob_project_mat_get(rv3d, ob, projmat);
|
|
|
|
planes_from_projmat(projmat, clip_xmin, clip_xmax, clip_ymin, clip_ymax, clip_zmin, clip_zmax);
|
|
|
|
}
|
|
|
|
return planes_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2012-12-23 03:04:19 +00:00
|
|
|
typedef struct foreachScreenObjectVert_userData {
|
|
|
|
void (*func)(void *userData, MVert *mv, const float screen_co_b[2], int index);
|
|
|
|
void *userData;
|
|
|
|
ViewContext vc;
|
|
|
|
eV3DProjTest clip_flag;
|
|
|
|
} foreachScreenObjectVert_userData;
|
2012-10-10 03:13:02 +00:00
|
|
|
|
|
|
|
typedef struct foreachScreenVert_userData {
|
|
|
|
void (*func)(void *userData, BMVert *eve, const float screen_co_b[2], int index);
|
|
|
|
void *userData;
|
|
|
|
ViewContext vc;
|
2012-10-10 04:03:22 +00:00
|
|
|
eV3DProjTest clip_flag;
|
2012-10-10 03:13:02 +00:00
|
|
|
} foreachScreenVert_userData;
|
|
|
|
|
|
|
|
/* user data structures for derived mesh callbacks */
|
|
|
|
typedef struct foreachScreenEdge_userData {
|
|
|
|
void (*func)(void *userData,
|
|
|
|
BMEdge *eed,
|
|
|
|
const float screen_co_a[2],
|
|
|
|
const float screen_co_b[2],
|
|
|
|
int index);
|
|
|
|
void *userData;
|
|
|
|
ViewContext vc;
|
2012-10-10 04:03:22 +00:00
|
|
|
eV3DProjTest clip_flag;
|
2021-06-21 17:25:10 +10:00
|
|
|
|
|
|
|
rctf win_rect; /* copy of: vc.region->winx/winy, use for faster tests, minx/y will always be 0 */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clip plans defined by the the view bounds,
|
|
|
|
* use when #V3D_PROJ_TEST_CLIP_CONTENT is enabled.
|
|
|
|
*/
|
|
|
|
float content_planes[6][4];
|
|
|
|
int content_planes_len;
|
2012-10-10 03:13:02 +00:00
|
|
|
} foreachScreenEdge_userData;
|
|
|
|
|
|
|
|
typedef struct foreachScreenFace_userData {
|
|
|
|
void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index);
|
|
|
|
void *userData;
|
|
|
|
ViewContext vc;
|
2012-10-10 04:03:22 +00:00
|
|
|
eV3DProjTest clip_flag;
|
2012-10-10 03:13:02 +00:00
|
|
|
} foreachScreenFace_userData;
|
|
|
|
|
2019-04-14 10:48:42 +02:00
|
|
|
/**
|
|
|
|
* \note foreach funcs should be called while drawing or directly after
|
|
|
|
* if not, #ED_view3d_init_mats_rv3d() can be used for selection tools
|
2012-10-10 03:13:02 +00:00
|
|
|
* but would not give correct results with dupli's for eg. which don't
|
2019-04-14 10:48:42 +02:00
|
|
|
* use the object matrix in the usual way.
|
|
|
|
*/
|
2012-10-10 03:13:02 +00:00
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
2012-12-23 03:04:19 +00:00
|
|
|
static void meshobject_foreachScreenVert__mapFunc(void *userData,
|
|
|
|
int index,
|
|
|
|
const float co[3],
|
|
|
|
const float UNUSED(no_f[3]),
|
|
|
|
const short UNUSED(no_s[3]))
|
|
|
|
{
|
|
|
|
foreachScreenObjectVert_userData *data = userData;
|
|
|
|
struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index];
|
|
|
|
|
|
|
|
if (!(mv->flag & ME_HIDE)) {
|
|
|
|
float screen_co[2];
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(data->vc.region, co, screen_co, data->clip_flag) !=
|
2012-12-23 03:04:19 +00:00
|
|
|
V3D_PROJ_RET_OK) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->func(data->userData, mv, screen_co, index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void meshobject_foreachScreenVert(
|
2018-04-06 12:07:27 +02:00
|
|
|
ViewContext *vc,
|
2012-12-23 03:04:19 +00:00
|
|
|
void (*func)(void *userData, MVert *eve, const float screen_co[2], int index),
|
|
|
|
void *userData,
|
|
|
|
eV3DProjTest clip_flag)
|
|
|
|
{
|
2021-06-21 17:25:10 +10:00
|
|
|
BLI_assert((clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) == 0);
|
2012-12-23 03:04:19 +00:00
|
|
|
foreachScreenObjectVert_userData data;
|
2018-10-15 14:29:46 +11:00
|
|
|
Mesh *me;
|
2017-07-21 11:53:13 +02:00
|
|
|
|
2018-12-01 19:06:44 +03:00
|
|
|
Scene *scene_eval = DEG_get_evaluated_scene(vc->depsgraph);
|
|
|
|
Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
|
|
|
|
|
2020-05-21 19:32:15 +10:00
|
|
|
me = mesh_get_eval_final(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
|
2012-12-23 03:04:19 +00:00
|
|
|
|
2013-05-08 13:00:52 +00:00
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
|
|
|
|
2012-12-23 03:04:19 +00:00
|
|
|
data.vc = *vc;
|
|
|
|
data.func = func;
|
|
|
|
data.userData = userData;
|
|
|
|
data.clip_flag = clip_flag;
|
|
|
|
|
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
|
2017-05-18 10:41:54 +10:00
|
|
|
ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat);
|
2012-12-23 03:04:19 +00:00
|
|
|
}
|
|
|
|
|
2018-10-15 14:29:46 +11:00
|
|
|
BKE_mesh_foreach_mapped_vert(me, meshobject_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP);
|
2012-12-23 03:04:19 +00:00
|
|
|
}
|
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
static void mesh_foreachScreenVert__mapFunc(void *userData,
|
|
|
|
int index,
|
|
|
|
const float co[3],
|
|
|
|
const float UNUSED(no_f[3]),
|
|
|
|
const short UNUSED(no_s[3]))
|
|
|
|
{
|
|
|
|
foreachScreenVert_userData *data = userData;
|
2013-10-28 02:05:33 +00:00
|
|
|
BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
|
2021-06-21 12:49:16 +10:00
|
|
|
if (UNLIKELY(BM_elem_flag_test(eve, BM_ELEM_HIDDEN))) {
|
|
|
|
return;
|
|
|
|
}
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2021-06-21 12:49:16 +10:00
|
|
|
float screen_co[2];
|
|
|
|
if (ED_view3d_project_float_object(data->vc.region, co, screen_co, data->clip_flag) !=
|
|
|
|
V3D_PROJ_RET_OK) {
|
|
|
|
return;
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
2021-06-21 12:49:16 +10:00
|
|
|
|
|
|
|
data->func(data->userData, eve, screen_co, index);
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mesh_foreachScreenVert(
|
2018-04-06 12:07:27 +02:00
|
|
|
ViewContext *vc,
|
2012-10-10 03:13:02 +00:00
|
|
|
void (*func)(void *userData, BMVert *eve, const float screen_co[2], int index),
|
2012-10-10 04:03:22 +00:00
|
|
|
void *userData,
|
|
|
|
eV3DProjTest clip_flag)
|
2012-10-10 03:13:02 +00:00
|
|
|
{
|
|
|
|
foreachScreenVert_userData data;
|
2017-07-21 11:53:13 +02:00
|
|
|
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
Mesh *me = editbmesh_get_eval_cage_from_orig(
|
2019-06-05 15:14:48 +02:00
|
|
|
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2013-05-08 13:00:52 +00:00
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
data.vc = *vc;
|
|
|
|
data.func = func;
|
|
|
|
data.userData = userData;
|
2012-10-10 04:03:22 +00:00
|
|
|
data.clip_flag = clip_flag;
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2012-10-10 04:03:22 +00:00
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
|
2012-10-10 03:13:02 +00:00
|
|
|
ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
|
2012-10-10 04:03:22 +00:00
|
|
|
}
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2013-10-28 02:05:33 +00:00
|
|
|
BM_mesh_elem_table_ensure(vc->em->bm, BM_VERT);
|
2018-10-09 16:52:46 +11:00
|
|
|
BKE_mesh_foreach_mapped_vert(me, mesh_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP);
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
2021-06-21 17:25:10 +10:00
|
|
|
/**
|
|
|
|
* Edge projection is more involved since part of the edge may be behind the view
|
|
|
|
* or extend beyond the far limits. In the case of single points, these can be ignored.
|
|
|
|
* However it just may still be visible on screen, so constrained the edge to planes
|
|
|
|
* defined by the port to ensure both ends of the edge can be projected, see T32214.
|
|
|
|
*
|
|
|
|
* \note This is unrelated to #V3D_PROJ_TEST_CLIP_BB which must be checked separately.
|
|
|
|
*/
|
|
|
|
static bool mesh_foreachScreenEdge_shared_project_and_test(const ARegion *region,
|
|
|
|
const float v0co[3],
|
|
|
|
const float v1co[3],
|
|
|
|
const eV3DProjTest clip_flag,
|
|
|
|
const rctf *win_rect,
|
|
|
|
const float content_planes[][4],
|
|
|
|
const int content_planes_len,
|
|
|
|
/* Output. */
|
|
|
|
float r_screen_co_a[2],
|
|
|
|
float r_screen_co_b[2])
|
|
|
|
{
|
|
|
|
/* Clipping already handled, no need to check in projection. */
|
|
|
|
eV3DProjTest clip_flag_nowin = clip_flag & ~V3D_PROJ_TEST_CLIP_WIN;
|
|
|
|
|
|
|
|
const eV3DProjStatus status_a = ED_view3d_project_float_object(
|
|
|
|
region, v0co, r_screen_co_a, clip_flag_nowin);
|
|
|
|
const eV3DProjStatus status_b = ED_view3d_project_float_object(
|
|
|
|
region, v1co, r_screen_co_b, clip_flag_nowin);
|
|
|
|
|
|
|
|
if ((status_a == V3D_PROJ_RET_OK) && (status_b == V3D_PROJ_RET_OK)) {
|
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_WIN) {
|
|
|
|
if (!BLI_rctf_isect_segment(win_rect, r_screen_co_a, r_screen_co_b)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (content_planes_len == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Both too near, ignore. */
|
|
|
|
if ((status_a & V3D_PROJ_TEST_CLIP_NEAR) && (status_b & V3D_PROJ_TEST_CLIP_NEAR)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Both too far, ignore. */
|
|
|
|
if ((status_a & V3D_PROJ_TEST_CLIP_FAR) && (status_b & V3D_PROJ_TEST_CLIP_FAR)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Simple cases have been ruled out, clip by viewport planes, then re-project. */
|
|
|
|
float v0co_clip[3], v1co_clip[3];
|
|
|
|
if (!clip_segment_v3_plane_n(
|
|
|
|
v0co, v1co, content_planes, content_planes_len, v0co_clip, v1co_clip)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ED_view3d_project_float_object(region, v0co_clip, r_screen_co_a, clip_flag_nowin) !=
|
|
|
|
V3D_PROJ_RET_OK) ||
|
|
|
|
(ED_view3d_project_float_object(region, v1co_clip, r_screen_co_b, clip_flag_nowin) !=
|
|
|
|
V3D_PROJ_RET_OK)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No need for #V3D_PROJ_TEST_CLIP_WIN check here,
|
|
|
|
* clipping the segment by planes handle this. */
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
static void mesh_foreachScreenEdge__mapFunc(void *userData,
|
|
|
|
int index,
|
|
|
|
const float v0co[3],
|
|
|
|
const float v1co[3])
|
|
|
|
{
|
|
|
|
foreachScreenEdge_userData *data = userData;
|
2013-10-28 02:05:33 +00:00
|
|
|
BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index);
|
2021-06-21 12:49:16 +10:00
|
|
|
if (UNLIKELY(BM_elem_flag_test(eed, BM_ELEM_HIDDEN))) {
|
|
|
|
return;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-21 17:25:10 +10:00
|
|
|
float screen_co_a[2], screen_co_b[2];
|
|
|
|
if (!mesh_foreachScreenEdge_shared_project_and_test(data->vc.region,
|
|
|
|
v0co,
|
|
|
|
v1co,
|
|
|
|
data->clip_flag,
|
|
|
|
&data->win_rect,
|
|
|
|
data->content_planes,
|
|
|
|
data->content_planes_len,
|
|
|
|
screen_co_a,
|
|
|
|
screen_co_b)) {
|
2021-06-21 12:49:16 +10:00
|
|
|
return;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-21 12:49:16 +10:00
|
|
|
data->func(data->userData, eed, screen_co_a, screen_co_b, index);
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mesh_foreachScreenEdge(ViewContext *vc,
|
|
|
|
void (*func)(void *userData,
|
|
|
|
BMEdge *eed,
|
|
|
|
const float screen_co_a[2],
|
|
|
|
const float screen_co_b[2],
|
|
|
|
int index),
|
2012-10-10 04:03:22 +00:00
|
|
|
void *userData,
|
|
|
|
eV3DProjTest clip_flag)
|
2012-10-10 03:13:02 +00:00
|
|
|
{
|
|
|
|
foreachScreenEdge_userData data;
|
2017-07-21 11:53:13 +02:00
|
|
|
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
Mesh *me = editbmesh_get_eval_cage_from_orig(
|
2019-06-05 15:14:48 +02:00
|
|
|
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2013-05-08 13:00:52 +00:00
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
data.vc = *vc;
|
|
|
|
|
|
|
|
data.win_rect.xmin = 0;
|
|
|
|
data.win_rect.ymin = 0;
|
2020-03-06 16:56:42 +01:00
|
|
|
data.win_rect.xmax = vc->region->winx;
|
|
|
|
data.win_rect.ymax = vc->region->winy;
|
2012-10-10 03:13:02 +00:00
|
|
|
|
|
|
|
data.func = func;
|
|
|
|
data.userData = userData;
|
2012-10-10 04:03:22 +00:00
|
|
|
data.clip_flag = clip_flag;
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2012-10-10 04:03:22 +00:00
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
|
2012-10-10 03:13:02 +00:00
|
|
|
ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
|
2012-10-10 04:03:22 +00:00
|
|
|
}
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2021-06-21 17:25:10 +10:00
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) {
|
|
|
|
data.content_planes_len = content_planes_from_clip_flag(
|
|
|
|
vc->region, vc->obedit, clip_flag, data.content_planes);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data.content_planes_len = 0;
|
|
|
|
}
|
|
|
|
|
2013-10-28 02:05:33 +00:00
|
|
|
BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE);
|
2018-10-09 16:52:46 +11:00
|
|
|
BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data);
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
2019-08-02 22:53:27 +10:00
|
|
|
/**
|
|
|
|
* Only call for bound-box clipping.
|
|
|
|
* Otherwise call #mesh_foreachScreenEdge__mapFunc
|
|
|
|
*/
|
|
|
|
static void mesh_foreachScreenEdge_clip_bb_segment__mapFunc(void *userData,
|
|
|
|
int index,
|
|
|
|
const float v0co[3],
|
|
|
|
const float v1co[3])
|
|
|
|
{
|
|
|
|
foreachScreenEdge_userData *data = userData;
|
|
|
|
BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index);
|
2021-06-21 12:49:16 +10:00
|
|
|
if (UNLIKELY(BM_elem_flag_test(eed, BM_ELEM_HIDDEN))) {
|
|
|
|
return;
|
|
|
|
}
|
2019-08-02 22:53:27 +10:00
|
|
|
|
|
|
|
BLI_assert(data->clip_flag & V3D_PROJ_TEST_CLIP_BB);
|
|
|
|
|
2021-06-21 17:25:10 +10:00
|
|
|
float v0co_clip[3], v1co_clip[3];
|
2021-06-21 12:49:16 +10:00
|
|
|
if (!clip_segment_v3_plane_n(v0co, v1co, data->vc.rv3d->clip_local, 4, v0co_clip, v1co_clip)) {
|
|
|
|
return;
|
|
|
|
}
|
2019-08-02 22:53:27 +10:00
|
|
|
|
2021-06-21 17:25:10 +10:00
|
|
|
float screen_co_a[2], screen_co_b[2];
|
|
|
|
if (!mesh_foreachScreenEdge_shared_project_and_test(data->vc.region,
|
|
|
|
v0co_clip,
|
|
|
|
v1co_clip,
|
|
|
|
data->clip_flag,
|
|
|
|
&data->win_rect,
|
|
|
|
data->content_planes,
|
|
|
|
data->content_planes_len,
|
|
|
|
screen_co_a,
|
|
|
|
screen_co_b)) {
|
2021-06-21 12:49:16 +10:00
|
|
|
return;
|
|
|
|
}
|
2019-08-02 22:53:27 +10:00
|
|
|
|
2021-06-21 12:49:16 +10:00
|
|
|
data->func(data->userData, eed, screen_co_a, screen_co_b, index);
|
2019-08-02 22:53:27 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A version of #mesh_foreachScreenEdge that clips the segment when
|
|
|
|
* there is a clipping bounding box.
|
|
|
|
*/
|
|
|
|
void 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)
|
|
|
|
{
|
|
|
|
foreachScreenEdge_userData data;
|
|
|
|
|
|
|
|
Mesh *me = editbmesh_get_eval_cage_from_orig(
|
|
|
|
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
|
|
|
|
|
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
|
|
|
|
|
|
|
data.vc = *vc;
|
|
|
|
|
|
|
|
data.win_rect.xmin = 0;
|
|
|
|
data.win_rect.ymin = 0;
|
2020-03-06 16:56:42 +01:00
|
|
|
data.win_rect.xmax = vc->region->winx;
|
|
|
|
data.win_rect.ymax = vc->region->winy;
|
2019-08-02 22:53:27 +10:00
|
|
|
|
|
|
|
data.func = func;
|
|
|
|
data.userData = userData;
|
|
|
|
data.clip_flag = clip_flag;
|
|
|
|
|
2021-06-21 17:25:10 +10:00
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) {
|
|
|
|
data.content_planes_len = content_planes_from_clip_flag(
|
|
|
|
vc->region, vc->obedit, clip_flag, data.content_planes);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data.content_planes_len = 0;
|
|
|
|
}
|
|
|
|
|
2019-08-02 22:53:27 +10:00
|
|
|
BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE);
|
|
|
|
|
|
|
|
if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != NULL)) {
|
|
|
|
ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups. */
|
|
|
|
BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
static void mesh_foreachScreenFace__mapFunc(void *userData,
|
|
|
|
int index,
|
|
|
|
const float cent[3],
|
|
|
|
const float UNUSED(no[3]))
|
|
|
|
{
|
|
|
|
foreachScreenFace_userData *data = userData;
|
2013-10-28 02:05:33 +00:00
|
|
|
BMFace *efa = BM_face_at_index(data->vc.em->bm, index);
|
2021-06-21 12:49:16 +10:00
|
|
|
if (UNLIKELY(BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) {
|
|
|
|
return;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-21 12:49:16 +10:00
|
|
|
float screen_co[2];
|
|
|
|
if (ED_view3d_project_float_object(data->vc.region, cent, screen_co, data->clip_flag) !=
|
|
|
|
V3D_PROJ_RET_OK) {
|
|
|
|
return;
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
2021-06-21 12:49:16 +10:00
|
|
|
|
|
|
|
data->func(data->userData, efa, screen_co, index);
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mesh_foreachScreenFace(
|
2018-04-06 12:07:27 +02:00
|
|
|
ViewContext *vc,
|
2012-10-10 03:13:02 +00:00
|
|
|
void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index),
|
2012-10-10 04:03:22 +00:00
|
|
|
void *userData,
|
|
|
|
const eV3DProjTest clip_flag)
|
2012-10-10 03:13:02 +00:00
|
|
|
{
|
2021-06-21 17:25:10 +10:00
|
|
|
BLI_assert((clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) == 0);
|
2012-10-10 03:13:02 +00:00
|
|
|
foreachScreenFace_userData data;
|
|
|
|
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
Mesh *me = editbmesh_get_eval_cage_from_orig(
|
2019-06-05 15:14:48 +02:00
|
|
|
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
|
2013-05-08 13:00:52 +00:00
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
data.vc = *vc;
|
|
|
|
data.func = func;
|
|
|
|
data.userData = userData;
|
2012-10-10 04:03:22 +00:00
|
|
|
data.clip_flag = clip_flag;
|
2012-10-10 03:13:02 +00:00
|
|
|
|
2013-10-28 02:05:33 +00:00
|
|
|
BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE);
|
2019-07-07 18:58:11 +02:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
if (BKE_modifiers_uses_subsurf_facedots(vc->scene, vc->obedit)) {
|
2019-07-07 18:58:11 +02:00
|
|
|
BKE_mesh_foreach_mapped_subdiv_face_center(
|
|
|
|
me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_mesh_foreach_mapped_face_center(
|
|
|
|
me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
|
|
|
|
}
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
|
|
|
void nurbs_foreachScreenVert(ViewContext *vc,
|
|
|
|
void (*func)(void *userData,
|
|
|
|
Nurb *nu,
|
|
|
|
BPoint *bp,
|
|
|
|
BezTriple *bezt,
|
|
|
|
int beztindex,
|
2020-05-26 10:37:47 +02:00
|
|
|
bool handles_visible,
|
2012-10-10 03:13:02 +00:00
|
|
|
const float screen_co_b[2]),
|
2012-10-10 04:03:22 +00:00
|
|
|
void *userData,
|
|
|
|
const eV3DProjTest clip_flag)
|
2012-10-10 03:13:02 +00:00
|
|
|
{
|
|
|
|
Curve *cu = vc->obedit->data;
|
|
|
|
Nurb *nu;
|
|
|
|
int i;
|
|
|
|
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
|
2020-05-26 10:37:47 +02:00
|
|
|
/* If no point in the triple is selected, the handles are invisible. */
|
|
|
|
const bool only_selected = (vc->v3d->overlay.handle_display == CURVE_HANDLE_SELECTED);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-08 13:00:52 +00:00
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 04:03:22 +00:00
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
|
|
|
|
ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
for (nu = nurbs->first; nu; nu = nu->next) {
|
|
|
|
if (nu->type == CU_BEZIER) {
|
|
|
|
for (i = 0; i < nu->pntsu; i++) {
|
|
|
|
BezTriple *bezt = &nu->bezt[i];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
if (bezt->hide == 0) {
|
2020-05-26 10:37:47 +02:00
|
|
|
const bool handles_visible = (vc->v3d->overlay.handle_display != CURVE_HANDLE_NONE) &&
|
|
|
|
(!only_selected || BEZT_ISSEL_ANY(bezt));
|
2012-10-10 03:13:02 +00:00
|
|
|
float screen_co[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-05-26 10:37:47 +02:00
|
|
|
if (!handles_visible) {
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(vc->region,
|
2012-10-10 03:13:02 +00:00
|
|
|
bezt->vec[1],
|
|
|
|
screen_co,
|
|
|
|
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
|
|
|
|
V3D_PROJ_RET_OK) {
|
2020-05-26 10:37:47 +02:00
|
|
|
func(userData, nu, NULL, bezt, 1, false, screen_co);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(vc->region,
|
2012-10-10 03:13:02 +00:00
|
|
|
bezt->vec[0],
|
|
|
|
screen_co,
|
|
|
|
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
|
|
|
|
V3D_PROJ_RET_OK) {
|
2020-05-26 10:37:47 +02:00
|
|
|
func(userData, nu, NULL, bezt, 0, true, screen_co);
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(vc->region,
|
2012-10-10 03:13:02 +00:00
|
|
|
bezt->vec[1],
|
|
|
|
screen_co,
|
|
|
|
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
|
|
|
|
V3D_PROJ_RET_OK) {
|
2020-05-26 10:37:47 +02:00
|
|
|
func(userData, nu, NULL, bezt, 1, true, screen_co);
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(vc->region,
|
2012-10-10 03:13:02 +00:00
|
|
|
bezt->vec[2],
|
|
|
|
screen_co,
|
|
|
|
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
|
|
|
|
V3D_PROJ_RET_OK) {
|
2020-05-26 10:37:47 +02:00
|
|
|
func(userData, nu, NULL, bezt, 2, true, screen_co);
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
2012-10-10 03:13:02 +00:00
|
|
|
else {
|
|
|
|
for (i = 0; i < nu->pntsu * nu->pntsv; i++) {
|
|
|
|
BPoint *bp = &nu->bp[i];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
if (bp->hide == 0) {
|
|
|
|
float screen_co[2];
|
|
|
|
if (ED_view3d_project_float_object(
|
2020-03-06 16:56:42 +01:00
|
|
|
vc->region, bp->vec, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
|
2012-10-10 03:13:02 +00:00
|
|
|
V3D_PROJ_RET_OK) {
|
2020-05-26 10:37:47 +02:00
|
|
|
func(userData, nu, bp, NULL, -1, false, screen_co);
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
|
|
|
/* ED_view3d_init_mats_rv3d must be called first */
|
|
|
|
void mball_foreachScreenElem(struct ViewContext *vc,
|
|
|
|
void (*func)(void *userData,
|
|
|
|
struct MetaElem *ml,
|
|
|
|
const float screen_co_b[2]),
|
2012-10-10 04:03:22 +00:00
|
|
|
void *userData,
|
|
|
|
const eV3DProjTest clip_flag)
|
2012-10-10 03:13:02 +00:00
|
|
|
{
|
|
|
|
MetaBall *mb = (MetaBall *)vc->obedit->data;
|
|
|
|
MetaElem *ml;
|
|
|
|
|
2013-05-08 13:00:52 +00:00
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
for (ml = mb->editelems->first; ml; ml = ml->next) {
|
|
|
|
float screen_co[2];
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(vc->region, &ml->x, screen_co, clip_flag) ==
|
|
|
|
V3D_PROJ_RET_OK) {
|
2012-10-10 03:13:02 +00:00
|
|
|
func(userData, ml, screen_co);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
2012-10-10 04:03:22 +00:00
|
|
|
void lattice_foreachScreenVert(ViewContext *vc,
|
|
|
|
void (*func)(void *userData, BPoint *bp, const float screen_co[2]),
|
|
|
|
void *userData,
|
|
|
|
const eV3DProjTest clip_flag)
|
2012-10-10 03:13:02 +00:00
|
|
|
{
|
|
|
|
Object *obedit = vc->obedit;
|
|
|
|
Lattice *lt = obedit->data;
|
|
|
|
BPoint *bp = lt->editlatt->latt->def;
|
2018-07-30 16:54:40 +02:00
|
|
|
DispList *dl = obedit->runtime.curve_cache ?
|
|
|
|
BKE_displist_find(&obedit->runtime.curve_cache->disp, DL_VERTS) :
|
|
|
|
NULL;
|
2014-04-27 00:22:49 +10:00
|
|
|
const float *co = dl ? dl->verts : NULL;
|
2012-10-10 03:13:02 +00:00
|
|
|
int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-08 13:00:52 +00:00
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 04:03:22 +00:00
|
|
|
if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
|
|
|
|
ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
for (i = 0; i < N; i++, bp++, co += 3) {
|
|
|
|
if (bp->hide == 0) {
|
|
|
|
float screen_co[2];
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(vc->region, dl ? co : bp->vec, screen_co, clip_flag) ==
|
2012-10-10 04:03:22 +00:00
|
|
|
V3D_PROJ_RET_OK) {
|
2012-10-10 03:13:02 +00:00
|
|
|
func(userData, bp, screen_co);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
|
|
|
/* ED_view3d_init_mats_rv3d must be called first */
|
|
|
|
void armature_foreachScreenBone(struct ViewContext *vc,
|
|
|
|
void (*func)(void *userData,
|
|
|
|
struct EditBone *ebone,
|
|
|
|
const float screen_co_a[2],
|
|
|
|
const float screen_co_b[2]),
|
2012-10-10 04:03:22 +00:00
|
|
|
void *userData,
|
|
|
|
const eV3DProjTest clip_flag)
|
2012-10-10 03:13:02 +00:00
|
|
|
{
|
|
|
|
bArmature *arm = vc->obedit->data;
|
|
|
|
EditBone *ebone;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-08 13:00:52 +00:00
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
|
|
|
|
if (EBONE_VISIBLE(arm, ebone)) {
|
|
|
|
float screen_co_a[2], screen_co_b[2];
|
|
|
|
int points_proj_tot = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
/* project head location to screenspace */
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(vc->region, ebone->head, screen_co_a, clip_flag) ==
|
2012-10-10 04:03:22 +00:00
|
|
|
V3D_PROJ_RET_OK) {
|
2012-10-10 03:13:02 +00:00
|
|
|
points_proj_tot++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
screen_co_a[0] = IS_CLIPPED; /* weak */
|
2021-03-18 09:35:12 +11:00
|
|
|
/* screen_co_a[1]: intentionally don't set this so we get errors on misuse */
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
/* project tail location to screenspace */
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(vc->region, ebone->tail, screen_co_b, clip_flag) ==
|
2012-10-10 04:03:22 +00:00
|
|
|
V3D_PROJ_RET_OK) {
|
2012-10-10 03:13:02 +00:00
|
|
|
points_proj_tot++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
screen_co_b[0] = IS_CLIPPED; /* weak */
|
2021-03-18 09:35:12 +11:00
|
|
|
/* screen_co_b[1]: intentionally don't set this so we get errors on misuse */
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
if (points_proj_tot) { /* at least one point's projection worked */
|
|
|
|
func(userData, ebone, screen_co_a, screen_co_b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
|
|
|
/* ED_view3d_init_mats_rv3d must be called first */
|
|
|
|
/* almost _exact_ copy of #armature_foreachScreenBone */
|
|
|
|
void pose_foreachScreenBone(struct ViewContext *vc,
|
|
|
|
void (*func)(void *userData,
|
|
|
|
struct bPoseChannel *pchan,
|
|
|
|
const float screen_co_a[2],
|
|
|
|
const float screen_co_b[2]),
|
2012-10-10 04:03:22 +00:00
|
|
|
void *userData,
|
|
|
|
const eV3DProjTest clip_flag)
|
2012-10-10 03:13:02 +00:00
|
|
|
{
|
2018-05-24 19:12:41 +02:00
|
|
|
const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
|
|
|
|
const bArmature *arm_eval = ob_eval->data;
|
2012-10-10 03:13:02 +00:00
|
|
|
bPose *pose = vc->obact->pose;
|
|
|
|
bPoseChannel *pchan;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-05-08 13:00:52 +00:00
|
|
|
ED_view3d_check_mats_rv3d(vc->rv3d);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
|
2018-05-24 19:12:41 +02:00
|
|
|
if (PBONE_VISIBLE(arm_eval, pchan->bone)) {
|
|
|
|
bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
|
2012-10-10 03:13:02 +00:00
|
|
|
float screen_co_a[2], screen_co_b[2];
|
|
|
|
int points_proj_tot = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
/* project head location to screenspace */
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(
|
|
|
|
vc->region, pchan_eval->pose_head, screen_co_a, clip_flag) == V3D_PROJ_RET_OK) {
|
2012-10-10 03:13:02 +00:00
|
|
|
points_proj_tot++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
screen_co_a[0] = IS_CLIPPED; /* weak */
|
2021-03-18 09:35:12 +11:00
|
|
|
/* screen_co_a[1]: intentionally don't set this so we get errors on misuse */
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
/* project tail location to screenspace */
|
2020-03-06 16:56:42 +01:00
|
|
|
if (ED_view3d_project_float_object(
|
|
|
|
vc->region, pchan_eval->pose_tail, screen_co_b, clip_flag) == V3D_PROJ_RET_OK) {
|
2012-10-10 03:13:02 +00:00
|
|
|
points_proj_tot++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
screen_co_b[0] = IS_CLIPPED; /* weak */
|
2021-03-18 09:35:12 +11:00
|
|
|
/* screen_co_b[1]: intentionally don't set this so we get errors on misuse */
|
2012-10-10 03:13:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-10 03:13:02 +00:00
|
|
|
if (points_proj_tot) { /* at least one point's projection worked */
|
|
|
|
func(userData, pchan, screen_co_a, screen_co_b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|