From 67d2de882841f56c9cd35f0f0e7329b0c9190c97 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Wed, 11 May 2016 19:59:02 +1000 Subject: Transform Volume rewrite/refactor Take advantage of the efficiency provided by the snap_context. Also fixes errors: - volume snap fails based on view angle (T48394). - multiple instances of dupli-objects break volume calculation. --- source/blender/editors/transform/transform_snap.c | 474 +++------------------ .../editors/transform/transform_snap_object.c | 423 ++++++++++++++---- 2 files changed, 404 insertions(+), 493 deletions(-) (limited to 'source/blender/editors/transform') diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index bcbe1f582b7..38f1d37acd6 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -963,86 +963,10 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) mval[1] = t->mval[1]; if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) { - ListBase depth_peels; - DepthPeel *p1, *p2; - const float *last_p = NULL; - float max_dist = FLT_MAX; - float p[3] = {0.0f, 0.0f, 0.0f}; - - BLI_listbase_clear(&depth_peels); - - peelObjectsTransForm(t, mval, t->tsnap.modeSelect, &depth_peels); - -// if (LAST_SNAP_POINT_VALID) -// { -// last_p = LAST_SNAP_POINT; -// } -// else - { - last_p = t->tsnap.snapPoint; - } - - - for (p1 = depth_peels.first; p1; p1 = p1->next) { - if (p1->flag == 0) { - float vec[3]; - float new_dist; - - p2 = NULL; - p1->flag = 1; - - /* if peeling objects, take the first and last from each object */ - if (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) { - DepthPeel *peel; - for (peel = p1->next; peel; peel = peel->next) { - if (peel->ob == p1->ob) { - peel->flag = 1; - p2 = peel; - } - } - } - /* otherwise, pair first with second and so on */ - else { - for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) { - /* nothing to do here */ - } - } - - if (p2) { - p2->flag = 1; - - add_v3_v3v3(vec, p1->p, p2->p); - mul_v3_fl(vec, 0.5f); - } - else { - copy_v3_v3(vec, p1->p); - } - - if (last_p == NULL) { - copy_v3_v3(p, vec); - max_dist = 0; - break; - } - - new_dist = len_squared_v3v3(last_p, vec); - - if (new_dist < max_dist) { - copy_v3_v3(p, vec); - max_dist = new_dist; - } - } - } - - if (max_dist != FLT_MAX) { - copy_v3_v3(loc, p); - /* XXX, is there a correct normal in this case ???, for now just z up */ - no[0] = 0.0; - no[1] = 0.0; - no[2] = 1.0; - found = true; - } - - BLI_freelistN(&depth_peels); + found = peelObjectsTransform( + t, mval, t->tsnap.modeSelect, + (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, + loc, no, NULL); } else { zero_v3(no); /* objects won't set this */ @@ -1302,347 +1226,87 @@ bool snapObjectsTransform( /******************** PEELING *********************************/ - -static int cmpPeel(const void *arg1, const void *arg2) -{ - const DepthPeel *p1 = arg1; - const DepthPeel *p2 = arg2; - int val = 0; - - if (p1->depth < p2->depth) { - val = -1; - } - else if (p1->depth > p2->depth) { - val = 1; - } - - return val; -} - -static void removeDoublesPeel(ListBase *depth_peels) +bool peelObjectsSnapContext( + SnapObjectContext *sctx, + const float mval[2], SnapSelect snap_select, bool use_peel_object, + /* return args */ + float r_loc[3], float r_no[3], float *r_thickness) { - DepthPeel *peel; - - for (peel = depth_peels->first; peel; peel = peel->next) { - DepthPeel *next_peel = peel->next; - - if (next_peel && fabsf(peel->depth - next_peel->depth) < 0.0015f) { - peel->next = next_peel->next; - - if (next_peel->next) { - next_peel->next->prev = peel; + ListBase depths_peel = {0}; + ED_transform_snap_object_project_all_view3d_ex( + sctx, + &(const struct SnapObjectParams){ + .snap_to = SCE_SNAP_MODE_FACE, + .snap_select = snap_select, + .use_object_edit = true, + }, + mval, -1.0f, false, + &depths_peel); + + if (!BLI_listbase_is_empty(&depths_peel)) { + /* At the moment we only use the hits of the first object */ + struct SnapObjectHitDepth *hit_min = depths_peel.first; + for (struct SnapObjectHitDepth *iter = hit_min->next; iter; iter = iter->next) { + if (iter->depth < hit_min->depth) { + hit_min = iter; } - - MEM_freeN(next_peel); } - } -} - -static void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob) -{ - DepthPeel *peel = MEM_callocN(sizeof(DepthPeel), "DepthPeel"); - - peel->depth = depth; - peel->ob = ob; - copy_v3_v3(peel->p, p); - copy_v3_v3(peel->no, no); - - BLI_addtail(depth_peels, peel); - - peel->flag = 0; -} - -struct PeelRayCast_Data { - BVHTreeFromMesh bvhdata; - - /* internal vars for adding peel */ - Object *ob; - const float (*obmat)[4]; - const float (*timat)[3]; - - const float *ray_start; /* globalspace */ - - const MLoopTri *looptri; - const float (*polynors)[3]; /* optional, can be NULL */ - - /* output list */ - ListBase *depth_peels; -}; - -struct PeelEditMeshRayCast_Data { - BVHTreeFromEditMesh bvhdata; - - /* internal vars for adding peel */ - Object *ob; - const float(*obmat)[4]; - const float(*timat)[3]; - - const float *ray_start; /* globalspace */ - - /* output list */ - ListBase *depth_peels; -}; - -static void peelRayCast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) -{ - struct PeelRayCast_Data *data = userdata; - - data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit); - - if (hit->index != -1) { - /* get all values in worldspace */ - float location[3], normal[3]; - float depth; - - /* worldspace location */ - mul_v3_m4v3(location, (float (*)[4])data->obmat, hit->co); - depth = len_v3v3(location, data->ray_start); - - /* worldspace normal */ - copy_v3_v3(normal, data->polynors ? data->polynors[data->looptri[hit->index].poly] : hit->no); - mul_m3_v3((float (*)[3])data->timat, normal); - normalize_v3(normal); - - addDepthPeel(data->depth_peels, depth, location, normal, data->ob); - } -} - -static void peelEditMeshRayCast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) -{ - struct PeelEditMeshRayCast_Data *data = userdata; - - data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit); - - if (hit->index != -1) { - /* get all values in worldspace */ - float location[3], normal[3]; - float depth; - - /* worldspace location */ - mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co); - depth = len_v3v3(location, data->ray_start); - - /* worldspace normal */ - copy_v3_v3(normal, hit->no); - mul_m3_v3((float(*)[3])data->timat, normal); - normalize_v3(normal); - - addDepthPeel(data->depth_peels, depth, location, normal, data->ob); - } -} - -static bool peelDerivedMesh( - Object *ob, DerivedMesh *dm, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]), - ListBase *depth_peels) -{ - bool retval = false; - int totvert = dm->getNumVerts(dm); - - if (totvert > 0) { - const MLoopTri *looptri = dm->getLoopTriArray(dm); - const int looptri_num = dm->getNumLoopTri(dm); - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - float ray_start_local[3], ray_normal_local[3]; - bool test = true; - - invert_m4_m4(imat, obmat); - - transpose_m3_m4(timat, imat); - - mul_v3_m4v3(ray_start_local, imat, ray_start); - mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); - - /* If number of vert is more than an arbitrary limit, - * test against boundbox first - * */ - if (looptri_num > 16) { - BoundBox *bb = BKE_object_boundbox_get(ob); - - if (bb) { - BoundBox bb_temp; - - /* We cannot aford a bbox with some null dimension, which may happen in some cases... - * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */ - bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f); - - test = BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, NULL); + struct SnapObjectHitDepth *hit_max = NULL; + + if (use_peel_object) { + /* if peeling objects, take the first and last from each object */ + hit_max = hit_min; + for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) { + if ((iter->depth > hit_max->depth) && (iter->ob_uuid == hit_min->ob_uuid)) { + hit_max = iter; + } } } - - if (test == true) { - struct PeelRayCast_Data data; - - bvhtree_from_mesh_looptri(&data.bvhdata, dm, 0.0f, 4, 6); - - if (data.bvhdata.tree != NULL) { - data.ob = ob; - data.obmat = (const float (*)[4])obmat; - data.timat = (const float (*)[3])timat; - data.ray_start = ray_start; - data.looptri = looptri; - data.polynors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */ - data.depth_peels = depth_peels; - - BLI_bvhtree_ray_cast_all( - data.bvhdata.tree, ray_start_local, ray_normal_local, 0.0f, BVH_RAYCAST_DIST_MAX, - peelRayCast_cb, &data); + else { + /* otherwise, pair first with second and so on */ + for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) { + if ((iter != hit_min) && (iter->ob_uuid == hit_min->ob_uuid)) { + if (hit_max == NULL) { + hit_max = iter; + } + else if (iter->depth < hit_max->depth) { + hit_max = iter; + } + } } - - free_bvhtree_from_mesh(&data.bvhdata); - } - } - - return retval; -} - -static bool peelEditMesh( - Object *ob, BMEditMesh *em, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], - ListBase *depth_peels) -{ - bool retval = false; - int totvert = em->bm->totvert; - - if (totvert > 0) { - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - float ray_start_local[3], ray_normal_local[3]; - bool test = true; - - invert_m4_m4(imat, obmat); - - transpose_m3_m4(timat, imat); - - mul_v3_m4v3(ray_start_local, imat, ray_start); - mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); - - if (test == true) { - struct PeelEditMeshRayCast_Data data; - - BLI_bitmap *looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__); - int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( - em->bm, looptri_mask, - BM_elem_cb_check_hflag_enabled_simple(BMFace *, (BM_ELEM_SELECT | BM_ELEM_HIDDEN))); - - bvhtree_from_editmesh_looptri_ex(&data.bvhdata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6); - - MEM_freeN(looptri_mask); - - if (data.bvhdata.tree != NULL) { - data.ob = ob; - data.obmat = (const float(*)[4])obmat; - data.timat = (const float(*)[3])timat; - data.ray_start = ray_start; - data.depth_peels = depth_peels; - - BLI_bvhtree_ray_cast_all( - data.bvhdata.tree, ray_start_local, ray_normal_local, 0.0f, BVH_RAYCAST_DIST_MAX, - peelEditMeshRayCast_cb, &data); + /* in this case has only one hit. treat as raycast */ + if (hit_max == NULL) { + hit_max = hit_min; } - - free_bvhtree_from_editmesh(&data.bvhdata); } - } - - return retval; -} - -static bool peelObjects( - Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, - const float mval[2], SnapSelect snap_select, - ListBase *r_depth_peels) -{ - Base *base; - bool retval = false; - float ray_start[3], ray_normal[3]; - - if (ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal, true) == false) { - return false; - } - - for (base = scene->base.first; base != NULL; base = base->next) { - if (BASE_SELECTABLE(v3d, base)) { - Object *ob = base->object; - - if (ob->transflag & OB_DUPLI) { - DupliObject *dupli_ob; - ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); - - for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { - Object *dob = dupli_ob->ob; - - if (dob->type == OB_MESH) { - BMEditMesh *em; - bool val; - if (dob != obedit) { - DerivedMesh *dm; - dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH); - val = peelDerivedMesh(dob, dm, dob->obmat, ray_start, ray_normal, mval, r_depth_peels); + mid_v3_v3v3(r_loc, hit_min->co, hit_max->co); - dm->release(dm); - } - else { - em = BKE_editmesh_from_object(dob); - val = peelEditMesh(dob, em, dob->obmat, ray_start, ray_normal, r_depth_peels); - } + if (r_thickness) { + *r_thickness = hit_max->depth - hit_min->depth; + } - retval = retval || val; - } - } - - free_object_duplilist(lb); - } - - if (ob->type == OB_MESH) { - bool val = false; + /* XXX, is there a correct normal in this case ???, for now just z up */ + r_no[0] = 0.0; + r_no[1] = 0.0; + r_no[2] = 1.0; - if (ob != obedit && ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT))) { - DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - - val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); - dm->release(dm); - } - else if (ob == obedit && snap_select != SNAP_NOT_OBEDIT) { - BMEditMesh *em = BKE_editmesh_from_object(ob); - DerivedMesh *dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); - - val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); - dm->release(dm); - } - - retval = retval || val; - - } - } + BLI_freelistN(&depths_peel); + return true; } - - BLI_listbase_sort(r_depth_peels, cmpPeel); - removeDoublesPeel(r_depth_peels); - - return retval; -} - -bool peelObjectsTransForm( - TransInfo *t, const float mval[2], SnapSelect snap_select, - ListBase *r_depth_peels) -{ - return peelObjects(t->scene, t->view, t->ar, t->obedit, mval, snap_select, r_depth_peels); + return false; } -bool peelObjectsContext( - bContext *C, const float mval[2], SnapSelect snap_select, - ListBase *r_depth_peels) +bool peelObjectsTransform( + TransInfo *t, + const float mval[2], SnapSelect snap_select, bool use_peel_object, + /* return args */ + float r_loc[3], float r_no[3], float *r_thickness) { - Scene *scene = CTX_data_scene(C); - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - ARegion *ar = CTX_wm_region(C); - Object *obedit = CTX_data_edit_object(C); - - return peelObjects(scene, v3d, ar, obedit, mval, snap_select, r_depth_peels); + return peelObjectsSnapContext( + t->tsnap.object_context, + mval, snap_select, use_peel_object, + r_loc, r_no, r_thickness); } /******************** NODES ***********************************/ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 57352f38789..17c77df58f2 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -34,6 +34,7 @@ #include "BLI_memarena.h" #include "BLI_ghash.h" #include "BLI_linklist.h" +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_armature_types.h" @@ -109,6 +110,111 @@ struct SnapObjectContext { }; +static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); + + +/* -------------------------------------------------------------------- */ + +/** \name Support for storing all depths, not just the first (raycast 'all') + * + * This uses a list of #SnapObjectHitDepth structs. + * + * \{ */ + +/* Store all ray-hits */ +struct RayCastAll_Data { + void *bvhdata; + + /* internal vars for adding depths */ + BVHTree_RayCastCallback raycast_callback; + + const float(*obmat)[4]; + const float(*timat)[3]; + + float len_diff; + float local_scale; + + Object *ob; + unsigned int ob_uuid; + + /* DerivedMesh only */ + DerivedMesh *dm; + const struct MLoopTri *dm_looptri; + + /* output data */ + ListBase *hit_list; + bool retval; +}; + +static struct SnapObjectHitDepth *hit_depth_create( + const float depth, const float co[3], const float no[3], int index, + Object *ob, const float obmat[4][4], unsigned int ob_uuid) +{ + struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__); + + hit->depth = depth; + copy_v3_v3(hit->co, co); + copy_v3_v3(hit->no, no); + hit->index = index; + + hit->ob = ob; + copy_m4_m4(hit->obmat, (float(*)[4])obmat); + hit->ob_uuid = ob_uuid; + + return hit; +} + +static int hit_depth_cmp(const void *arg1, const void *arg2) +{ + const struct SnapObjectHitDepth *h1 = arg1; + const struct SnapObjectHitDepth *h2 = arg2; + int val = 0; + + if (h1->depth < h2->depth) { + val = -1; + } + else if (h1->depth > h2->depth) { + val = 1; + } + + return val; +} + +static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + struct RayCastAll_Data *data = userdata; + data->raycast_callback(data->bvhdata, index, ray, hit); + if (hit->index != -1) { + /* get all values in worldspace */ + float location[3], normal[3]; + float depth; + + /* worldspace location */ + mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co); + depth = (hit->dist + data->len_diff) / data->local_scale; + + /* worldspace normal */ + copy_v3_v3(normal, hit->no); + mul_m3_v3((float(*)[3])data->timat, normal); + normalize_v3(normal); + + /* currently unused, and causes issues when looptri's havn't been calculated. + * since theres some overhead in ensuring this data is valid, it may need to be optional. */ +#if 0 + if (data->dm) { + hit->index = dm_looptri_to_poly_index(data->dm, &data->dm_looptri[hit->index]); + } +#endif + + struct SnapObjectHitDepth *hit_item = hit_depth_create( + depth, location, normal, hit->index, + data->ob, data->obmat, data->ob_uuid); + BLI_addtail(data->hit_list, hit_item); + } +} + +/** \} */ + /* -------------------------------------------------------------------- */ @@ -572,8 +678,10 @@ static bool snapDerivedMesh( SnapObjectContext *sctx, Object *ob, DerivedMesh *dm, float obmat[4][4], const float mval[2], float *dist_px, const short snap_to, bool do_bb, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, - float r_loc[3], float r_no[3], int *r_index) + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], + float *ray_depth, unsigned int ob_index, + float r_loc[3], float r_no[3], int *r_index, + ListBase *r_hit_list) { ARegion *ar = sctx->v3d_data.ar; bool retval = false; @@ -729,31 +837,55 @@ static bool snapDerivedMesh( switch (snap_to) { case SCE_SNAP_MODE_FACE: { - BVHTreeRayHit hit; + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index, + data.dm = dm; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit; - hit.index = -1; - hit.dist = local_depth; + hit.index = -1; + hit.dist = local_depth; - if (treedata->tree && - BLI_bvhtree_ray_cast(treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - if (hit.dist <= *ray_depth) { - *ray_depth = hit.dist; - copy_v3_v3(r_loc, hit.co); - copy_v3_v3(r_no, hit.no); - - /* back to worldspace */ - mul_m4_v3(obmat, r_loc); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - - retval = true; - - if (r_index) { - *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); + if (treedata->tree && + BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + copy_v3_v3(r_no, hit.no); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + + retval = true; + + if (r_index) { + *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); + } } } } @@ -814,8 +946,10 @@ static bool snapEditMesh( SnapObjectContext *sctx, Object *ob, BMEditMesh *em, float obmat[4][4], const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, - float r_loc[3], float r_no[3], int *r_index) + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], + float *ray_depth, const unsigned int ob_index, + float r_loc[3], float r_no[3], int *r_index, + ListBase *r_hit_list) { ARegion *ar = sctx->v3d_data.ar; bool retval = false; @@ -951,7 +1085,7 @@ static bool snapEditMesh( */ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, - len_diff - len_v3v3(ray_start_local, ray_org_local)); + len_diff - len_v3v3(ray_start_local, ray_org_local)); local_depth -= len_diff; } else { @@ -961,32 +1095,55 @@ static bool snapEditMesh( switch (snap_to) { case SCE_SNAP_MODE_FACE: { - BVHTreeRayHit hit; + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index; + data.dm = NULL; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit; - hit.index = -1; - hit.dist = local_depth; + hit.index = -1; + hit.dist = local_depth; - if (treedata->tree && - BLI_bvhtree_ray_cast( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - if (hit.dist <= *ray_depth) { - *ray_depth = hit.dist; - copy_v3_v3(r_loc, hit.co); - copy_v3_v3(r_no, hit.no); - - /* back to worldspace */ - mul_m4_v3(obmat, r_loc); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - - retval = true; - - if (r_index) { - *r_index = hit.index; + if (treedata->tree && + BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + copy_v3_v3(r_no, hit.no); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + + retval = true; + + if (r_index) { + *r_index = hit.index; + } } } } @@ -1050,11 +1207,13 @@ static bool snapEditMesh( static bool snapObject( SnapObjectContext *sctx, Object *ob, float obmat[4][4], bool use_obedit, const short snap_to, - const float mval[2], float *dist_px, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + const float mval[2], float *dist_px, const unsigned int ob_index, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], + float *ray_depth, /* return args */ float r_loc[3], float r_no[3], int *r_index, - Object **r_ob, float r_obmat[4][4]) + Object **r_ob, float r_obmat[4][4], + ListBase *r_hit_list) { ARegion *ar = sctx->v3d_data.ar; bool retval = false; @@ -1066,8 +1225,10 @@ static bool snapObject( em = BKE_editmesh_from_object(ob); retval = snapEditMesh( sctx, ob, em, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index); + ray_start, ray_normal, ray_origin, + ray_depth, ob_index, + r_loc, r_no, r_index, + r_hit_list); } else { /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978. @@ -1082,8 +1243,9 @@ static bool snapObject( } retval = snapDerivedMesh( sctx, ob, dm, obmat, mval, dist_px, snap_to, true, - ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index); + ray_start, ray_normal, ray_origin, + ray_depth, ob_index, + r_loc, r_no, r_index, r_hit_list); dm->release(dm); } @@ -1132,19 +1294,22 @@ static bool snapObjectsRay( const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, /* return args */ float r_loc[3], float r_no[3], int *r_index, - Object **r_ob, float r_obmat[4][4]) + Object **r_ob, float r_obmat[4][4], + ListBase *r_hit_list) { Base *base; bool retval = false; + bool snap_obedit_first = snap_select == SNAP_ALL && obedit; + unsigned int ob_index = 0; - if (snap_select == SNAP_ALL && obedit) { + if (snap_obedit_first) { Object *ob = obedit; retval |= snapObject( sctx, ob, ob->obmat, true, snap_to, - mval, dist_px, + mval, dist_px, ob_index++, ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index, r_ob, r_obmat); + r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA @@ -1157,9 +1322,9 @@ static bool snapObjectsRay( Object *ob = base->object; retval |= snapObject( sctx, ob, ob->obmat, false, snap_to, - mval, dist_px, + mval, dist_px, ob_index++, ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index, r_ob, r_obmat); + r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } for (base = sctx->scene->base.first; base != NULL; base = base->next) { @@ -1173,12 +1338,6 @@ static bool snapObjectsRay( Object *ob_snap = ob; bool use_obedit = false; - /* for linked objects, use the same object but a different matrix */ - if (obedit && ob->data == obedit->data) { - use_obedit = true; - ob_snap = obedit; - } - if (ob->transflag & OB_DUPLI) { DupliObject *dupli_ob; ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, ob); @@ -1189,19 +1348,33 @@ static bool snapObjectsRay( retval |= snapObject( sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to, - mval, dist_px, + mval, dist_px, ob_index++, ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index, r_ob, r_obmat); + r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } free_object_duplilist(lb); } + if (obedit) { + if ((ob == obedit) && + (snap_obedit_first || (snap_select == SNAP_NOT_OBEDIT))) + { + continue; + } + + if (ob->data == obedit->data) { + /* for linked objects, use the same object but a different matrix */ + use_obedit = true; + ob_snap = obedit; + } + } + retval |= snapObject( sctx, ob_snap, ob->obmat, use_obedit, snap_to, - mval, dist_px, + mval, dist_px, ob_index++, ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index, r_ob, r_obmat); + r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } } @@ -1315,7 +1488,53 @@ bool ED_transform_snap_object_project_ray_ex( base_act, obedit, ray_start, ray_normal, ray_start, ray_depth, r_loc, r_no, r_index, - r_ob, r_obmat); + r_ob, r_obmat, NULL); +} + +/** + * Fill in a list of all hits. + * + * \param ray_depth: Only depths in this range are considered, -1.0 for maximum. + * \param sort: Optionally sort the hits by depth. + * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). + */ +bool ED_transform_snap_object_project_ray_all( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float ray_start[3], const float ray_normal[3], + float ray_depth, bool sort, + ListBase *r_hit_list) +{ + Base *base_act = params->use_object_active ? sctx->scene->basact : NULL; + Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL; + + if (ray_depth == -1.0f) { + ray_depth = BVH_RAYCAST_DIST_MAX; + } + +#ifdef DEBUG + float ray_depth_prev = ray_depth; +#endif + + bool retval = snapObjectsRay( + sctx, + params->snap_select, params->snap_to, + NULL, NULL, + base_act, obedit, + ray_start, ray_normal, ray_start, &ray_depth, + NULL, NULL, NULL, NULL, NULL, + r_hit_list); + + /* meant to be readonly for 'all' hits, ensure it is */ +#ifdef DEBUG + BLI_assert(ray_depth_prev == ray_depth); +#endif + + if (sort) { + BLI_listbase_sort(r_hit_list, hit_depth_cmp); + } + + return retval; } /** @@ -1327,7 +1546,7 @@ bool ED_transform_snap_object_project_ray_ex( */ static bool transform_snap_context_project_ray_impl( SnapObjectContext *sctx, - const float ray_start[3], const float ray_normal[3], float *ray_dist, + const float ray_start[3], const float ray_normal[3], float *ray_depth, float r_co[3], float r_no[3]) { bool ret; @@ -1340,7 +1559,7 @@ static bool transform_snap_context_project_ray_impl( .snap_to = SCE_SNAP_MODE_FACE, .use_object_edit = (sctx->scene->obedit != NULL), }, - ray_start, ray_normal, ray_dist, + ray_start, ray_normal, ray_depth, r_co, r_no, NULL, NULL, NULL); @@ -1349,13 +1568,13 @@ static bool transform_snap_context_project_ray_impl( bool ED_transform_snap_object_project_ray( SnapObjectContext *sctx, - const float ray_origin[3], const float ray_direction[3], float *ray_dist, + const float ray_origin[3], const float ray_direction[3], float *ray_depth, float r_co[3], float r_no[3]) { - float ray_dist_fallback; - if (ray_dist == NULL) { - ray_dist_fallback = BVH_RAYCAST_DIST_MAX; - ray_dist = &ray_dist_fallback; + float ray_depth_fallback; + if (ray_depth == NULL) { + ray_depth_fallback = BVH_RAYCAST_DIST_MAX; + ray_depth = &ray_depth_fallback; } float no_fallback[3]; @@ -1365,7 +1584,7 @@ bool ED_transform_snap_object_project_ray( return transform_snap_context_project_ray_impl( sctx, - ray_origin, ray_direction, ray_dist, + ray_origin, ray_direction, ray_depth, r_co, r_no); } @@ -1376,7 +1595,7 @@ static bool transform_snap_context_project_view3d_mixed_impl( bool use_depth, float r_co[3], float r_no[3]) { - float ray_dist = BVH_RAYCAST_DIST_MAX; + float ray_depth = BVH_RAYCAST_DIST_MAX; bool is_hit = false; float r_no_dummy[3]; @@ -1394,7 +1613,7 @@ static bool transform_snap_context_project_view3d_mixed_impl( for (int i = 0; i < 3; i++) { if ((params->snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) { if (use_depth == false) { - ray_dist = BVH_RAYCAST_DIST_MAX; + ray_depth = BVH_RAYCAST_DIST_MAX; } params_temp.snap_to = elem_type[i]; @@ -1402,7 +1621,7 @@ static bool transform_snap_context_project_view3d_mixed_impl( if (ED_transform_snap_object_project_view3d( sctx, ¶ms_temp, - mval, dist_px, &ray_dist, + mval, dist_px, &ray_depth, r_co, r_no)) { is_hit = true; @@ -1470,7 +1689,7 @@ bool ED_transform_snap_object_project_view3d_ex( mval, dist_px, base_act, obedit, ray_start, ray_normal, ray_orgigin, ray_depth, - r_loc, r_no, r_index, NULL, NULL); + r_loc, r_no, r_index, NULL, NULL, NULL); } bool ED_transform_snap_object_project_view3d( @@ -1488,4 +1707,32 @@ bool ED_transform_snap_object_project_view3d( r_loc, r_no, NULL); } +/** + * see: #ED_transform_snap_object_project_ray_all + */ +bool ED_transform_snap_object_project_all_view3d_ex( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], + float ray_depth, bool sort, + ListBase *r_hit_list) +{ + float ray_start[3], ray_normal[3]; + + BLI_assert(params->snap_to == SCE_SNAP_MODE_FACE); + + if (!ED_view3d_win_to_ray_ex( + sctx->v3d_data.ar, sctx->v3d_data.v3d, + mval, NULL, ray_normal, ray_start, true)) + { + return false; + } + + return ED_transform_snap_object_project_ray_all( + sctx, + params, + ray_start, ray_normal, ray_depth, sort, + r_hit_list); +} + /** \} */ -- cgit v1.2.3