diff options
author | Joseph Eagar <joeedh@gmail.com> | 2022-06-01 01:46:09 +0300 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2022-06-01 01:46:09 +0300 |
commit | 75162ab8c23937fce64e7b2674cc706a008ded96 (patch) | |
tree | e164662b22459b49aec8dcf4b597ea05ebfa80cd /source/blender/editors | |
parent | 511a08585d2934b38e7d3de447752686b5f0e15b (diff) |
Fix T97408: Temporary fix for attribute convert undo
Sculpt undo now detects if an attribute layer has
changed type/domain and unconverts it back. This
is a temporary workaround to a more fundamental
bug in the undo system.
Memfile undo assumes it can always rebuild the
application state from the prior undo step,
which isn't true with incremental undo systems.
The correct fix is to push an extra undo step prior
to running an operator if an incremental undo system
is active and the operator is using memfile undo.
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/geometry/geometry_attributes.cc | 36 | ||||
-rw-r--r-- | source/blender/editors/include/ED_geometry.h | 12 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_undo.c | 19 |
3 files changed, 66 insertions, 1 deletions
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index 05f9e19da71..17784a50bca 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -33,6 +33,7 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "ED_geometry.h" #include "ED_object.h" #include "geometry_intern.hh" @@ -580,3 +581,38 @@ void GEOMETRY_OT_attribute_convert(wmOperatorType *ot) } } // namespace blender::ed::geometry + +using blender::CPPType; +using blender::GVArray; + +bool ED_geometry_attribute_convert(Mesh *mesh, + const char *layer_name, + CustomDataType old_type, + AttributeDomain old_domain, + CustomDataType new_type, + AttributeDomain new_domain) +{ + CustomDataLayer *layer = BKE_id_attribute_find(&mesh->id, layer_name, old_type, old_domain); + const std::string name = layer->name; + + if (!layer) { + return false; + } + + MeshComponent mesh_component; + mesh_component.replace(mesh, GeometryOwnershipType::Editable); + GVArray src_varray = mesh_component.attribute_get_for_read(name, new_domain, new_type); + + const CPPType &cpp_type = src_varray.type(); + void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); + src_varray.materialize_to_uninitialized(new_data); + mesh_component.attribute_try_delete(name); + mesh_component.attribute_try_create(name, new_domain, new_type, AttributeInitMove(new_data)); + + int *active_index = BKE_id_attributes_active_index_p(&mesh->id); + if (*active_index > 0) { + *active_index -= 1; + } + + return true; +} diff --git a/source/blender/editors/include/ED_geometry.h b/source/blender/editors/include/ED_geometry.h index 74ff968828c..46e6904523a 100644 --- a/source/blender/editors/include/ED_geometry.h +++ b/source/blender/editors/include/ED_geometry.h @@ -7,12 +7,22 @@ #pragma once +#include "BKE_attribute.h" +#include "DNA_customdata_types.h" + #ifdef __cplusplus extern "C" { #endif -void ED_operatortypes_geometry(void); +struct Mesh; +void ED_operatortypes_geometry(void); +bool ED_geometry_attribute_convert(struct Mesh *mesh, + const char *layer_name, + CustomDataType old_type, + AttributeDomain old_domain, + CustomDataType new_type, + AttributeDomain new_domain); #ifdef __cplusplus } #endif diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 5867dc558de..54678c21cb8 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -50,6 +50,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_geometry.h" #include "ED_object.h" #include "ED_sculpt.h" #include "ED_undo.h" @@ -1565,6 +1566,24 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr CustomDataLayer *layer; layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); + /* Temporary fix for T97408. This is a fundamental + * bug in the undo stack; the operator code needs to push + * an extra undo step before running an operator if a + * non-memfile undo system is active. + * + * For now, detect if the layer does exist but with a different + * domain and just unconvert it. + */ + if (!layer) { + layer = BKE_id_attribute_search(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL); + AttributeDomain domain = layer ? BKE_id_attribute_domain(&me->id, layer) : ATTR_DOMAIN_NUM; + + if (layer && ED_geometry_attribute_convert( + me, attr->name, layer->type, domain, attr->type, attr->domain)) { + layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); + } + } + if (!layer) { /* Memfile undo killed the layer; re-create it. */ CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &me->vdata : &me->ldata; |