Sculpt: Fix more attribute bugs when switching PBVH modes

Fixed more cases where attributes weren't being reinitialized
on switching PBVH mode:

* When PBVH_GRIDS and PBVH_BMESH force attributes into simple
  array mode they no longer override simple_array in the
  SculptAttributeParams parameters, instead they set a field
  in SculptAttribute itself.  Thus if the attribute is
  reinitialized in another mode it won't retain the simple_array
  parameter.
* sculpt_attribute_ensure_ex now calls sculpt_attr_update if
  the attribute already exists.
* Fixed a bug from a couple commits ago that set
  SculptAttribute.data_for_bmesh wrong.
This commit is contained in:
Joseph Eagar 2022-12-13 13:42:25 -08:00
parent 6f9cfb037a
commit 939b63bcd6
4 changed files with 60 additions and 22 deletions

View File

@ -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;

View File

@ -426,6 +426,28 @@ void multires_flush_sculpt_updates(Object *object)
}
Mesh *mesh = static_cast<Mesh *>(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);

View File

@ -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) {

View File

@ -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;