Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Eagar <joeedh@gmail.com>2022-04-05 21:42:55 +0300
committerJoseph Eagar <joeedh@gmail.com>2022-04-05 21:42:55 +0300
commiteae36be372a6b16ee3e76eff0485a47da4f3c230 (patch)
treed1ca2dc30951e31f1b91eed6a4edfdfb0824bf1f /source/blender/editors/sculpt_paint/sculpt_undo.c
parenta3e122b9aec59fc303c2375a78183cfb8642c14f (diff)
Refactor: Unify vertex and sculpt colors into new
color attribute system. This commit removes sculpt colors from experimental status and unifies it with vertex colors. It introduces the concept of "color attributes", which are any attributes that represents colors. Color attributes can be represented with byte or floating-point numbers and can be stored in either vertices or face corners. Color attributes share a common namespace (so you can no longer have a floating-point sculpt color attribute and a byte vertex color attribute with the same name). Note: this commit does not include vertex paint mode, which is a separate patch, see: https://developer.blender.org/D14179 Differential Revision: https://developer.blender.org/D12587 Ref D12587
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_undo.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c235
1 files changed, 207 insertions, 28 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 2ec553c63c7..1354277fbdd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -24,6 +24,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "BKE_attribute.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -31,6 +32,7 @@
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_multires.h"
#include "BKE_object.h"
@@ -94,13 +96,38 @@
* End of dynamic topology and symmetrize in this mode are handled in a special
* manner as well. */
+#define NO_ACTIVE_LAYER ATTR_DOMAIN_AUTO
+
typedef struct UndoSculpt {
ListBase nodes;
size_t undo_size;
} UndoSculpt;
+typedef struct SculptAttrRef {
+ AttributeDomain domain;
+ int type;
+ char name[MAX_CUSTOMDATA_LAYER_NAME];
+ bool was_set;
+} SculptAttrRef;
+
+typedef struct SculptUndoStep {
+ UndoStep step;
+ /* NOTE: will split out into list for multi-object-sculpt-mode. */
+ UndoSculpt data;
+
+ /* Active color attribute at the start of this undo step. */
+ SculptAttrRef active_color_start;
+
+ /* Active color attribute at the end of this undo step. */
+ SculptAttrRef active_color_end;
+
+ bContext *C;
+} SculptUndoStep;
+
static UndoSculpt *sculpt_undo_get_nodes(void);
+static bool sculpt_attribute_ref_equals(SculptAttrRef *a, SculptAttrRef *b);
+static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr);
static void update_cb(PBVHNode *node, void *rebuild)
{
@@ -313,17 +340,30 @@ static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode)
Object *ob = OBACT(view_layer);
SculptSession *ss = ob->sculpt;
- if (unode->maxvert) {
- /* regular mesh restore */
- int *index = unode->index;
- MPropCol *vcol = ss->vcol;
+ bool modified = false;
+ /* NOTE: even with loop colors we still store derived
+ * vertex colors for original data lookup.*/
+ if (unode->col && !unode->loop_col) {
+ BKE_pbvh_swap_colors(ss->pbvh, unode->index, unode->totvert, unode->col);
+ modified = true;
+ }
+
+ Mesh *me = BKE_object_get_original_mesh(ob);
+
+ if (unode->loop_col && unode->maxloop == me->totloop) {
+ BKE_pbvh_swap_colors(ss->pbvh, unode->loop_index, unode->totloop, unode->loop_col);
+
+ modified = true;
+ }
+
+ if (modified) {
for (int i = 0; i < unode->totvert; i++) {
- copy_v4_v4(vcol[index[i]].color, unode->col[i]);
- BKE_pbvh_vert_mark_update(ss->pbvh, index[i]);
+ BKE_pbvh_vert_mark_update(ss->pbvh, unode->index[i]);
}
}
- return true;
+
+ return modified;
}
static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
@@ -739,8 +779,8 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
if (sculpt_undo_restore_color(C, unode)) {
update = true;
}
- break;
+ break;
case SCULPT_UNDO_GEOMETRY:
need_refine_subdiv = true;
sculpt_undo_geometry_restore(unode, ob);
@@ -843,12 +883,21 @@ static void sculpt_undo_free_list(ListBase *lb)
if (unode->co) {
MEM_freeN(unode->co);
}
+ if (unode->col) {
+ MEM_freeN(unode->col);
+ }
+ if (unode->loop_col) {
+ MEM_freeN(unode->loop_col);
+ }
if (unode->no) {
MEM_freeN(unode->no);
}
if (unode->index) {
MEM_freeN(unode->index);
}
+ if (unode->loop_index) {
+ MEM_freeN(unode->loop_index);
+ }
if (unode->grids) {
MEM_freeN(unode->grids);
}
@@ -1010,6 +1059,21 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
unode->totvert = totvert;
}
+ bool need_loops = type == SCULPT_UNDO_COLOR;
+
+ if (need_loops) {
+ int totloop;
+
+ BKE_pbvh_node_num_loops(ss->pbvh, node, &totloop);
+
+ unode->loop_index = MEM_calloc_arrayN(totloop, sizeof(int), __func__);
+ unode->maxloop = 0;
+ unode->totloop = totloop;
+
+ size_t alloc_size = sizeof(int) * (size_t)totloop;
+ usculpt->undo_size += alloc_size;
+ }
+
switch (type) {
case SCULPT_UNDO_COORDS: {
size_t alloc_size = sizeof(*unode->co) * (size_t)allvert;
@@ -1041,9 +1105,20 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
break;
}
case SCULPT_UNDO_COLOR: {
+ /* Allocate vertex colors, even for loop colors we still
+ * need this for original data lookup. */
const size_t alloc_size = sizeof(*unode->col) * (size_t)allvert;
unode->col = MEM_callocN(alloc_size, "SculptUndoNode.col");
usculpt->undo_size += alloc_size;
+
+ /* Allocate loop colors separately too. */
+ if (ss->vcol_domain == ATTR_DOMAIN_CORNER) {
+ size_t alloc_size_loop = sizeof(float) * 4 * (size_t)unode->totloop;
+
+ unode->loop_col = MEM_calloc_arrayN(
+ unode->totloop, sizeof(float) * 4, "SculptUndoNode.loop_col");
+ usculpt->undo_size += alloc_size_loop;
+ }
break;
}
case SCULPT_UNDO_DYNTOPO_BEGIN:
@@ -1139,12 +1214,19 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode)
static void sculpt_undo_store_color(Object *ob, SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
- copy_v4_v4(unode->col[vd.i], vd.col);
+ BLI_assert(BKE_pbvh_type(ss->pbvh) == PBVH_FACES);
+
+ int allvert;
+ BKE_pbvh_node_num_verts(ss->pbvh, unode->node, NULL, &allvert);
+
+ /* NOTE: even with loop colors we still store (derived)
+ * vertex colors for original data lookup. */
+ BKE_pbvh_store_colors_vertex(ss->pbvh, unode->index, allvert, unode->col);
+
+ if (unode->loop_col && unode->totloop) {
+ BKE_pbvh_store_colors(ss->pbvh, unode->loop_index, unode->totloop, unode->loop_col);
}
- BKE_pbvh_vertex_iter_end;
}
static SculptUndoNodeGeometry *sculpt_undo_geometry_get(SculptUndoNode *unode)
@@ -1316,11 +1398,23 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
memcpy(unode->grids, grids, sizeof(int) * totgrid);
}
else {
- const int *vert_indices;
- int allvert;
- BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert);
+ const int *vert_indices, *loop_indices;
+ int allvert, allloop;
+
+ BKE_pbvh_node_num_verts(ss->pbvh, unode->node, NULL, &allvert);
BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL);
- memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert);
+ memcpy(unode->index, vert_indices, sizeof(int) * allvert);
+
+ if (unode->loop_index) {
+ BKE_pbvh_node_num_loops(ss->pbvh, unode->node, &allloop);
+ BKE_pbvh_node_get_loops(ss->pbvh, unode->node, &loop_indices, NULL);
+
+ if (allloop) {
+ memcpy(unode->loop_index, loop_indices, sizeof(int) * allloop);
+
+ unode->maxloop = BKE_object_get_original_mesh(ob)->totloop;
+ }
+ }
}
switch (type) {
@@ -1362,6 +1456,29 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
return unode;
}
+static bool sculpt_attribute_ref_equals(SculptAttrRef *a, SculptAttrRef *b)
+{
+ return a->domain == b->domain && a->type == b->type && STREQ(a->name, b->name);
+}
+
+static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr)
+{
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ CustomDataLayer *layer;
+
+ if (ob && me && (layer = BKE_id_attributes_active_color_get((ID *)me))) {
+ attr->domain = BKE_id_attribute_domain((ID *)me, layer);
+ BLI_strncpy(attr->name, layer->name, sizeof(attr->name));
+ attr->type = layer->type;
+ }
+ else {
+ attr->domain = NO_ACTIVE_LAYER;
+ attr->name[0] = 0;
+ }
+
+ attr->was_set = true;
+}
+
void SCULPT_undo_push_begin(Object *ob, const char *name)
{
UndoStack *ustack = ED_undo_stack_get();
@@ -1376,15 +1493,28 @@ void SCULPT_undo_push_begin(Object *ob, const char *name)
/* Special case, we never read from this. */
bContext *C = NULL;
- BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_SCULPT);
+ SculptUndoStep *us = (SculptUndoStep *)BKE_undosys_step_push_init_with_type(
+ ustack, C, name, BKE_UNDOSYS_TYPE_SCULPT);
+
+ if (!us->active_color_start.was_set) {
+ sculpt_save_active_attribute(ob, &us->active_color_start);
+ }
+
+ /* Set end attribute in case SCULPT_undo_push_end is not called,
+ * so we don't end up with corrupted state.
+ */
+ if (!us->active_color_end.was_set) {
+ sculpt_save_active_attribute(ob, &us->active_color_end);
+ us->active_color_end.was_set = false;
+ }
}
-void SCULPT_undo_push_end(void)
+void SCULPT_undo_push_end(Object *ob)
{
- SCULPT_undo_push_end_ex(false);
+ SCULPT_undo_push_end_ex(ob, false);
}
-void SCULPT_undo_push_end_ex(const bool use_nested_undo)
+void SCULPT_undo_push_end_ex(struct Object *ob, const bool use_nested_undo)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptUndoNode *unode;
@@ -1408,17 +1538,54 @@ void SCULPT_undo_push_end_ex(const bool use_nested_undo)
}
WM_file_tag_modified();
}
+
+ UndoStack *ustack = ED_undo_stack_get();
+ SculptUndoStep *us = (SculptUndoStep *)BKE_undosys_stack_init_or_active_with_type(
+ ustack, BKE_UNDOSYS_TYPE_SCULPT);
+
+ sculpt_save_active_attribute(ob, &us->active_color_end);
}
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
* \{ */
-typedef struct SculptUndoStep {
- UndoStep step;
- /* NOTE: will split out into list for multi-object-sculpt-mode. */
- UndoSculpt data;
-} SculptUndoStep;
+static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr)
+{
+ if (attr->domain == ATTR_DOMAIN_AUTO) {
+ return;
+ }
+
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = BKE_object_get_original_mesh(ob);
+
+ SculptAttrRef existing;
+ sculpt_save_active_attribute(ob, &existing);
+
+ CustomDataLayer *layer;
+ 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;
+ int totelem = attr->domain == ATTR_DOMAIN_POINT ? me->totvert : me->totloop;
+
+ CustomData_add_layer_named(cdata, attr->type, CD_DEFAULT, NULL, totelem, attr->name);
+ layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
+ }
+
+ if (layer) {
+ BKE_id_attributes_active_color_set(&me->id, layer);
+
+ if (ob->sculpt && ob->sculpt->pbvh) {
+ BKE_pbvh_update_active_vcol(ob->sculpt->pbvh, me);
+
+ if (!sculpt_attribute_ref_equals(&existing, attr)) {
+ BKE_pbvh_update_vertex_data(ob->sculpt->pbvh, PBVH_UpdateColor);
+ }
+ }
+ }
+}
static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
{
@@ -1454,6 +1621,7 @@ static void sculpt_undosys_step_decode_undo_impl(struct bContext *C,
SculptUndoStep *us)
{
BLI_assert(us->step.is_applied == true);
+
sculpt_undo_restore_list(C, depsgraph, &us->data.nodes);
us->step.is_applied = false;
}
@@ -1463,6 +1631,7 @@ static void sculpt_undosys_step_decode_redo_impl(struct bContext *C,
SculptUndoStep *us)
{
BLI_assert(us->step.is_applied == false);
+
sculpt_undo_restore_list(C, depsgraph, &us->data.nodes);
us->step.is_applied = true;
}
@@ -1484,10 +1653,17 @@ static void sculpt_undosys_step_decode_undo(struct bContext *C,
while ((us_iter != us) || (!is_final && us_iter == us)) {
BLI_assert(us_iter->step.type == us->step.type); /* Previous loop ensures this. */
+
+ sculpt_undo_set_active_layer(C, &((SculptUndoStep *)us_iter)->active_color_start);
sculpt_undosys_step_decode_undo_impl(C, depsgraph, us_iter);
+
if (us_iter == us) {
+ if (us_iter->step.prev && us_iter->step.prev->type == BKE_UNDOSYS_TYPE_SCULPT) {
+ sculpt_undo_set_active_layer(C, &((SculptUndoStep *)us_iter->step.prev)->active_color_end);
+ }
break;
}
+
us_iter = (SculptUndoStep *)us_iter->step.prev;
}
}
@@ -1504,8 +1680,11 @@ static void sculpt_undosys_step_decode_redo(struct bContext *C,
us_iter = (SculptUndoStep *)us_iter->step.prev;
}
while (us_iter && (us_iter->step.is_applied == false)) {
+ sculpt_undo_set_active_layer(C, &((SculptUndoStep *)us_iter)->active_color_start);
sculpt_undosys_step_decode_redo_impl(C, depsgraph, us_iter);
+
if (us_iter == us) {
+ sculpt_undo_set_active_layer(C, &((SculptUndoStep *)us_iter)->active_color_end);
break;
}
us_iter = (SculptUndoStep *)us_iter->step.next;
@@ -1526,7 +1705,7 @@ static void sculpt_undosys_step_decode(
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
if (ob && (ob->type == OB_MESH)) {
- if (ob->mode & OB_MODE_SCULPT) {
+ if (ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT)) {
/* Pass. */
}
else {
@@ -1579,7 +1758,7 @@ void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name)
void ED_sculpt_undo_geometry_end(struct Object *ob)
{
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_GEOMETRY);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
}
void ED_sculpt_undosys_type(UndoType *ut)
@@ -1705,7 +1884,7 @@ void ED_sculpt_undo_push_multires_mesh_end(bContext *C, const char *str)
SculptUndoNode *geometry_unode = SCULPT_undo_push_node(object, NULL, SCULPT_UNDO_GEOMETRY);
geometry_unode->geometry_clear_pbvh = false;
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(object);
}
/** \} */