diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 434255b2d9c..4acaa7b05e1 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -516,6 +516,11 @@ typedef struct SculptAttribute { int elem_size, elem_num; bool data_for_bmesh; /* Temporary data store as array outside of bmesh. */ + /* Data is a flat array outside the CustomData system. + * This will be true if simple_array is requested in + * SculptAttributeParams, or the PBVH type is PBVH_GRIDS or PBVH_BMESH. + */ + bool simple_array; /* Data stored per BMesh element. */ int bmesh_cd_offset; diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc index 7f9a0d64e4b..3700432696a 100644 --- a/source/blender/blenkernel/intern/multires.cc +++ b/source/blender/blenkernel/intern/multires.cc @@ -426,6 +426,28 @@ void multires_flush_sculpt_updates(Object *object) } Mesh *mesh = static_cast(object->data); + + /* Check that the multires modifier still exists. + * Fixes crash when deleting multires modifier + * from within sculpt mode. + */ + ModifierData *md; + MultiresModifierData *mmd = nullptr; + VirtualModifierData virtualModifierData; + + for (md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData); md; + md = md->next) { + if (md->type == eModifierType_Multires) { + if (BKE_modifier_is_enabled(nullptr, md, eModifierMode_Realtime)) { + mmd = (MultiresModifierData *)md; + } + } + } + + if (!mmd) { + return; + } + multiresModifier_reshapeFromCCG( sculpt_session->multires.modifier->totlvl, mesh, sculpt_session->subdiv_ccg); diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 3100b4cc20c..718ec5318ac 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -2454,7 +2454,7 @@ static bool sculpt_attribute_create(SculptSession *ss, permanent = (out->params.permanent = false); } - simple_array = (out->params.simple_array = true); + simple_array = true; } BLI_assert(!(simple_array && permanent)); @@ -2466,8 +2466,8 @@ static bool sculpt_attribute_create(SculptSession *ss, out->data = MEM_calloc_arrayN(totelem, elemsize, __func__); - out->data_for_bmesh = false; - out->params.simple_array = true; + out->data_for_bmesh = ss->bm != nullptr; + out->simple_array = true; out->bmesh_cd_offset = -1; out->layer = nullptr; out->elem_size = elemsize; @@ -2477,6 +2477,8 @@ static bool sculpt_attribute_create(SculptSession *ss, return true; } + out->simple_array = false; + switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_BMESH: { CustomData *cdata = nullptr; @@ -2512,8 +2514,6 @@ static bool sculpt_attribute_create(SculptSession *ss, case PBVH_FACES: { CustomData *cdata = nullptr; - out->data_for_bmesh = false; - switch (domain) { case ATTR_DOMAIN_POINT: cdata = &me->vdata; @@ -2535,10 +2535,10 @@ static bool sculpt_attribute_create(SculptSession *ss, cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY; } - out->data = nullptr; out->layer = cdata->layers + index; - out->bmesh_cd_offset = -1; out->data = out->layer->data; + out->data_for_bmesh = false; + out->bmesh_cd_offset = -1; out->elem_size = CustomData_get_elem_size(out->layer); break; @@ -2566,31 +2566,36 @@ static bool sculpt_attr_update(Object *ob, SculptAttribute *attr) bool bad = false; - if (attr->params.simple_array) { + if (attr->data) { bad = attr->elem_num != elem_num; - - if (bad) { - MEM_SAFE_FREE(attr->data); - } - else { - attr->data_for_bmesh = false; - } } - else { - CustomData *cdata = sculpt_get_cdata(ob, attr->domain); - if (cdata) { - int layer_index = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name); + /* Check if we are a coerced simple array and shouldn't be. */ + bad |= attr->simple_array && !attr->params.simple_array && + !ELEM(BKE_pbvh_type(ss->pbvh), PBVH_GRIDS, PBVH_BMESH); - bad |= (ss->bm != nullptr) != attr->data_for_bmesh; + CustomData *cdata = sculpt_get_cdata(ob, attr->domain); + if (cdata && !attr->simple_array) { + int layer_index = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name); + bad |= layer_index == -1; + bad |= (ss->bm != nullptr) != attr->data_for_bmesh; + + if (!bad) { if (attr->data_for_bmesh) { attr->bmesh_cd_offset = cdata->layers[layer_index].offset; } + else { + attr->data = cdata->layers[layer_index].data; + } } } if (bad) { + if (attr->simple_array) { + MEM_SAFE_FREE(attr->data); + } + sculpt_attribute_create(ss, ob, attr->domain, @@ -2725,6 +2730,8 @@ static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob, SculptAttribute *attr = BKE_sculpt_attribute_get(ob, domain, proptype, name); if (attr) { + sculpt_attr_update(ob, attr); + return attr; } @@ -2763,7 +2770,7 @@ static void sculptsession_bmesh_attr_update_internal(Object *ob) } } -void sculptsession_bmesh_add_layers(Object *ob) +static void sculptsession_bmesh_add_layers(Object *ob) { SculptSession *ss = ob->sculpt; SculptAttributeParams params = {0}; @@ -2870,7 +2877,7 @@ bool BKE_sculpt_attribute_destroy(Object *ob, SculptAttribute *attr) Mesh *me = BKE_object_get_original_mesh(ob); - if (attr->params.simple_array) { + if (attr->simple_array) { MEM_SAFE_FREE(attr->data); } else if (ss->bm) { diff --git a/source/blender/draw/intern/draw_pbvh.cc b/source/blender/draw/intern/draw_pbvh.cc index 0bdfbf11cb8..c3d660b8ecd 100644 --- a/source/blender/draw/intern/draw_pbvh.cc +++ b/source/blender/draw/intern/draw_pbvh.cc @@ -1368,6 +1368,8 @@ GPUBatch *DRW_pbvh_tris_get(PBVHBatches *batches, int *r_prim_count, bool do_coarse_grids) { + do_coarse_grids &= args->pbvh_type == PBVH_GRIDS; + PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args, do_coarse_grids); *r_prim_count = batch.tris_count; @@ -1382,6 +1384,8 @@ GPUBatch *DRW_pbvh_lines_get(PBVHBatches *batches, int *r_prim_count, bool do_coarse_grids) { + do_coarse_grids &= args->pbvh_type == PBVH_GRIDS; + PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args, do_coarse_grids); *r_prim_count = batch.lines_count;