Transform: remove SnapData cache for meshes

All cache needed is already stored in `Mesh.runtime`.
This commit is contained in:
Germano Cavalcante 2022-11-03 16:33:41 -03:00
parent 129197f20d
commit cad897de16
Notes: blender-bot 2023-06-14 15:23:59 +02:00
Referenced by issue #108958, Measure tool: Crash in edit mode when snapping is enabled
Referenced by commit c2ed9c39cd, Fix #108958: Crash in edit mode when snapping is enabled
1 changed files with 97 additions and 224 deletions

View File

@ -61,41 +61,6 @@ enum eViewProj {
VIEW_PROJ_PERSP = -1,
};
/* SnapObjectContext.cache.mesh_map */
struct SnapData_Mesh {
/* Loose edges, loose verts. */
BVHTree *bvhtree[2];
bool cached[2];
/* Looptris. */
BVHTreeFromMesh treedata_mesh;
const MPoly *poly;
bool has_looptris;
bool has_loose_edge;
bool has_loose_vert;
void clear()
{
for (int i = 0; i < ARRAY_SIZE(this->bvhtree); i++) {
if (!this->cached[i]) {
BLI_bvhtree_free(this->bvhtree[i]);
}
this->bvhtree[i] = nullptr;
}
free_bvhtree_from_mesh(&this->treedata_mesh);
}
~SnapData_Mesh()
{
this->clear();
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("SnapData_Mesh")
#endif
};
/* SnapObjectContext.cache.editmesh_map */
struct SnapData_EditMesh {
/* Verts, Edges. */
@ -134,7 +99,6 @@ struct SnapObjectContext {
int flag;
Map<const Object *, std::unique_ptr<SnapData_Mesh>> mesh_caches;
Map<const BMEditMesh *, std::unique_ptr<SnapData_EditMesh>> editmesh_caches;
/* Filter data, returns true to check this value */
@ -180,28 +144,36 @@ static const Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type,
{
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
bool use_hide = false;
if (BKE_object_is_in_editmode(ob_eval)) {
if (edit_mode_type == SNAP_GEOM_EDIT) {
return nullptr;
}
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
switch (ob_eval->type) {
case OB_MESH: {
if (BKE_object_is_in_editmode(ob_eval)) {
if (edit_mode_type == SNAP_GEOM_EDIT) {
return nullptr;
}
if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) {
if (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return nullptr;
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) {
if (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return nullptr;
}
me_eval = editmesh_eval_final;
use_hide = true;
}
else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) {
if (editmesh_eval_cage->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return nullptr;
}
me_eval = editmesh_eval_cage;
use_hide = true;
}
}
me_eval = editmesh_eval_final;
use_hide = true;
}
else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) {
if (editmesh_eval_cage->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return nullptr;
}
me_eval = editmesh_eval_cage;
use_hide = true;
break;
}
default:
break;
}
if (r_use_hide) {
*r_use_hide = use_hide;
@ -236,96 +208,31 @@ static void snap_editmesh_minmax(SnapObjectContext *sctx,
}
}
static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
Object *ob_eval,
const Mesh *me_eval,
bool use_hide)
static void snap_object_data_mesh_get(SnapObjectContext *sctx,
Object *ob_eval,
const Mesh *me_eval,
bool use_hide,
BVHTreeFromMesh *r_treedata)
{
SnapData_Mesh *sod;
bool init = false;
const Span<MVert> verts = me_eval->verts();
const Span<MEdge> edges = me_eval->edges();
const Span<MPoly> polys = me_eval->polys();
const Span<MLoop> loops = me_eval->loops();
if (std::unique_ptr<SnapData_Mesh> *sod_p = sctx->mesh_caches.lookup_ptr(ob_eval)) {
sod = sod_p->get();
bool is_dirty = false;
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 != me_eval->looptris().data()) {
is_dirty = true;
}
else if (sod->treedata_mesh.vert != verts.data()) {
is_dirty = true;
}
else if (sod->treedata_mesh.loop != loops.data()) {
is_dirty = true;
}
else if (sod->treedata_mesh.edge != edges.data()) {
is_dirty = true;
}
else if (sod->poly != polys.data()) {
is_dirty = true;
}
if (is_dirty) {
sod->clear();
init = true;
}
}
else {
if (ob_eval->type == OB_MESH) {
/* Any existing #SnapData_EditMesh is now invalid. */
sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
}
std::unique_ptr<SnapData_Mesh> sod_ptr = std::make_unique<SnapData_Mesh>();
sod = sod_ptr.get();
sctx->mesh_caches.add_new(ob_eval, std::move(sod_ptr));
init = true;
if (ob_eval->type == OB_MESH) {
/* Any existing #SnapData_EditMesh is now invalid. */
sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
}
if (init) {
/* The BVHTree from looptris is always required. */
BLI_assert(sod->treedata_mesh.tree == nullptr);
BKE_bvhtree_from_mesh_get(&sod->treedata_mesh,
me_eval,
use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI,
4);
/* The BVHTree from looptris is always required. */
BKE_bvhtree_from_mesh_get(
r_treedata, me_eval, use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI, 4);
BLI_assert(sod->treedata_mesh.vert == verts.data());
BLI_assert(!verts.data() || sod->treedata_mesh.vert_normals);
BLI_assert(sod->treedata_mesh.loop == loops.data());
BLI_assert(!polys.data() || sod->treedata_mesh.looptri);
sod->has_looptris = sod->treedata_mesh.tree != nullptr;
/* Required for snapping with occlusion. */
sod->treedata_mesh.edge = edges.data();
sod->poly = polys.data();
/* Start assuming that it has each of these element types. */
sod->has_loose_edge = true;
sod->has_loose_vert = true;
}
return sod;
BLI_assert(r_treedata->vert == verts.data());
BLI_assert(!verts.data() || r_treedata->vert_normals);
BLI_assert(r_treedata->loop == loops.data());
BLI_assert(!polys.data() || r_treedata->looptri);
BLI_assert(!r_treedata->tree || r_treedata->looptri);
}
/* Searches for the #Mesh_Runtime associated with the object that is most likely to be updated due
@ -352,9 +259,6 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
SnapData_EditMesh *sod;
bool init = false;
/* Any existing #SnapData_Mesh is now invalid. */
sctx->mesh_caches.remove(ob_eval);
if (std::unique_ptr<SnapData_EditMesh> *sod_p = sctx->editmesh_caches.lookup_ptr(em)) {
sod = sod_p->get();
bool is_dirty = false;
@ -411,15 +315,6 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
return sod;
}
static BVHTreeFromMesh *snap_object_data_mesh_treedata_get(SnapObjectContext *sctx,
Object *ob_eval,
const Mesh *me_eval,
bool use_hide)
{
SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
return &sod->treedata_mesh;
}
static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectContext *sctx,
Object *ob_eval,
BMEditMesh *em)
@ -787,23 +682,22 @@ static bool raycastMesh(SnapObjectContext *sctx,
len_diff = 0.0f;
}
SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
BVHTreeFromMesh treedata;
snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide, &treedata);
BVHTreeFromMesh *treedata = &sod->treedata_mesh;
if (treedata->tree == nullptr) {
if (treedata.tree == nullptr) {
return retval;
}
float timat[3][3]; /* transpose inverse matrix for normals */
transpose_m3_m4(timat, imat);
BLI_assert(treedata->raycast_callback != nullptr);
BLI_assert(treedata.raycast_callback != nullptr);
if (r_hit_list) {
RayCastAll_Data data;
data.bvhdata = treedata;
data.raycast_callback = treedata->raycast_callback;
data.bvhdata = &treedata;
data.raycast_callback = treedata.raycast_callback;
data.obmat = obmat;
data.timat = timat;
data.len_diff = len_diff;
@ -813,13 +707,8 @@ static bool raycastMesh(SnapObjectContext *sctx,
data.hit_list = r_hit_list;
data.retval = retval;
BLI_bvhtree_ray_cast_all(treedata->tree,
ray_start_local,
ray_normal_local,
0.0f,
*ray_depth,
raycast_all_cb,
&data);
BLI_bvhtree_ray_cast_all(
treedata.tree, ray_start_local, ray_normal_local, 0.0f, *ray_depth, raycast_all_cb, &data);
retval = data.retval;
}
@ -828,15 +717,15 @@ static bool raycastMesh(SnapObjectContext *sctx,
hit.index = -1;
hit.dist = local_depth;
if (BLI_bvhtree_ray_cast(treedata->tree,
if (BLI_bvhtree_ray_cast(treedata.tree,
ray_start_local,
ray_normal_local,
0.0f,
&hit,
params->use_backface_culling ?
mesh_looptri_raycast_backface_culling_cb :
treedata->raycast_callback,
treedata) != -1) {
treedata.raycast_callback,
&treedata) != -1) {
hit.dist += len_diff;
hit.dist /= local_scale;
if (hit.dist <= *ray_depth) {
@ -855,7 +744,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
retval = true;
if (r_index) {
*r_index = treedata->looptri[hit.index].poly;
*r_index = treedata.looptri[hit.index].poly;
}
}
}
@ -1335,16 +1224,17 @@ static bool nearest_world_mesh(SnapObjectContext *sctx,
float *r_no,
int *r_index)
{
BVHTreeFromMesh *treedata = snap_object_data_mesh_treedata_get(sctx, ob_eval, me_eval, use_hide);
if (treedata == nullptr || treedata->tree == nullptr) {
BVHTreeFromMesh treedata;
snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide, &treedata);
if (treedata.tree == nullptr) {
return false;
}
return nearest_world_tree(sctx,
params,
treedata->tree,
treedata->nearest_callback,
treedata,
treedata.tree,
treedata.nearest_callback,
&treedata,
obmat,
init_co,
curr_co,
@ -1854,7 +1744,7 @@ static void cb_snap_tri_verts(void *userdata,
}
}
static void nearest2d_data_init_mesh(SnapData_Mesh *sod,
static void nearest2d_data_init_mesh(const Mesh *mesh,
bool is_persp,
bool use_backface_culling,
Nearest2dUserData *r_nearest2d)
@ -1865,11 +1755,11 @@ static void nearest2d_data_init_mesh(SnapData_Mesh *sod,
r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
r_nearest2d->vert = sod->treedata_mesh.vert;
r_nearest2d->vert_normals = sod->treedata_mesh.vert_normals;
r_nearest2d->edge = sod->treedata_mesh.edge;
r_nearest2d->loop = sod->treedata_mesh.loop;
r_nearest2d->looptri = sod->treedata_mesh.looptri;
r_nearest2d->vert = mesh->verts().data();
r_nearest2d->vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
r_nearest2d->edge = mesh->edges().data();
r_nearest2d->loop = mesh->loops().data();
r_nearest2d->looptri = BKE_mesh_runtime_looptri_ensure(mesh);
r_nearest2d->is_persp = is_persp;
r_nearest2d->use_backface_culling = use_backface_culling;
@ -1929,20 +1819,18 @@ static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx,
nearest.dist_sq = square_f(*dist_px);
Nearest2dUserData nearest2d;
std::unique_ptr<SnapData_Mesh> *sod_mesh = sctx->mesh_caches.lookup_ptr(ob_eval);
if (sod_mesh) {
nearest2d_data_init_mesh(sod_mesh->get(),
const Mesh *mesh = mesh_for_snap(ob_eval, params->edit_mode_type, nullptr);
if (mesh) {
nearest2d_data_init_mesh(mesh,
sctx->runtime.view_proj == VIEW_PROJ_PERSP,
params->use_backface_culling,
&nearest2d);
BVHTreeFromMesh *treedata = &sod_mesh->get()->treedata_mesh;
const MPoly *mp = &sod_mesh->get()->poly[*r_index];
const MLoop *ml = &treedata->loop[mp->loopstart];
const MPoly *mp = &mesh->polys()[*r_index];
const MLoop *ml = &nearest2d.loop[mp->loopstart];
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
elem = SCE_SNAP_MODE_EDGE;
BLI_assert(treedata->edge != nullptr);
BLI_assert(nearest2d.edge != nullptr);
for (int i = mp->totloop; i--; ml++) {
cb_snap_edge(&nearest2d,
ml->e,
@ -2052,9 +1940,9 @@ static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
Nearest2dUserData nearest2d;
{
std::unique_ptr<SnapData_Mesh> *sod_mesh = sctx->mesh_caches.lookup_ptr(ob_eval);
if (sod_mesh) {
nearest2d_data_init_mesh(sod_mesh->get(),
const Mesh *mesh = mesh_for_snap(ob_eval, params->edit_mode_type, nullptr);
if (mesh) {
nearest2d_data_init_mesh(mesh,
sctx->runtime.view_proj == VIEW_PROJ_PERSP,
params->use_backface_culling,
&nearest2d);
@ -2713,38 +2601,22 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
return SCE_SNAP_MODE_NONE;
}
SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
BVHTreeFromMesh *treedata, treedata_tmp;
treedata = &sod->treedata_mesh;
if (sod->has_loose_edge && sod->bvhtree[0] == nullptr) {
sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(
&treedata_tmp, me_eval, BVHTREE_FROM_LOOSEEDGES, 2);
if (sod->bvhtree[0] == nullptr) {
sod->has_loose_edge = false;
}
sod->cached[0] = treedata_tmp.cached;
}
BVHTreeFromMesh treedata, treedata_dummy;
snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide, &treedata);
BVHTree *bvhtree[2] = {nullptr};
bvhtree[0] = BKE_bvhtree_from_mesh_get(&treedata_dummy, me_eval, BVHTREE_FROM_LOOSEEDGES, 2);
BLI_assert(treedata_dummy.cached);
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
if (sod->has_loose_vert && sod->bvhtree[1] == nullptr) {
sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(
&treedata_tmp, me_eval, BVHTREE_FROM_LOOSEVERTS, 2);
if (sod->bvhtree[1] == nullptr) {
sod->has_loose_vert = false;
}
sod->cached[1] = treedata_tmp.cached;
}
}
else {
/* Not necessary, just to keep the data more consistent. */
sod->has_loose_vert = false;
bvhtree[1] = BKE_bvhtree_from_mesh_get(&treedata_dummy, me_eval, BVHTREE_FROM_LOOSEVERTS, 2);
BLI_assert(treedata_dummy.cached);
}
Nearest2dUserData nearest2d;
nearest2d_data_init_mesh(
sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
nearest2d_data_init_mesh(me_eval,
sctx->runtime.view_proj == VIEW_PROJ_PERSP,
params->use_backface_culling,
&nearest2d);
BVHTreeNearest nearest{};
nearest.index = -1;
@ -2759,9 +2631,10 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
if (sod->bvhtree[1] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
if (bvhtree[1]) {
BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX);
/* snap to loose verts */
BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
BLI_bvhtree_find_nearest_projected(bvhtree[1],
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,
@ -2775,9 +2648,9 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
}
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
if (sod->bvhtree[0]) {
if (bvhtree[0]) {
/* snap to loose edges */
BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
BLI_bvhtree_find_nearest_projected(bvhtree[0],
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,
@ -2788,9 +2661,9 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
&nearest2d);
}
if (treedata->tree) {
if (treedata.tree) {
/* snap to looptris */
BLI_bvhtree_find_nearest_projected(treedata->tree,
BLI_bvhtree_find_nearest_projected(treedata.tree,
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,
@ -2807,9 +2680,9 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
}
else {
BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX);
if (sod->bvhtree[0]) {
if (bvhtree[0]) {
/* snap to loose edge verts */
BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
BLI_bvhtree_find_nearest_projected(bvhtree[0],
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,
@ -2820,9 +2693,9 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
&nearest2d);
}
if (treedata->tree) {
if (treedata.tree) {
/* snap to looptri verts */
BLI_bvhtree_find_nearest_projected(treedata->tree,
BLI_bvhtree_find_nearest_projected(treedata.tree,
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,