Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_snap_object.c
| Show All 37 Lines | |||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "DNA_view3d_types.h" | #include "DNA_view3d_types.h" | ||||
| #include "BKE_armature.h" | #include "BKE_armature.h" | ||||
| #include "BKE_bvhutils.h" | #include "BKE_bvhutils.h" | ||||
| #include "BKE_curve.h" | #include "BKE_curve.h" | ||||
| #include "BKE_duplilist.h" | #include "BKE_duplilist.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_geometry_set.h" | |||||
| #include "BKE_global.h" | |||||
| #include "BKE_layer.h" | #include "BKE_layer.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_mesh_runtime.h" | #include "BKE_mesh_runtime.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_tracking.h" | #include "BKE_tracking.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| ▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | |||||
| }; | }; | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Utilities | /** \name Utilities | ||||
| * \{ */ | * \{ */ | ||||
| static bool editmesh_eval_final_is_bmesh(const BMEditMesh *em) | /* Mesh used for snapping. | ||||
| * If NULL the BMesh should be used. */ | |||||
| static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide) | |||||
| { | { | ||||
| return (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH); | Mesh *me_eval = ob_eval->data; | ||||
| bool use_hide = false; | |||||
| if (BKE_object_is_in_editmode(ob_eval)) { | |||||
| if (edit_mode_type == SNAP_GEOM_EDIT) { | |||||
| return NULL; | |||||
| } | |||||
| BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval); | |||||
| if ((edit_mode_type == SNAP_GEOM_FINAL) && em_eval->mesh_eval_final) { | |||||
| if (em_eval->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { | |||||
| return NULL; | |||||
| } | |||||
| me_eval = em_eval->mesh_eval_final; | |||||
| use_hide = true; | |||||
| } | |||||
| else if ((edit_mode_type == SNAP_GEOM_CAGE) && em_eval->mesh_eval_cage) { | |||||
| if (em_eval->mesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { | |||||
| return NULL; | |||||
| } | |||||
| me_eval = em_eval->mesh_eval_cage; | |||||
| use_hide = true; | |||||
| } | |||||
| } | |||||
| if (r_use_hide) { | |||||
| *r_use_hide = use_hide; | |||||
| } | |||||
| return me_eval; | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Snap Object Data | /** \name Snap Object Data | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | switch (sod->type) { | ||||
| case SNAP_EDIT_MESH: { | case SNAP_EDIT_MESH: { | ||||
| snap_object_data_editmesh_clear(sod); | snap_object_data_editmesh_clear(sod); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| memset(&sod->type, 0x0, sizeof(*sod) - offsetof(SnapObjectData, type)); | memset(&sod->type, 0x0, sizeof(*sod) - offsetof(SnapObjectData, type)); | ||||
| } | } | ||||
| static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob) | static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob_eval) | ||||
| { | { | ||||
| SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob); | SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob_eval); | ||||
| if (sod == NULL) { | if (sod == NULL) { | ||||
| if (sctx->cache.data_to_object_map != NULL) { | if (sctx->cache.data_to_object_map != NULL) { | ||||
| ob = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob->data); | ob_eval = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob_eval->data); | ||||
| /* Could be NULl when mixing edit-mode and non edit-mode objects. */ | /* Could be NULl when mixing edit-mode and non edit-mode objects. */ | ||||
| if (ob != NULL) { | if (ob_eval != NULL) { | ||||
| sod = BLI_ghash_lookup(sctx->cache.object_map, ob); | sod = BLI_ghash_lookup(sctx->cache.object_map, ob_eval); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return sod; | return sod; | ||||
| } | } | ||||
| static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob) | static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, | ||||
| Object *ob_eval, | |||||
| Mesh *me_eval, | |||||
| bool use_hide) | |||||
| { | { | ||||
| SnapObjectData *sod; | SnapObjectData *sod; | ||||
| void **sod_p; | void **sod_p; | ||||
| bool init = false; | bool init = false; | ||||
| if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { | if (BLI_ghash_ensure_p(sctx->cache.object_map, ob_eval, &sod_p)) { | ||||
| sod = *sod_p; | sod = *sod_p; | ||||
| bool is_dirty = false; | |||||
| if (sod->type != SNAP_MESH) { | if (sod->type != SNAP_MESH) { | ||||
| is_dirty = true; | |||||
| } | |||||
| else if (sod->treedata_mesh.tree && sod->treedata_mesh.cached && | |||||
| !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->treedata_mesh.tree)) { | |||||
| /* The tree is owned by the Mesh and may have been freed since we last used. */ | |||||
| is_dirty = true; | |||||
| } | |||||
| else if (sod->bvhtree[0] && sod->cached[0] && | |||||
| !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[0])) { | |||||
| /* The tree is owned by the Mesh and may have been freed since we last used. */ | |||||
| is_dirty = true; | |||||
| } | |||||
| else if (sod->bvhtree[1] && sod->cached[1] && | |||||
| !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[1])) { | |||||
| /* The tree is owned by the Mesh and may have been freed since we last used. */ | |||||
| is_dirty = true; | |||||
| } | |||||
| else if (!sod->treedata_mesh.looptri_allocated && | |||||
| sod->treedata_mesh.looptri != me_eval->runtime.looptris.array) { | |||||
| is_dirty = true; | |||||
| } | |||||
| else if (!sod->treedata_mesh.vert_allocated && sod->treedata_mesh.vert != me_eval->mvert) { | |||||
| is_dirty = true; | |||||
| } | |||||
| else if (!sod->treedata_mesh.loop_allocated && sod->treedata_mesh.loop != me_eval->mloop) { | |||||
| is_dirty = true; | |||||
| } | |||||
| else if (!sod->treedata_mesh.edge_allocated && sod->treedata_mesh.edge != me_eval->medge) { | |||||
| is_dirty = true; | |||||
| } | |||||
| else if (sod->poly != me_eval->mpoly) { | |||||
| is_dirty = true; | |||||
| } | |||||
| if (is_dirty) { | |||||
| snap_object_data_clear(sod); | snap_object_data_clear(sod); | ||||
| init = true; | init = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); | sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); | ||||
| init = true; | init = true; | ||||
| } | } | ||||
| if (init) { | if (init) { | ||||
| sod->type = SNAP_MESH; | sod->type = SNAP_MESH; | ||||
| /* start assuming that it has each of these element types */ | |||||
| /* The BVHTree from looptris is always required. */ | |||||
| BLI_assert(sod->treedata_mesh.tree == NULL); | |||||
| BKE_bvhtree_from_mesh_get(&sod->treedata_mesh, | |||||
| me_eval, | |||||
| use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI, | |||||
| 4); | |||||
| if (sod->treedata_mesh.tree == NULL) { | |||||
| sod->treedata_mesh.vert = me_eval->mvert; | |||||
| sod->treedata_mesh.loop = me_eval->mloop; | |||||
| sod->treedata_mesh.looptri = BKE_mesh_runtime_looptri_ensure(me_eval); | |||||
| BLI_assert(sod->has_looptris == false); | |||||
| } | |||||
| else { | |||||
| BLI_assert(sod->treedata_mesh.vert != NULL); | |||||
| BLI_assert(sod->treedata_mesh.loop != NULL); | |||||
| BLI_assert(sod->treedata_mesh.looptri != NULL); | |||||
| sod->has_looptris = true; | sod->has_looptris = true; | ||||
| } | |||||
| /* Required for snapping with occlusion. */ | |||||
| sod->treedata_mesh.edge = me_eval->medge; | |||||
| sod->poly = me_eval->mpoly; | |||||
| /* Start assuming that it has each of these element types. */ | |||||
| sod->has_loose_edge = true; | sod->has_loose_edge = true; | ||||
| sod->has_loose_vert = true; | sod->has_loose_vert = true; | ||||
| } | } | ||||
| return sod; | return sod; | ||||
| } | } | ||||
| static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob) | static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval); | ||||
| if (em->mesh_eval_final) { | if (em_eval->mesh_eval_final) { | ||||
| return &em->mesh_eval_final->runtime; | return &em_eval->mesh_eval_final->runtime; | ||||
| } | } | ||||
| if (em->mesh_eval_cage) { | if (em_eval->mesh_eval_cage) { | ||||
| return &em->mesh_eval_cage->runtime; | return &em_eval->mesh_eval_cage->runtime; | ||||
| } | } | ||||
| return &((Mesh *)ob->data)->runtime; | return &((Mesh *)ob_eval->data)->runtime; | ||||
| } | } | ||||
| static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, | static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, | ||||
| Object *ob, | Object *ob_eval, | ||||
| BMEditMesh *em) | BMEditMesh *em) | ||||
| { | { | ||||
| SnapObjectData *sod; | SnapObjectData *sod; | ||||
| void **sod_p; | void **sod_p; | ||||
| bool init = false, init_min_max = true, clear_cache = false; | bool init = false; | ||||
| { | { | ||||
| /* Use object-data as the key in ghash since the editmesh | /* Use object-data as the key in ghash since the editmesh | ||||
| * is used to create bvhtree and is the same for each linked object. */ | * is used to create bvhtree and is the same for each linked object. */ | ||||
| if (sctx->cache.data_to_object_map == NULL) { | if (sctx->cache.data_to_object_map == NULL) { | ||||
| sctx->cache.data_to_object_map = BLI_ghash_ptr_new(__func__); | sctx->cache.data_to_object_map = BLI_ghash_ptr_new(__func__); | ||||
| } | } | ||||
| void **ob_p; | void **ob_p; | ||||
| if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob->data, &ob_p)) { | if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob_eval->data, &ob_p)) { | ||||
| ob = *ob_p; | ob_eval = *ob_p; | ||||
| } | } | ||||
| else { | else { | ||||
| *ob_p = ob; | *ob_p = ob_eval; | ||||
| } | } | ||||
| } | } | ||||
| if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { | if (BLI_ghash_ensure_p(sctx->cache.object_map, ob_eval, &sod_p)) { | ||||
| sod = *sod_p; | sod = *sod_p; | ||||
| bool clear = false; | bool is_dirty = false; | ||||
| /* Check if the geometry has changed. */ | /* Check if the geometry has changed. */ | ||||
| if (sod->type != SNAP_EDIT_MESH) { | if (sod->type != SNAP_EDIT_MESH) { | ||||
| clear = true; | is_dirty = true; | ||||
| } | } | ||||
| else if (sod->treedata_editmesh.em != em) { | else if (sod->treedata_editmesh.em != em) { | ||||
| clear_cache = true; | is_dirty = true; | ||||
| init = true; | |||||
| } | } | ||||
| else if (sod->mesh_runtime) { | else if (sod->mesh_runtime) { | ||||
| if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob)) { | if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob_eval)) { | ||||
| clear_cache = true; | if (G.moving) { | ||||
| init = true; | /* Hack to avoid updating while transforming. */ | ||||
| BLI_assert(!sod->treedata_editmesh.cached && !sod->cached[0] && !sod->cached[1]); | |||||
| sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval); | |||||
| } | |||||
| else { | |||||
| is_dirty = true; | |||||
| } | |||||
| } | } | ||||
| else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached && | else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached && | ||||
| !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) { | !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) { | ||||
| /* The tree is owned by the EditMesh and may have been freed since we last used! */ | /* The tree is owned by the EditMesh and may have been freed since we last used! */ | ||||
| clear = true; | is_dirty = true; | ||||
| } | } | ||||
| else if (sod->bvhtree[0] && sod->cached[0] && | else if (sod->bvhtree[0] && sod->cached[0] && | ||||
| !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) { | !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) { | ||||
| /* The tree is owned by the EditMesh and may have been freed since we last used! */ | /* The tree is owned by the EditMesh and may have been freed since we last used! */ | ||||
| clear = true; | is_dirty = true; | ||||
| } | } | ||||
| else if (sod->bvhtree[1] && sod->cached[1] && | else if (sod->bvhtree[1] && sod->cached[1] && | ||||
| !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) { | !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) { | ||||
| /* The tree is owned by the EditMesh and may have been freed since we last used! */ | /* The tree is owned by the EditMesh and may have been freed since we last used! */ | ||||
| clear = true; | is_dirty = true; | ||||
| } | } | ||||
| } | } | ||||
| if (clear) { | if (is_dirty) { | ||||
| snap_object_data_clear(sod); | snap_object_data_clear(sod); | ||||
| init = true; | init = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); | sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); | ||||
| init = true; | init = true; | ||||
| } | } | ||||
| if (init) { | if (init) { | ||||
| sod->type = SNAP_EDIT_MESH; | sod->type = SNAP_EDIT_MESH; | ||||
| sod->treedata_editmesh.em = em; | sod->treedata_editmesh.em = em; | ||||
| sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval); | |||||
| if (clear_cache) { | |||||
| /* Only init min and max when you have a non-custom bvhtree pending. */ | |||||
| init_min_max = false; | |||||
| if (sod->treedata_editmesh.cached) { | |||||
| sod->treedata_editmesh.tree = NULL; | |||||
| init_min_max = true; | |||||
| } | |||||
| for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) { | |||||
| if (sod->cached[i]) { | |||||
| sod->bvhtree[i] = NULL; | |||||
| init_min_max = true; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (init_min_max) { | |||||
| bm_mesh_minmax(em->bm, sod->min, sod->max); | bm_mesh_minmax(em->bm, sod->min, sod->max); | ||||
| } | } | ||||
| sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob); | |||||
| } | |||||
| return sod; | return sod; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Iterator | /** \name Iterator | ||||
| * \{ */ | * \{ */ | ||||
| typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, | typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, | ||||
| Object *ob, | Object *ob_eval, | ||||
| float obmat[4][4], | float obmat[4][4], | ||||
| bool use_obedit, | eSnapEditType edit_mode_type, | ||||
| bool use_backface_culling, | bool use_backface_culling, | ||||
| bool is_object_active, | bool is_object_active, | ||||
| void *data); | void *data); | ||||
| /** | /** | ||||
| * Walks through all objects in the scene to create the list of objects to snap. | * Walks through all objects in the scene to create the list of objects to snap. | ||||
| */ | */ | ||||
| static void iter_snap_objects(SnapObjectContext *sctx, | static void iter_snap_objects(SnapObjectContext *sctx, | ||||
| Depsgraph *depsgraph, | Depsgraph *depsgraph, | ||||
| const struct SnapObjectParams *params, | const struct SnapObjectParams *params, | ||||
| IterSnapObjsCallback sob_callback, | IterSnapObjsCallback sob_callback, | ||||
| void *data) | void *data) | ||||
| { | { | ||||
| ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); | ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); | ||||
| const View3D *v3d = sctx->v3d_data.v3d; | const View3D *v3d = sctx->v3d_data.v3d; | ||||
| const eSnapSelect snap_select = params->snap_select; | const eSnapSelect snap_select = params->snap_select; | ||||
| const bool use_object_edit_cage = params->use_object_edit_cage; | const eSnapEditType edit_mode_type = params->edit_mode_type; | ||||
| const bool use_backface_culling = params->use_backface_culling; | const bool use_backface_culling = params->use_backface_culling; | ||||
| Base *base_act = view_layer->basact; | Base *base_act = view_layer->basact; | ||||
| if (snap_select == SNAP_ONLY_ACTIVE) { | |||||
| Object *obj_eval = DEG_get_evaluated_object(depsgraph, base_act->object); | |||||
| sob_callback( | |||||
| sctx, obj_eval, obj_eval->obmat, edit_mode_type, use_backface_culling, true, data); | |||||
| return; | |||||
| } | |||||
| for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { | for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { | ||||
| if (!BASE_VISIBLE(v3d, base)) { | if (!BASE_VISIBLE(v3d, base)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE) { | if (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| Show All 9 Lines | for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { | ||||
| } | } | ||||
| else if (snap_select == SNAP_NOT_ACTIVE) { | else if (snap_select == SNAP_NOT_ACTIVE) { | ||||
| if (is_object_active) { | if (is_object_active) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object); | Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object); | ||||
| if (obj_eval->transflag & OB_DUPLI) { | if (obj_eval->transflag & OB_DUPLI || | ||||
| DupliObject *dupli_ob; | (obj_eval->runtime.geometry_set_eval != NULL && | ||||
| BKE_geometry_set_has_instances(obj_eval->runtime.geometry_set_eval))) { | |||||
| ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval); | ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval); | ||||
| for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { | for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { | ||||
| BLI_assert(DEG_is_evaluated_object(dupli_ob->ob)); | |||||
| sob_callback(sctx, | sob_callback(sctx, | ||||
| dupli_ob->ob, | dupli_ob->ob, | ||||
| dupli_ob->mat, | dupli_ob->mat, | ||||
| use_object_edit_cage, | edit_mode_type, | ||||
| use_backface_culling, | use_backface_culling, | ||||
| is_object_active, | is_object_active, | ||||
| data); | data); | ||||
| } | } | ||||
| free_object_duplilist(lb); | free_object_duplilist(lb); | ||||
| } | } | ||||
| sob_callback(sctx, | sob_callback(sctx, | ||||
| obj_eval, | obj_eval, | ||||
| obj_eval->obmat, | obj_eval->obmat, | ||||
| use_object_edit_cage, | edit_mode_type, | ||||
| use_backface_culling, | use_backface_culling, | ||||
| is_object_active, | is_object_active, | ||||
| data); | data); | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| Show All 11 Lines | struct RayCastAll_Data { | ||||
| BVHTree_RayCastCallback raycast_callback; | BVHTree_RayCastCallback raycast_callback; | ||||
| const float (*obmat)[4]; | const float (*obmat)[4]; | ||||
| const float (*timat)[3]; | const float (*timat)[3]; | ||||
| float len_diff; | float len_diff; | ||||
| float local_scale; | float local_scale; | ||||
| Object *ob; | Object *ob_eval; | ||||
| uint ob_uuid; | uint ob_uuid; | ||||
| /* output data */ | /* output data */ | ||||
| ListBase *hit_list; | ListBase *hit_list; | ||||
| bool retval; | bool retval; | ||||
| }; | }; | ||||
| static struct SnapObjectHitDepth *hit_depth_create(const float depth, | static struct SnapObjectHitDepth *hit_depth_create(const float depth, | ||||
| const float co[3], | const float co[3], | ||||
| const float no[3], | const float no[3], | ||||
| int index, | int index, | ||||
| Object *ob, | Object *ob_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| uint ob_uuid) | uint ob_uuid) | ||||
| { | { | ||||
| struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__); | struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__); | ||||
| hit->depth = depth; | hit->depth = depth; | ||||
| copy_v3_v3(hit->co, co); | copy_v3_v3(hit->co, co); | ||||
| copy_v3_v3(hit->no, no); | copy_v3_v3(hit->no, no); | ||||
| hit->index = index; | hit->index = index; | ||||
| hit->ob = ob; | hit->ob_eval = ob_eval; | ||||
| copy_m4_m4(hit->obmat, (float(*)[4])obmat); | copy_m4_m4(hit->obmat, (float(*)[4])obmat); | ||||
| hit->ob_uuid = ob_uuid; | hit->ob_uuid = ob_uuid; | ||||
| return hit; | return hit; | ||||
| } | } | ||||
| static int hit_depth_cmp(const void *arg1, const void *arg2) | static int hit_depth_cmp(const void *arg1, const void *arg2) | ||||
| { | { | ||||
| Show All 25 Lines | if (hit->index != -1) { | ||||
| depth = (hit->dist + data->len_diff) / data->local_scale; | depth = (hit->dist + data->len_diff) / data->local_scale; | ||||
| /* worldspace normal */ | /* worldspace normal */ | ||||
| copy_v3_v3(normal, hit->no); | copy_v3_v3(normal, hit->no); | ||||
| mul_m3_v3((float(*)[3])data->timat, normal); | mul_m3_v3((float(*)[3])data->timat, normal); | ||||
| normalize_v3(normal); | normalize_v3(normal); | ||||
| struct SnapObjectHitDepth *hit_item = hit_depth_create( | struct SnapObjectHitDepth *hit_item = hit_depth_create( | ||||
| depth, location, normal, hit->index, data->ob, data->obmat, data->ob_uuid); | depth, location, normal, hit->index, data->ob_eval, data->obmat, data->ob_uuid); | ||||
| BLI_addtail(data->hit_list, hit_item); | BLI_addtail(data->hit_list, hit_item); | ||||
| } | } | ||||
| } | } | ||||
| static bool raycast_tri_backface_culling_test( | static bool raycast_tri_backface_culling_test( | ||||
| const float dir[3], const float v0[3], const float v1[3], const float v2[3], float no[3]) | const float dir[3], const float v0[3], const float v1[3], const float v2[3], float no[3]) | ||||
| { | { | ||||
| cross_tri_v3(no, v0, v1, v2); | cross_tri_v3(no, v0, v1, v2); | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | if (dist >= 0 && dist < hit->dist) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static bool raycastMesh(SnapObjectContext *sctx, | static bool raycastMesh(SnapObjectContext *sctx, | ||||
| const float ray_start[3], | const float ray_start[3], | ||||
| const float ray_dir[3], | const float ray_dir[3], | ||||
| Object *ob, | Object *ob_eval, | ||||
| Mesh *me, | Mesh *me_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| const uint ob_index, | const uint ob_index, | ||||
| bool use_hide, | bool use_hide, | ||||
| bool use_backface_culling, | bool use_backface_culling, | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *ray_depth, | float *ray_depth, | ||||
| /* return args */ | /* return args */ | ||||
| float r_loc[3], | float r_loc[3], | ||||
| float r_no[3], | float r_no[3], | ||||
| int *r_index, | int *r_index, | ||||
| ListBase *r_hit_list) | ListBase *r_hit_list) | ||||
| { | { | ||||
| bool retval = false; | bool retval = false; | ||||
| if (me->totpoly == 0) { | if (me_eval->totpoly == 0) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| float imat[4][4]; | float imat[4][4]; | ||||
| float ray_start_local[3], ray_normal_local[3]; | float ray_start_local[3], ray_normal_local[3]; | ||||
| float local_scale, local_depth, len_diff = 0.0f; | float local_scale, local_depth, len_diff = 0.0f; | ||||
| invert_m4_m4(imat, obmat); | invert_m4_m4(imat, obmat); | ||||
| copy_v3_v3(ray_start_local, ray_start); | copy_v3_v3(ray_start_local, ray_start); | ||||
| copy_v3_v3(ray_normal_local, ray_dir); | copy_v3_v3(ray_normal_local, ray_dir); | ||||
| mul_m4_v3(imat, ray_start_local); | mul_m4_v3(imat, ray_start_local); | ||||
| mul_mat3_m4_v3(imat, ray_normal_local); | mul_mat3_m4_v3(imat, ray_normal_local); | ||||
| /* local scale in normal direction */ | /* local scale in normal direction */ | ||||
| local_scale = normalize_v3(ray_normal_local); | local_scale = normalize_v3(ray_normal_local); | ||||
| local_depth = *ray_depth; | local_depth = *ray_depth; | ||||
| if (local_depth != BVH_RAYCAST_DIST_MAX) { | if (local_depth != BVH_RAYCAST_DIST_MAX) { | ||||
| local_depth *= local_scale; | local_depth *= local_scale; | ||||
| } | } | ||||
| /* Test BoundBox */ | /* Test BoundBox */ | ||||
| BoundBox *bb = BKE_mesh_boundbox_get(ob); | BoundBox *bb = BKE_mesh_boundbox_get(ob_eval); | ||||
| if (bb) { | if (bb) { | ||||
| /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ | /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ | ||||
| if (!isect_ray_aabb_v3_simple( | if (!isect_ray_aabb_v3_simple( | ||||
| ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, NULL)) { | ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, NULL)) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| } | } | ||||
| /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with | /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with | ||||
| * very far away ray_start values (as returned in case of ortho view3d), see T50486, T38358. | * very far away ray_start values (as returned in case of ortho view3d), see T50486, T38358. | ||||
| */ | */ | ||||
| if (len_diff > 400.0f) { | if (len_diff > 400.0f) { | ||||
| len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ | len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ | ||||
| madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff); | madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff); | ||||
| local_depth -= len_diff; | local_depth -= len_diff; | ||||
| } | } | ||||
| else { | else { | ||||
| len_diff = 0.0f; | len_diff = 0.0f; | ||||
| } | } | ||||
| SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob); | SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide); | ||||
| BVHTreeFromMesh *treedata = &sod->treedata_mesh; | BVHTreeFromMesh *treedata = &sod->treedata_mesh; | ||||
| /* The tree is owned by the Mesh and may have been freed since we last used. */ | |||||
| if (treedata->tree) { | |||||
| BLI_assert(treedata->cached); | |||||
| if (!bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) { | |||||
| free_bvhtree_from_mesh(treedata); | |||||
| } | |||||
| else { | |||||
| /* Update Pointers. */ | |||||
| if (treedata->vert && treedata->vert_allocated == false) { | |||||
| treedata->vert = me->mvert; | |||||
| } | |||||
| if (treedata->loop && treedata->loop_allocated == false) { | |||||
| treedata->loop = me->mloop; | |||||
| } | |||||
| if (treedata->looptri && treedata->looptri_allocated == false) { | |||||
| treedata->looptri = BKE_mesh_runtime_looptri_ensure(me); | |||||
| } | |||||
| /* required for snapping with occlusion. */ | |||||
| treedata->edge = me->medge; | |||||
| sod->poly = me->mpoly; | |||||
| } | |||||
| } | |||||
| if (treedata->tree == NULL) { | |||||
| if (use_hide) { | |||||
| BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI_NO_HIDDEN, 4); | |||||
| } | |||||
| else { | |||||
| BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4); | |||||
| } | |||||
| /* required for snapping with occlusion. */ | |||||
| treedata->edge = me->medge; | |||||
| sod->poly = me->mpoly; | |||||
| if (treedata->tree == NULL) { | if (treedata->tree == NULL) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| } | |||||
| float timat[3][3]; /* transpose inverse matrix for normals */ | float timat[3][3]; /* transpose inverse matrix for normals */ | ||||
| transpose_m3_m4(timat, imat); | transpose_m3_m4(timat, imat); | ||||
| BLI_assert(treedata->raycast_callback != NULL); | |||||
| if (r_hit_list) { | if (r_hit_list) { | ||||
| struct RayCastAll_Data data; | struct RayCastAll_Data data; | ||||
| data.bvhdata = treedata; | data.bvhdata = treedata; | ||||
| data.raycast_callback = treedata->raycast_callback; | data.raycast_callback = treedata->raycast_callback; | ||||
| data.obmat = obmat; | data.obmat = obmat; | ||||
| data.timat = timat; | data.timat = timat; | ||||
| data.len_diff = len_diff; | data.len_diff = len_diff; | ||||
| data.local_scale = local_scale; | data.local_scale = local_scale; | ||||
| data.ob = ob; | data.ob_eval = ob_eval; | ||||
| data.ob_uuid = ob_index; | data.ob_uuid = ob_index; | ||||
| data.hit_list = r_hit_list; | data.hit_list = r_hit_list; | ||||
| data.retval = retval; | data.retval = retval; | ||||
| BLI_bvhtree_ray_cast_all(treedata->tree, | BLI_bvhtree_ray_cast_all(treedata->tree, | ||||
| ray_start_local, | ray_start_local, | ||||
| ray_normal_local, | ray_normal_local, | ||||
| 0.0f, | 0.0f, | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | static bool raycastMesh(SnapObjectContext *sctx, | ||||
| } | } | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| static bool raycastEditMesh(SnapObjectContext *sctx, | static bool raycastEditMesh(SnapObjectContext *sctx, | ||||
| const float ray_start[3], | const float ray_start[3], | ||||
| const float ray_dir[3], | const float ray_dir[3], | ||||
| Object *ob, | Object *ob_eval, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| const uint ob_index, | const uint ob_index, | ||||
| bool use_backface_culling, | bool use_backface_culling, | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *ray_depth, | float *ray_depth, | ||||
| /* return args */ | /* return args */ | ||||
| float r_loc[3], | float r_loc[3], | ||||
| Show All 20 Lines | static bool raycastEditMesh(SnapObjectContext *sctx, | ||||
| /* local scale in normal direction */ | /* local scale in normal direction */ | ||||
| local_scale = normalize_v3(ray_normal_local); | local_scale = normalize_v3(ray_normal_local); | ||||
| local_depth = *ray_depth; | local_depth = *ray_depth; | ||||
| if (local_depth != BVH_RAYCAST_DIST_MAX) { | if (local_depth != BVH_RAYCAST_DIST_MAX) { | ||||
| local_depth *= local_scale; | local_depth *= local_scale; | ||||
| } | } | ||||
| SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em); | SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob_eval, em); | ||||
| /* Test BoundBox */ | /* Test BoundBox */ | ||||
| /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ | /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ | ||||
| if (!isect_ray_aabb_v3_simple( | if (!isect_ray_aabb_v3_simple( | ||||
| ray_start_local, ray_normal_local, sod->min, sod->max, &len_diff, NULL)) { | ray_start_local, ray_normal_local, sod->min, sod->max, &len_diff, NULL)) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| Show All 9 Lines | static bool raycastEditMesh(SnapObjectContext *sctx, | ||||
| else { | else { | ||||
| len_diff = 0.0f; | len_diff = 0.0f; | ||||
| } | } | ||||
| BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh; | BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh; | ||||
| if (treedata->tree == NULL) { | if (treedata->tree == NULL) { | ||||
| /* Operators only update the editmesh looptris of the original mesh. */ | /* Operators only update the editmesh looptris of the original mesh. */ | ||||
| BLI_assert(sod->treedata_editmesh.em == BKE_editmesh_from_object(DEG_get_original_object(ob))); | BLI_assert(sod->treedata_editmesh.em == | ||||
| BKE_editmesh_from_object(DEG_get_original_object(ob_eval))); | |||||
| em = sod->treedata_editmesh.em; | em = sod->treedata_editmesh.em; | ||||
| if (sctx->callbacks.edit_mesh.test_face_fn) { | if (sctx->callbacks.edit_mesh.test_face_fn) { | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri); | BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri); | ||||
| BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__); | BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__); | ||||
| int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( | int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( | ||||
| Show All 30 Lines | if (r_hit_list) { | ||||
| struct RayCastAll_Data data; | struct RayCastAll_Data data; | ||||
| data.bvhdata = treedata; | data.bvhdata = treedata; | ||||
| data.raycast_callback = treedata->raycast_callback; | data.raycast_callback = treedata->raycast_callback; | ||||
| data.obmat = obmat; | data.obmat = obmat; | ||||
| data.timat = timat; | data.timat = timat; | ||||
| data.len_diff = len_diff; | data.len_diff = len_diff; | ||||
| data.local_scale = local_scale; | data.local_scale = local_scale; | ||||
| data.ob = ob; | data.ob_eval = ob_eval; | ||||
| data.ob_uuid = ob_index; | data.ob_uuid = ob_index; | ||||
| data.hit_list = r_hit_list; | data.hit_list = r_hit_list; | ||||
| data.retval = retval; | data.retval = retval; | ||||
| BLI_bvhtree_ray_cast_all(treedata->tree, | BLI_bvhtree_ray_cast_all(treedata->tree, | ||||
| ray_start_local, | ray_start_local, | ||||
| ray_normal_local, | ray_normal_local, | ||||
| 0.0f, | 0.0f, | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
| }; | }; | ||||
| /** | /** | ||||
| * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; | * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; | ||||
| * | * | ||||
| * \note Duplicate args here are documented at #snapObjectsRay | * \note Duplicate args here are documented at #snapObjectsRay | ||||
| */ | */ | ||||
| static void raycast_obj_fn(SnapObjectContext *sctx, | static void raycast_obj_fn(SnapObjectContext *sctx, | ||||
| Object *ob, | Object *ob_eval, | ||||
| float obmat[4][4], | float obmat[4][4], | ||||
| bool use_obedit, | eSnapEditType edit_mode_type, | ||||
| bool use_backface_culling, | bool use_backface_culling, | ||||
| bool is_object_active, | bool is_object_active, | ||||
| void *data) | void *data) | ||||
| { | { | ||||
| struct RaycastObjUserData *dt = data; | struct RaycastObjUserData *dt = data; | ||||
| const uint ob_index = dt->ob_index++; | const uint ob_index = dt->ob_index++; | ||||
| bool use_occlusion_test = dt->use_occlusion_test; | bool use_occlusion_test = dt->use_occlusion_test; | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *ray_depth = dt->ray_depth; | float *ray_depth = dt->ray_depth; | ||||
| bool retval = false; | bool retval = false; | ||||
| if (use_occlusion_test) { | if (use_occlusion_test) { | ||||
| if (use_obedit && sctx->use_v3d && XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) { | if ((edit_mode_type == SNAP_GEOM_EDIT) && sctx->use_v3d && | ||||
| XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) { | |||||
| /* Use of occlude geometry in editing mode disabled. */ | /* Use of occlude geometry in editing mode disabled. */ | ||||
| return; | return; | ||||
| } | } | ||||
| if (ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE)) { | if (ELEM(ob_eval->dt, OB_BOUNDBOX, OB_WIRE)) { | ||||
| /* Do not hit objects that are in wire or bounding box | /* Do not hit objects that are in wire or bounding box | ||||
| * display mode. */ | * display mode. */ | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| switch (ob->type) { | switch (ob_eval->type) { | ||||
| case OB_MESH: { | case OB_MESH: { | ||||
| Mesh *me = ob->data; | |||||
| bool use_hide = false; | bool use_hide = false; | ||||
| if (BKE_object_is_in_editmode(ob)) { | Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); | ||||
| if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) { | if (me_eval == NULL) { | ||||
| /* Operators only update the editmesh looptris of the original mesh. */ | /* Operators only update the editmesh looptris of the original mesh. */ | ||||
| BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); | BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval)); | ||||
| retval = raycastEditMesh(sctx, | retval = raycastEditMesh(sctx, | ||||
| dt->ray_start, | dt->ray_start, | ||||
| dt->ray_dir, | dt->ray_dir, | ||||
| ob, | ob_eval, | ||||
| em_orig, | em_orig, | ||||
| obmat, | obmat, | ||||
| ob_index, | ob_index, | ||||
| use_backface_culling, | use_backface_culling, | ||||
| ray_depth, | ray_depth, | ||||
| dt->r_loc, | dt->r_loc, | ||||
| dt->r_no, | dt->r_no, | ||||
| dt->r_index, | dt->r_index, | ||||
| dt->r_hit_list); | dt->r_hit_list); | ||||
| break; | break; | ||||
| } | } | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | |||||
| if (em->mesh_eval_final) { | |||||
| me = em->mesh_eval_final; | |||||
| use_hide = true; | |||||
| } | |||||
| } | |||||
| retval = raycastMesh(sctx, | retval = raycastMesh(sctx, | ||||
| dt->ray_start, | dt->ray_start, | ||||
| dt->ray_dir, | dt->ray_dir, | ||||
| ob, | ob_eval, | ||||
| me, | me_eval, | ||||
| obmat, | obmat, | ||||
| ob_index, | ob_index, | ||||
| use_hide, | use_hide, | ||||
| use_backface_culling, | use_backface_culling, | ||||
| ray_depth, | ray_depth, | ||||
| dt->r_loc, | dt->r_loc, | ||||
| dt->r_no, | dt->r_no, | ||||
| dt->r_index, | dt->r_index, | ||||
| dt->r_hit_list); | dt->r_hit_list); | ||||
| break; | break; | ||||
| } | } | ||||
| case OB_CURVE: | case OB_CURVE: | ||||
| case OB_SURF: | case OB_SURF: | ||||
| case OB_FONT: { | case OB_FONT: { | ||||
| if (!is_object_active) { | if (!is_object_active) { | ||||
| Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); | Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); | ||||
| if (mesh_eval) { | if (mesh_eval) { | ||||
| retval = raycastMesh(sctx, | retval = raycastMesh(sctx, | ||||
| dt->ray_start, | dt->ray_start, | ||||
| dt->ray_dir, | dt->ray_dir, | ||||
| ob, | ob_eval, | ||||
| mesh_eval, | mesh_eval, | ||||
| obmat, | obmat, | ||||
| ob_index, | ob_index, | ||||
| false, | false, | ||||
| use_backface_culling, | use_backface_culling, | ||||
| ray_depth, | ray_depth, | ||||
| dt->r_loc, | dt->r_loc, | ||||
| dt->r_no, | dt->r_no, | ||||
| dt->r_index, | dt->r_index, | ||||
| dt->r_hit_list); | dt->r_hit_list); | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (retval) { | if (retval) { | ||||
| if (dt->r_ob) { | if (dt->r_ob) { | ||||
| *dt->r_ob = ob; | *dt->r_ob = ob_eval; | ||||
| } | } | ||||
| if (dt->r_obmat) { | if (dt->r_obmat) { | ||||
| copy_m4_m4(dt->r_obmat, obmat); | copy_m4_m4(dt->r_obmat, obmat); | ||||
| } | } | ||||
| dt->ret = true; | dt->ret = true; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 238 Lines • ▼ Show 20 Lines | typedef struct Nearest2dUserData { | ||||
| Nearest2DGetTriVertsCallback get_tri_verts_index; | Nearest2DGetTriVertsCallback get_tri_verts_index; | ||||
| Nearest2DGetTriEdgesCallback get_tri_edges_index; | Nearest2DGetTriEdgesCallback get_tri_edges_index; | ||||
| Nearest2DCopyVertNoCallback copy_vert_no; | Nearest2DCopyVertNoCallback copy_vert_no; | ||||
| bool is_persp; | bool is_persp; | ||||
| bool use_backface_culling; | bool use_backface_culling; | ||||
| } Nearest2dUserData; | } Nearest2dUserData; | ||||
| static void nearest2d_data_init(SnapObjectData *sod, | |||||
| bool is_persp, | |||||
| bool use_backface_culling, | |||||
| Nearest2dUserData *r_nearest2d) | |||||
| { | |||||
| if (sod->type == SNAP_MESH) { | |||||
| r_nearest2d->userdata = &sod->treedata_mesh; | |||||
| r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get; | |||||
| r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get; | |||||
| r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy; | |||||
| r_nearest2d->get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get; | |||||
| r_nearest2d->get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get; | |||||
| } | |||||
| else { | |||||
| BLI_assert(sod->type == SNAP_EDIT_MESH); | |||||
| r_nearest2d->userdata = sod->treedata_editmesh.em; | |||||
| r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get; | |||||
| r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get; | |||||
| r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy; | |||||
| r_nearest2d->get_tri_verts_index = NULL; | |||||
| r_nearest2d->get_tri_edges_index = NULL; | |||||
| } | |||||
| r_nearest2d->is_persp = is_persp; | |||||
| r_nearest2d->use_backface_culling = use_backface_culling; | |||||
| } | |||||
| static void cb_snap_vert(void *userdata, | static void cb_snap_vert(void *userdata, | ||||
| int index, | int index, | ||||
| const struct DistProjectedAABBPrecalc *precalc, | const struct DistProjectedAABBPrecalc *precalc, | ||||
| const float (*clip_plane)[4], | const float (*clip_plane)[4], | ||||
| const int clip_plane_len, | const int clip_plane_len, | ||||
| BVHTreeNearest *nearest) | BVHTreeNearest *nearest) | ||||
| { | { | ||||
| struct Nearest2dUserData *data = userdata; | struct Nearest2dUserData *data = userdata; | ||||
| ▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Internal Object Snapping API | /** \name Internal Object Snapping API | ||||
| * \{ */ | * \{ */ | ||||
| static short snap_mesh_polygon(SnapObjectContext *sctx, | static short snap_mesh_polygon(SnapObjectContext *sctx, | ||||
| SnapData *snapdata, | SnapData *snapdata, | ||||
| Object *ob, | Object *ob_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| bool use_backface_culling, | bool use_backface_culling, | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *dist_px, | float *dist_px, | ||||
| /* return args */ | /* return args */ | ||||
| float r_loc[3], | float r_loc[3], | ||||
| float r_no[3], | float r_no[3], | ||||
| int *r_index) | int *r_index) | ||||
| { | { | ||||
| short elem = 0; | short elem = 0; | ||||
| float lpmat[4][4]; | float lpmat[4][4]; | ||||
| mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | ||||
| struct DistProjectedAABBPrecalc neasrest_precalc; | struct DistProjectedAABBPrecalc neasrest_precalc; | ||||
| dist_squared_to_projected_aabb_precalc( | dist_squared_to_projected_aabb_precalc( | ||||
| &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); | &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); | ||||
| float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; | float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; | ||||
| transpose_m4_m4(tobmat, obmat); | transpose_m4_m4(tobmat, obmat); | ||||
| for (int i = snapdata->clip_plane_len; i--;) { | for (int i = snapdata->clip_plane_len; i--;) { | ||||
| mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); | mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); | ||||
| } | } | ||||
| Nearest2dUserData nearest2d = { | |||||
| .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, | |||||
| .use_backface_culling = use_backface_culling, | |||||
| }; | |||||
| BVHTreeNearest nearest = { | BVHTreeNearest nearest = { | ||||
| .index = -1, | .index = -1, | ||||
| .dist_sq = square_f(*dist_px), | .dist_sq = square_f(*dist_px), | ||||
| }; | }; | ||||
| SnapObjectData *sod = snap_object_data_lookup(sctx, ob); | SnapObjectData *sod = snap_object_data_lookup(sctx, ob_eval); | ||||
| BLI_assert(sod != NULL); | BLI_assert(sod != NULL); | ||||
| Nearest2dUserData nearest2d; | |||||
| nearest2d_data_init( | |||||
| sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); | |||||
| if (sod->type == SNAP_MESH) { | if (sod->type == SNAP_MESH) { | ||||
| BVHTreeFromMesh *treedata = &sod->treedata_mesh; | BVHTreeFromMesh *treedata = &sod->treedata_mesh; | ||||
| nearest2d.userdata = treedata; | |||||
| nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get; | |||||
| nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get; | |||||
| nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy; | |||||
| const MPoly *mp = &sod->poly[*r_index]; | const MPoly *mp = &sod->poly[*r_index]; | ||||
| const MLoop *ml = &treedata->loop[mp->loopstart]; | const MLoop *ml = &treedata->loop[mp->loopstart]; | ||||
| if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) { | if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) { | ||||
| elem = SCE_SNAP_MODE_EDGE; | elem = SCE_SNAP_MODE_EDGE; | ||||
| BLI_assert(treedata->edge != NULL); | BLI_assert(treedata->edge != NULL); | ||||
| for (int i = mp->totloop; i--; ml++) { | for (int i = mp->totloop; i--; ml++) { | ||||
| cb_snap_edge(&nearest2d, | cb_snap_edge(&nearest2d, | ||||
| ml->e, | ml->e, | ||||
| Show All 14 Lines | else { | ||||
| &nearest); | &nearest); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_assert(sod->type == SNAP_EDIT_MESH); | BLI_assert(sod->type == SNAP_EDIT_MESH); | ||||
| BMEditMesh *em = sod->treedata_editmesh.em; | BMEditMesh *em = sod->treedata_editmesh.em; | ||||
| nearest2d.userdata = em; | |||||
| nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get; | |||||
| nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get; | |||||
| nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy; | |||||
| BM_mesh_elem_table_ensure(em->bm, BM_FACE); | BM_mesh_elem_table_ensure(em->bm, BM_FACE); | ||||
| BMFace *f = BM_face_at_index(em->bm, *r_index); | BMFace *f = BM_face_at_index(em->bm, *r_index); | ||||
| BMLoop *l_iter, *l_first; | BMLoop *l_iter, *l_first; | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) { | if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) { | ||||
| elem = SCE_SNAP_MODE_EDGE; | elem = SCE_SNAP_MODE_EDGE; | ||||
| BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_EDGE); | BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_EDGE); | ||||
| BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE); | BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE); | ||||
| Show All 40 Lines | if (nearest.index != -1) { | ||||
| return elem; | return elem; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, | static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, | ||||
| SnapData *snapdata, | SnapData *snapdata, | ||||
| Object *ob, | Object *ob_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| float original_dist_px, | float original_dist_px, | ||||
| const float prev_co[3], | const float prev_co[3], | ||||
| bool use_backface_culling, | bool use_backface_culling, | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *dist_px, | float *dist_px, | ||||
| /* return args */ | /* return args */ | ||||
| float r_loc[3], | float r_loc[3], | ||||
| float r_no[3], | float r_no[3], | ||||
| int *r_index) | int *r_index) | ||||
| { | { | ||||
| short elem = SCE_SNAP_MODE_EDGE; | short elem = SCE_SNAP_MODE_EDGE; | ||||
| if (ob->type != OB_MESH) { | if (ob_eval->type != OB_MESH) { | ||||
| return elem; | return elem; | ||||
| } | } | ||||
| SnapObjectData *sod = snap_object_data_lookup(sctx, ob); | SnapObjectData *sod = snap_object_data_lookup(sctx, ob_eval); | ||||
| BLI_assert(sod != NULL); | BLI_assert(sod != NULL); | ||||
| Nearest2dUserData nearest2d; | Nearest2dUserData nearest2d; | ||||
| { | nearest2d_data_init( | ||||
| nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; | sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); | ||||
| nearest2d.use_backface_culling = use_backface_culling; | |||||
| if (sod->type == SNAP_MESH) { | |||||
| nearest2d.userdata = &sod->treedata_mesh; | |||||
| nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get; | |||||
| nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get; | |||||
| nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy; | |||||
| } | |||||
| else { | |||||
| BLI_assert(sod->type == SNAP_EDIT_MESH); | |||||
| nearest2d.userdata = sod->treedata_editmesh.em; | |||||
| nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get; | |||||
| nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get; | |||||
| nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy; | |||||
| } | |||||
| } | |||||
| int vindex[2]; | int vindex[2]; | ||||
| nearest2d.get_edge_verts_index(*r_index, vindex, nearest2d.userdata); | nearest2d.get_edge_verts_index(*r_index, vindex, nearest2d.userdata); | ||||
| const float *v_pair[2]; | const float *v_pair[2]; | ||||
| nearest2d.get_vert_co(vindex[0], &v_pair[0], nearest2d.userdata); | nearest2d.get_vert_co(vindex[0], &v_pair[0], nearest2d.userdata); | ||||
| nearest2d.get_vert_co(vindex[1], &v_pair[1], nearest2d.userdata); | nearest2d.get_vert_co(vindex[1], &v_pair[1], nearest2d.userdata); | ||||
| ▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | if (nearest.index != -1) { | ||||
| *r_index = nearest.index; | *r_index = nearest.index; | ||||
| } | } | ||||
| return elem; | return elem; | ||||
| } | } | ||||
| static short snapArmature(SnapData *snapdata, | static short snapArmature(SnapData *snapdata, | ||||
| Object *ob, | Object *ob_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| bool use_obedit, | |||||
| /* read/write args */ | /* read/write args */ | ||||
| float *dist_px, | float *dist_px, | ||||
| /* return args */ | /* return args */ | ||||
| float r_loc[3], | float r_loc[3], | ||||
| float *UNUSED(r_no), | float *UNUSED(r_no), | ||||
| int *r_index) | int *r_index) | ||||
| { | { | ||||
| short retval = 0; | short retval = 0; | ||||
| if (snapdata->snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */ | if (snapdata->snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */ | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| float lpmat[4][4], dist_px_sq = square_f(*dist_px); | float lpmat[4][4], dist_px_sq = square_f(*dist_px); | ||||
| mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | ||||
| struct DistProjectedAABBPrecalc neasrest_precalc; | struct DistProjectedAABBPrecalc neasrest_precalc; | ||||
| dist_squared_to_projected_aabb_precalc( | dist_squared_to_projected_aabb_precalc( | ||||
| &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); | &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); | ||||
| use_obedit = use_obedit && BKE_object_is_in_editmode(ob); | bool use_obedit = ((bArmature *)ob_eval->data)->edbo != NULL; | ||||
| if (use_obedit == false) { | if (use_obedit == false) { | ||||
| /* Test BoundBox */ | /* Test BoundBox */ | ||||
| BoundBox *bb = BKE_armature_boundbox_get(ob); | BoundBox *bb = BKE_armature_boundbox_get(ob_eval); | ||||
| if (bb && !snap_bound_box_check_dist( | if (bb && !snap_bound_box_check_dist( | ||||
| bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { | bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| } | } | ||||
| float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; | float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; | ||||
| transpose_m4_m4(tobmat, obmat); | transpose_m4_m4(tobmat, obmat); | ||||
| for (int i = snapdata->clip_plane_len; i--;) { | for (int i = snapdata->clip_plane_len; i--;) { | ||||
| mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); | mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); | ||||
| } | } | ||||
| bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; | bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; | ||||
| bArmature *arm = ob->data; | bArmature *arm = ob_eval->data; | ||||
| if (arm->edbo) { | if (arm->edbo) { | ||||
| LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) { | LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) { | ||||
| if (eBone->layer & arm->layer) { | if (eBone->layer & arm->layer) { | ||||
| /* skip hidden or moving (selected) bones */ | /* skip hidden or moving (selected) bones */ | ||||
| if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) { | if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) { | ||||
| bool has_vert_snap = false; | bool has_vert_snap = false; | ||||
| if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { | if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { | ||||
| Show All 27 Lines | LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) { | ||||
| r_loc)) { | r_loc)) { | ||||
| retval = SCE_SNAP_MODE_EDGE; | retval = SCE_SNAP_MODE_EDGE; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (ob->pose && ob->pose->chanbase.first) { | else if (ob_eval->pose && ob_eval->pose->chanbase.first) { | ||||
| LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { | LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_eval->pose->chanbase) { | ||||
| Bone *bone = pchan->bone; | Bone *bone = pchan->bone; | ||||
| /* skip hidden bones */ | /* skip hidden bones */ | ||||
| if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { | if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { | ||||
| bool has_vert_snap = false; | bool has_vert_snap = false; | ||||
| const float *head_vec = pchan->pose_head; | const float *head_vec = pchan->pose_head; | ||||
| const float *tail_vec = pchan->pose_tail; | const float *tail_vec = pchan->pose_tail; | ||||
| if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { | if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (retval) { | ||||
| } | } | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static short snapCurve(SnapData *snapdata, | static short snapCurve(SnapData *snapdata, | ||||
| Object *ob, | Object *ob_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| bool use_obedit, | bool use_obedit, | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *dist_px, | float *dist_px, | ||||
| /* return args */ | /* return args */ | ||||
| float r_loc[3], | float r_loc[3], | ||||
| float *UNUSED(r_no), | float *UNUSED(r_no), | ||||
| int *r_index) | int *r_index) | ||||
| { | { | ||||
| bool has_snap = false; | bool has_snap = false; | ||||
| /* only vertex snapping mode (eg control points and handles) supported for now) */ | /* only vertex snapping mode (eg control points and handles) supported for now) */ | ||||
| if ((snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) { | if ((snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| Curve *cu = ob->data; | Curve *cu = ob_eval->data; | ||||
| float dist_px_sq = square_f(*dist_px); | float dist_px_sq = square_f(*dist_px); | ||||
| float lpmat[4][4]; | float lpmat[4][4]; | ||||
| mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | ||||
| struct DistProjectedAABBPrecalc neasrest_precalc; | struct DistProjectedAABBPrecalc neasrest_precalc; | ||||
| dist_squared_to_projected_aabb_precalc( | dist_squared_to_projected_aabb_precalc( | ||||
| &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); | &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); | ||||
| use_obedit = use_obedit && BKE_object_is_in_editmode(ob); | use_obedit = use_obedit && BKE_object_is_in_editmode(ob_eval); | ||||
| if (use_obedit == false) { | if (use_obedit == false) { | ||||
| /* Test BoundBox */ | /* Test BoundBox */ | ||||
| BoundBox *bb = BKE_curve_boundbox_get(ob); | BoundBox *bb = BKE_curve_boundbox_get(ob_eval); | ||||
| if (bb && !snap_bound_box_check_dist( | if (bb && !snap_bound_box_check_dist( | ||||
| bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { | bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| float tobmat[4][4]; | float tobmat[4][4]; | ||||
| transpose_m4_m4(tobmat, obmat); | transpose_m4_m4(tobmat, obmat); | ||||
| ▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | if (has_snap) { | ||||
| return SCE_SNAP_MODE_VERTEX; | return SCE_SNAP_MODE_VERTEX; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* may extend later (for now just snaps to empty center) */ | /* may extend later (for now just snaps to empty center) */ | ||||
| static short snap_object_center(SnapData *snapdata, | static short snap_object_center(SnapData *snapdata, | ||||
| Object *ob, | Object *ob_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *dist_px, | float *dist_px, | ||||
| /* return args */ | /* return args */ | ||||
| float r_loc[3], | float r_loc[3], | ||||
| float *UNUSED(r_no), | float *UNUSED(r_no), | ||||
| int *r_index) | int *r_index) | ||||
| { | { | ||||
| short retval = 0; | short retval = 0; | ||||
| if (ob->transflag & OB_DUPLI) { | if (ob_eval->transflag & OB_DUPLI) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| /* for now only vertex supported */ | /* for now only vertex supported */ | ||||
| if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { | if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { | ||||
| struct DistProjectedAABBPrecalc neasrest_precalc; | struct DistProjectedAABBPrecalc neasrest_precalc; | ||||
| dist_squared_to_projected_aabb_precalc( | dist_squared_to_projected_aabb_precalc( | ||||
| &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval); | &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval); | ||||
| ▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | if (retval) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static short snapMesh(SnapObjectContext *sctx, | static short snapMesh(SnapObjectContext *sctx, | ||||
| SnapData *snapdata, | SnapData *snapdata, | ||||
| Object *ob, | Object *ob_eval, | ||||
| Mesh *me, | Mesh *me_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| bool use_hide, | |||||
| bool use_backface_culling, | bool use_backface_culling, | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *dist_px, | float *dist_px, | ||||
| /* return args */ | /* return args */ | ||||
| float r_loc[3], | float r_loc[3], | ||||
| float r_no[3], | float r_no[3], | ||||
| int *r_index) | int *r_index) | ||||
| { | { | ||||
| BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE); | BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE); | ||||
| if (me_eval->totvert == 0) { | |||||
| if ((snapdata->snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) { | |||||
| if (me->totvert == 0) { | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | if (me_eval->totedge == 0 && !(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) { | ||||
| else { | |||||
| if (me->totedge == 0) { | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | |||||
| float lpmat[4][4]; | float lpmat[4][4]; | ||||
| mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | ||||
| float dist_px_sq = square_f(*dist_px); | float dist_px_sq = square_f(*dist_px); | ||||
| /* Test BoundBox */ | /* Test BoundBox */ | ||||
| BoundBox *bb = BKE_mesh_boundbox_get(ob); | BoundBox *bb = BKE_mesh_boundbox_get(ob_eval); | ||||
| if (bb && !snap_bound_box_check_dist( | if (bb && !snap_bound_box_check_dist( | ||||
| bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { | bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob); | SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide); | ||||
| BVHTreeFromMesh *treedata, dummy_treedata; | BVHTreeFromMesh *treedata, treedata_tmp; | ||||
| treedata = &sod->treedata_mesh; | treedata = &sod->treedata_mesh; | ||||
| /* The tree is owned by the Mesh and may have been freed since we last used! */ | |||||
| if (treedata->cached && treedata->tree && | |||||
| !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) { | |||||
| free_bvhtree_from_mesh(treedata); | |||||
| } | |||||
| if (sod->cached[0] && sod->bvhtree[0] && | |||||
| !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[0])) { | |||||
| sod->bvhtree[0] = NULL; | |||||
| } | |||||
| if (sod->cached[1] && sod->bvhtree[1] && | |||||
| !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[1])) { | |||||
| sod->bvhtree[1] = NULL; | |||||
| } | |||||
| if (sod->has_looptris && treedata->tree == NULL) { | |||||
| BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4); | |||||
| sod->has_looptris = (treedata->tree != NULL); | |||||
| if (sod->has_looptris) { | |||||
| /* Make sure that the array of edges is referenced in the callbacks. */ | |||||
| treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */ | |||||
| } | |||||
| } | |||||
| if (sod->has_loose_edge && sod->bvhtree[0] == NULL) { | if (sod->has_loose_edge && sod->bvhtree[0] == NULL) { | ||||
| sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2); | sod->bvhtree[0] = BKE_bvhtree_from_mesh_get( | ||||
| sod->has_loose_edge = sod->bvhtree[0] != NULL; | &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEEDGES, 2); | ||||
| sod->cached[0] = dummy_treedata.cached; | if (sod->bvhtree[0] == NULL) { | ||||
| sod->has_loose_edge = false; | |||||
| if (sod->has_loose_edge) { | } | ||||
| BLI_assert(treedata->vert_allocated == false); | sod->cached[0] = treedata_tmp.cached; | ||||
| treedata->vert = dummy_treedata.vert; | BLI_assert(!ELEM(true, | ||||
| treedata->vert_allocated = dummy_treedata.vert_allocated; | treedata_tmp.vert_allocated, | ||||
| treedata_tmp.edge_allocated, | |||||
| BLI_assert(treedata->edge_allocated == false); | treedata_tmp.face_allocated, | ||||
| treedata->edge = dummy_treedata.edge; | treedata_tmp.loop_allocated, | ||||
| treedata->edge_allocated = dummy_treedata.edge_allocated; | treedata_tmp.looptri_allocated)); | ||||
| } | |||||
| } | } | ||||
| if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { | if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { | ||||
| if (sod->has_loose_vert && sod->bvhtree[1] == NULL) { | if (sod->has_loose_vert && sod->bvhtree[1] == NULL) { | ||||
| sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2); | sod->bvhtree[1] = BKE_bvhtree_from_mesh_get( | ||||
| sod->has_loose_vert = sod->bvhtree[1] != NULL; | &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEVERTS, 2); | ||||
| sod->cached[1] = dummy_treedata.cached; | if (sod->bvhtree[1] == NULL) { | ||||
| sod->has_loose_vert = false; | |||||
| if (sod->has_loose_vert) { | |||||
| BLI_assert(treedata->vert_allocated == false); | |||||
| treedata->vert = dummy_treedata.vert; | |||||
| treedata->vert_allocated = dummy_treedata.vert_allocated; | |||||
| } | } | ||||
| sod->cached[1] = treedata_tmp.cached; | |||||
| BLI_assert(!ELEM(true, | |||||
| treedata_tmp.vert_allocated, | |||||
| treedata_tmp.edge_allocated, | |||||
| treedata_tmp.face_allocated, | |||||
| treedata_tmp.loop_allocated, | |||||
| treedata_tmp.looptri_allocated)); | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* Not necessary, just to keep the data more consistent. */ | /* Not necessary, just to keep the data more consistent. */ | ||||
| sod->has_loose_vert = false; | sod->has_loose_vert = false; | ||||
| } | } | ||||
| /* Update pointers. */ | Nearest2dUserData nearest2d; | ||||
| if (treedata->vert_allocated == false) { | nearest2d_data_init( | ||||
| treedata->vert = me->mvert; /* CustomData_get_layer(&me->vdata, CD_MVERT);? */ | sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); | ||||
| } | |||||
| if (treedata->tree || sod->bvhtree[0]) { | |||||
| if (treedata->edge_allocated == false) { | |||||
| /* If raycast has been executed before, `treedata->edge` can be NULL. */ | |||||
| treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */ | |||||
| } | |||||
| if (treedata->loop && treedata->loop_allocated == false) { | |||||
| treedata->loop = me->mloop; /* CustomData_get_layer(&me->edata, CD_MLOOP);? */ | |||||
| } | |||||
| if (treedata->looptri && treedata->looptri_allocated == false) { | |||||
| treedata->looptri = BKE_mesh_runtime_looptri_ensure(me); | |||||
| } | |||||
| } | |||||
| Nearest2dUserData nearest2d = { | |||||
| .userdata = treedata, | |||||
| .get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get, | |||||
| .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get, | |||||
| .get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get, | |||||
| .get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get, | |||||
| .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy, | |||||
| .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, | |||||
| .use_backface_culling = use_backface_culling, | |||||
| }; | |||||
| BVHTreeNearest nearest = { | BVHTreeNearest nearest = { | ||||
| .index = -1, | .index = -1, | ||||
| .dist_sq = dist_px_sq, | .dist_sq = dist_px_sq, | ||||
| }; | }; | ||||
| int last_index = nearest.index; | int last_index = nearest.index; | ||||
| short elem = SCE_SNAP_MODE_VERTEX; | short elem = SCE_SNAP_MODE_VERTEX; | ||||
| ▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | if (nearest.index != -1) { | ||||
| return elem; | return elem; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static short snapEditMesh(SnapObjectContext *sctx, | static short snapEditMesh(SnapObjectContext *sctx, | ||||
| SnapData *snapdata, | SnapData *snapdata, | ||||
| Object *ob, | Object *ob_eval, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| bool use_backface_culling, | bool use_backface_culling, | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *dist_px, | float *dist_px, | ||||
| /* return args */ | /* return args */ | ||||
| float r_loc[3], | float r_loc[3], | ||||
| float r_no[3], | float r_no[3], | ||||
| Show All 12 Lines | else { | ||||
| } | } | ||||
| } | } | ||||
| float lpmat[4][4]; | float lpmat[4][4]; | ||||
| mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | mul_m4_m4m4(lpmat, snapdata->pmat, obmat); | ||||
| float dist_px_sq = square_f(*dist_px); | float dist_px_sq = square_f(*dist_px); | ||||
| SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em); | SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob_eval, em); | ||||
| /* Test BoundBox */ | /* Test BoundBox */ | ||||
| /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ | /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ | ||||
| if (!snap_bound_box_check_dist( | if (!snap_bound_box_check_dist( | ||||
| sod->min, sod->max, lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { | sod->min, sod->max, lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (treedata.tree == NULL) { | ||||
| &sod->mesh_runtime->bvh_cache, | &sod->mesh_runtime->bvh_cache, | ||||
| sod->mesh_runtime->eval_mutex); | sod->mesh_runtime->eval_mutex); | ||||
| } | } | ||||
| sod->bvhtree[1] = treedata.tree; | sod->bvhtree[1] = treedata.tree; | ||||
| sod->cached[1] = treedata.cached; | sod->cached[1] = treedata.cached; | ||||
| } | } | ||||
| } | } | ||||
| Nearest2dUserData nearest2d = { | Nearest2dUserData nearest2d; | ||||
| .userdata = em, | nearest2d_data_init( | ||||
| .get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get, | sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); | ||||
| .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get, | |||||
| .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy, | |||||
| .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, | |||||
| .use_backface_culling = use_backface_culling, | |||||
| }; | |||||
| BVHTreeNearest nearest = { | BVHTreeNearest nearest = { | ||||
| .index = -1, | .index = -1, | ||||
| .dist_sq = dist_px_sq, | .dist_sq = dist_px_sq, | ||||
| }; | }; | ||||
| short elem = SCE_SNAP_MODE_VERTEX; | short elem = SCE_SNAP_MODE_VERTEX; | ||||
| float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; | float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; | ||||
| ▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
| }; | }; | ||||
| /** | /** | ||||
| * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; | * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; | ||||
| * | * | ||||
| * \note Duplicate args here are documented at #snapObjectsRay | * \note Duplicate args here are documented at #snapObjectsRay | ||||
| */ | */ | ||||
| static void snap_obj_fn(SnapObjectContext *sctx, | static void snap_obj_fn(SnapObjectContext *sctx, | ||||
| Object *ob, | Object *ob_eval, | ||||
| float obmat[4][4], | float obmat[4][4], | ||||
| bool use_obedit, | eSnapEditType edit_mode_type, | ||||
| bool use_backface_culling, | bool use_backface_culling, | ||||
| bool UNUSED(is_object_active), | bool UNUSED(is_object_active), | ||||
| void *data) | void *data) | ||||
| { | { | ||||
| struct SnapObjUserData *dt = data; | struct SnapObjUserData *dt = data; | ||||
| short retval = 0; | short retval = 0; | ||||
| switch (ob->type) { | switch (ob_eval->type) { | ||||
| case OB_MESH: { | case OB_MESH: { | ||||
| Mesh *me = ob->data; | bool use_hide; | ||||
| if (BKE_object_is_in_editmode(ob)) { | Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); | ||||
| if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) { | if (me_eval == NULL) { | ||||
| /* Operators only update the editmesh looptris of the original mesh. */ | /* Operators only update the editmesh looptris of the original mesh. */ | ||||
| BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); | BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval)); | ||||
| retval = snapEditMesh(sctx, | retval = snapEditMesh(sctx, | ||||
| dt->snapdata, | dt->snapdata, | ||||
| ob, | ob_eval, | ||||
| em_orig, | em_orig, | ||||
| obmat, | obmat, | ||||
| use_backface_culling, | use_backface_culling, | ||||
| dt->dist_px, | dt->dist_px, | ||||
| dt->r_loc, | dt->r_loc, | ||||
| dt->r_no, | dt->r_no, | ||||
| dt->r_index); | dt->r_index); | ||||
| break; | break; | ||||
| } | } | ||||
| if (ob_eval->dt == OB_BOUNDBOX) { | |||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | |||||
| if (em->mesh_eval_final) { | |||||
| me = em->mesh_eval_final; | |||||
| } | |||||
| } | |||||
| else if (ob->dt == OB_BOUNDBOX) { | |||||
| /* Do not snap to objects that are in bounding box display mode */ | /* Do not snap to objects that are in bounding box display mode */ | ||||
| return; | return; | ||||
| } | } | ||||
| retval = snapMesh(sctx, | retval = snapMesh(sctx, | ||||
| dt->snapdata, | dt->snapdata, | ||||
| ob, | ob_eval, | ||||
| me, | me_eval, | ||||
| obmat, | obmat, | ||||
| use_hide, | |||||
| use_backface_culling, | use_backface_culling, | ||||
| dt->dist_px, | dt->dist_px, | ||||
| dt->r_loc, | dt->r_loc, | ||||
| dt->r_no, | dt->r_no, | ||||
| dt->r_index); | dt->r_index); | ||||
| break; | break; | ||||
| } | } | ||||
| case OB_ARMATURE: | case OB_ARMATURE: | ||||
| retval = snapArmature( | retval = snapArmature( | ||||
| dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); | dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); | ||||
| break; | break; | ||||
| case OB_CURVE: | case OB_CURVE: | ||||
| retval = snapCurve( | retval = snapCurve(dt->snapdata, | ||||
| dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); | ob_eval, | ||||
| obmat, | |||||
| edit_mode_type == SNAP_GEOM_EDIT, | |||||
| dt->dist_px, | |||||
| dt->r_loc, | |||||
| dt->r_no, | |||||
| dt->r_index); | |||||
| break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */ | break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */ | ||||
| case OB_SURF: | case OB_SURF: | ||||
| case OB_FONT: { | case OB_FONT: { | ||||
| Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); | Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); | ||||
| if (mesh_eval) { | if (mesh_eval) { | ||||
| retval |= snapMesh(sctx, | retval |= snapMesh(sctx, | ||||
| dt->snapdata, | dt->snapdata, | ||||
| ob, | ob_eval, | ||||
| mesh_eval, | mesh_eval, | ||||
| obmat, | obmat, | ||||
| false, | |||||
| use_backface_culling, | use_backface_culling, | ||||
| dt->dist_px, | dt->dist_px, | ||||
| dt->r_loc, | dt->r_loc, | ||||
| dt->r_no, | dt->r_no, | ||||
| dt->r_index); | dt->r_index); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case OB_EMPTY: | case OB_EMPTY: | ||||
| case OB_GPENCIL: | case OB_GPENCIL: | ||||
| case OB_LAMP: | case OB_LAMP: | ||||
| retval = snap_object_center( | retval = snap_object_center( | ||||
| dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); | dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); | ||||
| break; | break; | ||||
| case OB_CAMERA: | case OB_CAMERA: | ||||
| retval = snapCamera( | retval = snapCamera( | ||||
| sctx, dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); | sctx, dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); | ||||
| break; | break; | ||||
| } | } | ||||
| if (retval) { | if (retval) { | ||||
| if (dt->r_ob) { | if (dt->r_ob) { | ||||
| *dt->r_ob = ob; | *dt->r_ob = ob_eval; | ||||
| } | } | ||||
| if (dt->r_obmat) { | if (dt->r_obmat) { | ||||
| copy_m4_m4(dt->r_obmat, obmat); | copy_m4_m4(dt->r_obmat, obmat); | ||||
| } | } | ||||
| dt->ret = retval; | dt->ret = retval; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 256 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | | BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | | ||||
| SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) != | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) != | ||||
| 0); | 0); | ||||
| short retval = 0; | short retval = 0; | ||||
| bool has_hit = false; | bool has_hit = false; | ||||
| Object *ob = NULL; | Object *ob_eval = NULL; | ||||
| float loc[3]; | float loc[3]; | ||||
| /* Not all snapping callbacks set the normal, | /* Not all snapping callbacks set the normal, | ||||
| * initialize this since any hit copies both the `loc` and `no`. */ | * initialize this since any hit copies both the `loc` and `no`. */ | ||||
| float no[3] = {0.0f, 0.0f, 0.0f}; | float no[3] = {0.0f, 0.0f, 0.0f}; | ||||
| float obmat[4][4]; | float obmat[4][4]; | ||||
| int index = -1; | int index = -1; | ||||
| const ARegion *region = sctx->v3d_data.region; | const ARegion *region = sctx->v3d_data.region; | ||||
| Show All 20 Lines | has_hit = raycastObjects(sctx, | ||||
| depsgraph, | depsgraph, | ||||
| params, | params, | ||||
| ray_start, | ray_start, | ||||
| ray_normal, | ray_normal, | ||||
| &dummy_ray_depth, | &dummy_ray_depth, | ||||
| loc, | loc, | ||||
| no, | no, | ||||
| &index, | &index, | ||||
| &ob, | &ob_eval, | ||||
| obmat, | obmat, | ||||
| NULL); | NULL); | ||||
| if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) { | if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) { | ||||
| retval = SCE_SNAP_MODE_FACE; | retval = SCE_SNAP_MODE_FACE; | ||||
| copy_v3_v3(r_loc, loc); | copy_v3_v3(r_loc, loc); | ||||
| if (r_no) { | if (r_no) { | ||||
| copy_v3_v3(r_no, no); | copy_v3_v3(r_no, no); | ||||
| } | } | ||||
| if (r_ob) { | if (r_ob) { | ||||
| *r_ob = ob; | *r_ob = ob_eval; | ||||
| } | } | ||||
| if (r_obmat) { | if (r_obmat) { | ||||
| copy_m4_m4(r_obmat, obmat); | copy_m4_m4(r_obmat, obmat); | ||||
| } | } | ||||
| if (r_index) { | if (r_index) { | ||||
| *r_index = index; | *r_index = index; | ||||
| } | } | ||||
| } | } | ||||
| Show All 19 Lines | if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | | ||||
| planes_from_projmat( | planes_from_projmat( | ||||
| snapdata.pmat, NULL, NULL, NULL, NULL, snapdata.clip_plane[0], snapdata.clip_plane[1]); | snapdata.pmat, NULL, NULL, NULL, NULL, snapdata.clip_plane[0], snapdata.clip_plane[1]); | ||||
| snapdata.clip_plane_len = 2; | snapdata.clip_plane_len = 2; | ||||
| snapdata.has_occlusion_plane = false; | snapdata.has_occlusion_plane = false; | ||||
| /* By convention we only snap to the original elements of a curve. */ | /* By convention we only snap to the original elements of a curve. */ | ||||
| if (has_hit && ob->type != OB_CURVE) { | if (has_hit && ob_eval->type != OB_CURVE) { | ||||
| /* Compute the new clip_pane but do not add it yet. */ | /* Compute the new clip_pane but do not add it yet. */ | ||||
| float new_clipplane[4]; | float new_clipplane[4]; | ||||
| BLI_ASSERT_UNIT_V3(no); | |||||
| plane_from_point_normal_v3(new_clipplane, loc, no); | plane_from_point_normal_v3(new_clipplane, loc, no); | ||||
| if (dot_v3v3(snapdata.clip_plane[0], new_clipplane) > 0.0f) { | if (dot_v3v3(snapdata.clip_plane[0], new_clipplane) > 0.0f) { | ||||
| /* The plane is facing the wrong direction. */ | /* The plane is facing the wrong direction. */ | ||||
| negate_v4(new_clipplane); | negate_v4(new_clipplane); | ||||
| } | } | ||||
| /* Small offset to simulate a kind of volume for edges and vertices. */ | /* Small offset to simulate a kind of volume for edges and vertices. */ | ||||
| new_clipplane[3] += 0.01f; | new_clipplane[3] += 0.01f; | ||||
| /* Try to snap only to the polygon. */ | /* Try to snap only to the polygon. */ | ||||
| elem_test = snap_mesh_polygon( | elem_test = snap_mesh_polygon(sctx, | ||||
| sctx, &snapdata, ob, obmat, params->use_backface_culling, &dist_px_tmp, loc, no, &index); | &snapdata, | ||||
| ob_eval, | |||||
| obmat, | |||||
| params->use_backface_culling, | |||||
| &dist_px_tmp, | |||||
| loc, | |||||
| no, | |||||
| &index); | |||||
| if (elem_test) { | if (elem_test) { | ||||
| elem = elem_test; | elem = elem_test; | ||||
| } | } | ||||
| /* Add the new clip plane to the beginning of the list. */ | /* Add the new clip plane to the beginning of the list. */ | ||||
| for (int i = snapdata.clip_plane_len; i != 0; i--) { | for (int i = snapdata.clip_plane_len; i != 0; i--) { | ||||
| copy_v4_v4(snapdata.clip_plane[i], snapdata.clip_plane[i - 1]); | copy_v4_v4(snapdata.clip_plane[i], snapdata.clip_plane[i - 1]); | ||||
| } | } | ||||
| copy_v4_v4(snapdata.clip_plane[0], new_clipplane); | copy_v4_v4(snapdata.clip_plane[0], new_clipplane); | ||||
| snapdata.clip_plane_len++; | snapdata.clip_plane_len++; | ||||
| snapdata.has_occlusion_plane = true; | snapdata.has_occlusion_plane = true; | ||||
| } | } | ||||
| elem_test = snapObjectsRay( | elem_test = snapObjectsRay( | ||||
| sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat); | sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat); | ||||
| if (elem_test) { | if (elem_test) { | ||||
| elem = elem_test; | elem = elem_test; | ||||
| } | } | ||||
| if ((elem == SCE_SNAP_MODE_EDGE) && | if ((elem == SCE_SNAP_MODE_EDGE) && | ||||
| (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT | | (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT | | ||||
| SCE_SNAP_MODE_EDGE_PERPENDICULAR))) { | SCE_SNAP_MODE_EDGE_PERPENDICULAR))) { | ||||
| snapdata.snap_to_flag = snap_to_flag; | snapdata.snap_to_flag = snap_to_flag; | ||||
| elem = snap_mesh_edge_verts_mixed(sctx, | elem = snap_mesh_edge_verts_mixed(sctx, | ||||
| &snapdata, | &snapdata, | ||||
| ob, | ob_eval, | ||||
| obmat, | obmat, | ||||
| *dist_px, | *dist_px, | ||||
| prev_co, | prev_co, | ||||
| params->use_backface_culling, | params->use_backface_culling, | ||||
| &dist_px_tmp, | &dist_px_tmp, | ||||
| loc, | loc, | ||||
| no, | no, | ||||
| &index); | &index); | ||||
| } | } | ||||
| if (elem & snap_to_flag) { | if (elem & snap_to_flag) { | ||||
| retval = elem; | retval = elem; | ||||
| copy_v3_v3(r_loc, loc); | copy_v3_v3(r_loc, loc); | ||||
| if (r_no) { | if (r_no) { | ||||
| copy_v3_v3(r_no, no); | copy_v3_v3(r_no, no); | ||||
| } | } | ||||
| if (r_ob) { | if (r_ob) { | ||||
| *r_ob = ob; | *r_ob = ob_eval; | ||||
| } | } | ||||
| if (r_obmat) { | if (r_obmat) { | ||||
| copy_m4_m4(r_obmat, obmat); | copy_m4_m4(r_obmat, obmat); | ||||
| } | } | ||||
| if (r_index) { | if (r_index) { | ||||
| *r_index = index; | *r_index = index; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 100 Lines • Show Last 20 Lines | |||||