Fix #137751: Dyntopo undo can crash when drawing attributes
When performing an undo in Sculpt Mode with Dyntopo enabled, it is possible that the active color attribute exists in the original mesh but not on the BMesh used by Dyntopo. When attempting to extract this color data, this can then lead to a crash. To prevent this, use the BMesh as the source of truth for existence of generic attributes when mode inside Sculpt Mode when Dyntopo is enabled. Pull Request: https://projects.blender.org/blender/blender/pulls/137828
This commit is contained in:
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "BLI_math_matrix.hh"
|
||||
|
||||
#include "bmesh_class.hh"
|
||||
|
||||
#include "DRW_pbvh.hh"
|
||||
#include "DRW_render.hh"
|
||||
|
||||
@@ -123,6 +125,28 @@ static Vector<SculptBatch> sculpt_batches_get_ex(const Object *ob,
|
||||
return result_batches;
|
||||
}
|
||||
|
||||
static const CustomData *get_cdata(const BMesh &bm, const bke::AttrDomain domain)
|
||||
{
|
||||
switch (domain) {
|
||||
case bke::AttrDomain::Point:
|
||||
return &bm.vdata;
|
||||
case bke::AttrDomain::Corner:
|
||||
return &bm.ldata;
|
||||
case bke::AttrDomain::Face:
|
||||
return &bm.pdata;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool bmesh_attribute_exists(const BMesh &bm,
|
||||
const bke::AttributeMetaData &meta_data,
|
||||
const StringRef name)
|
||||
{
|
||||
const CustomData *cdata = get_cdata(bm, meta_data.domain);
|
||||
return cdata && CustomData_get_offset_named(cdata, meta_data.data_type, name) != -1;
|
||||
}
|
||||
|
||||
Vector<SculptBatch> sculpt_batches_get(const Object *ob, SculptBatchFeature features)
|
||||
{
|
||||
Vector<pbvh::AttributeRequest, 16> attrs;
|
||||
@@ -138,19 +162,30 @@ Vector<SculptBatch> sculpt_batches_get(const Object *ob, SculptBatchFeature feat
|
||||
|
||||
const Mesh *mesh = BKE_object_get_original_mesh(ob);
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
const SculptSession &ss = *ob->sculpt;
|
||||
|
||||
/* If Dyntopo is enabled, the source of truth for an attribute existing or not is the BMesh, not
|
||||
* the Mesh. */
|
||||
if (features & SCULPT_BATCH_VERTEX_COLOR) {
|
||||
if (const char *name = mesh->active_color_attribute) {
|
||||
if (const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(
|
||||
name))
|
||||
{
|
||||
attrs.append(pbvh::GenericRequest{name, meta_data->data_type, meta_data->domain});
|
||||
if (ss.bm) {
|
||||
if (bmesh_attribute_exists(*ss.bm, *meta_data, name)) {
|
||||
attrs.append(pbvh::GenericRequest{name, meta_data->data_type, meta_data->domain});
|
||||
}
|
||||
}
|
||||
else {
|
||||
attrs.append(pbvh::GenericRequest{name, meta_data->data_type, meta_data->domain});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (features & SCULPT_BATCH_UV) {
|
||||
if (const char *name = CustomData_get_active_layer_name(&mesh->corner_data, CD_PROP_FLOAT2)) {
|
||||
const CustomData *corner_data = ss.bm ? &ss.bm->ldata : &mesh->corner_data;
|
||||
if (const char *name = CustomData_get_active_layer_name(corner_data, CD_PROP_FLOAT2)) {
|
||||
attrs.append(pbvh::GenericRequest{name, CD_PROP_FLOAT2, bke::AttrDomain::Corner});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user