diff options
author | Germano Cavalcante <germano.costa@ig.com.br> | 2016-05-11 12:59:02 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2016-05-11 13:20:25 +0300 |
commit | 67d2de882841f56c9cd35f0f0e7329b0c9190c97 (patch) | |
tree | 49778334fe1d4e71e19a62a5876a8d10e4a6e2ff /source/blender/editors/transform/transform_snap.c | |
parent | 4a135ad2b7886c3a4731f7db7ddce60af8068f32 (diff) |
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.
Diffstat (limited to 'source/blender/editors/transform/transform_snap.c')
-rw-r--r-- | source/blender/editors/transform/transform_snap.c | 474 |
1 files changed, 69 insertions, 405 deletions
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 ***********************************/ |