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:
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c75
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c13
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c18
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h32
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_init.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c43
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c128
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c235
20 files changed, 473 insertions, 134 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 57d4bd67438..944b3f953a0 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -376,7 +376,7 @@ static int hide_show_exec(bContext *C, wmOperator *op)
}
/* End undo. */
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
/* Ensure that edges and faces get hidden as well (not used by
* sculpt but it looks wrong when entering editmode otherwise). */
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 5e89a4823db..5929aa75b45 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -173,7 +173,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
if (nodes) {
MEM_freeN(nodes);
@@ -707,7 +707,8 @@ static void sculpt_gesture_apply(bContext *C, SculptGestureContext *sgcontext)
operation->sculpt_gesture_end(C, sgcontext);
- SCULPT_undo_push_end();
+ Object *ob = CTX_data_active_object(C);
+ SCULPT_undo_push_end(ob);
SCULPT_tag_update_overlays(C);
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 3f0f97dffd2..33b92c22d3f 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -27,6 +27,7 @@
#include "RNA_access.h"
+#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -190,7 +191,14 @@ bool vertex_paint_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly;
+ if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly)) {
+ return false;
+ }
+
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)ob->data);
+ AttributeDomain domain = BKE_id_attribute_domain((ID *)ob->data, layer);
+
+ return layer && layer->type == CD_MLOOPCOL && domain == ATTR_DOMAIN_CORNER;
}
static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
@@ -3559,7 +3567,7 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot)
/* identifiers */
ot->name = "Vertex Paint";
ot->idname = "PAINT_OT_vertex_paint";
- ot->description = "Paint a stroke in the active vertex color layer";
+ ot->description = "Paint a stroke in the active color attribute layer";
/* api callbacks */
ot->invoke = vpaint_invoke;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index e82ac058281..e03f12025c8 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -31,6 +31,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_colortools.h"
@@ -143,19 +144,27 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
return NULL;
}
-const float *SCULPT_vertex_color_get(SculptSession *ss, int index)
+bool SCULPT_has_loop_colors(const Object *ob)
{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- if (ss->vcol) {
- return ss->vcol[index].color;
- }
- break;
- case PBVH_BMESH:
- case PBVH_GRIDS:
- break;
- }
- return NULL;
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+
+ return layer && BKE_id_attribute_domain(&me->id, layer) == ATTR_DOMAIN_CORNER;
+}
+
+bool SCULPT_has_colors(const SculptSession *ss)
+{
+ return ss->vcol || ss->mcol;
+}
+
+void SCULPT_vertex_color_get(const SculptSession *ss, int index, float r_color[4])
+{
+ BKE_pbvh_vertex_color_get(ss->pbvh, index, r_color);
+}
+
+void SCULPT_vertex_color_set(SculptSession *ss, int index, const float color[4])
+{
+ BKE_pbvh_vertex_color_set(ss->pbvh, index, color);
}
void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
@@ -1045,6 +1054,7 @@ void SCULPT_tag_update_overlays(bContext *C)
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+
View3D *v3d = CTX_wm_view3d(C);
if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -1378,7 +1388,7 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
*vd.mask = orig_data.mask;
}
else if (orig_data.unode->type == SCULPT_UNDO_COLOR) {
- copy_v4_v4(vd.col, orig_data.col);
+ SCULPT_vertex_color_set(ss, vd.index, orig_data.col);
}
if (vd.mvert) {
@@ -3149,7 +3159,7 @@ static void do_brush_action_task_cb(void *__restrict userdata,
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
BKE_pbvh_node_mark_update_mask(data->nodes[n]);
}
- else if (ELEM(data->brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) {
+ else if (SCULPT_TOOL_NEEDS_COLOR(data->brush->sculpt_tool)) {
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
BKE_pbvh_node_mark_update_color(data->nodes[n]);
}
@@ -3167,12 +3177,13 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Check for unsupported features. */
PBVHType type = BKE_pbvh_type(ss->pbvh);
- if (brush->sculpt_tool == SCULPT_TOOL_PAINT && type != PBVH_FACES) {
- return;
- }
- if (brush->sculpt_tool == SCULPT_TOOL_SMEAR && type != PBVH_FACES) {
- return;
+ if (SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool) && SCULPT_has_loop_colors(ob)) {
+ if (type != PBVH_FACES) {
+ return;
+ }
+
+ BKE_pbvh_ensure_node_loops(ss->pbvh);
}
/* Build a list of all nodes that are potentially within the brush's area of influence */
@@ -3188,6 +3199,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
ss->cache->original;
float radius_scale = 1.0f;
+
/* With these options enabled not all required nodes are inside the original brush radius, so
* the brush can produce artifacts in some situations. */
if (brush->sculpt_tool == SCULPT_TOOL_DRAW && brush->flag & BRUSH_ORIGINAL_NORMAL) {
@@ -3849,10 +3861,12 @@ bool SCULPT_mode_poll(bContext *C)
bool SCULPT_vertex_colors_poll(bContext *C)
{
- if (!U.experimental.use_sculpt_vertex_colors) {
+ if (!SCULPT_mode_poll(C)) {
return false;
}
- return SCULPT_mode_poll(C);
+
+ Object *ob = CTX_data_active_object(C);
+ return ob->sculpt && SCULPT_has_colors(ob->sculpt);
}
bool SCULPT_mode_poll_view3d(bContext *C)
@@ -4591,6 +4605,7 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd,
(brush->sculpt_tool == SCULPT_TOOL_POSE) ||
(brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) ||
(brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) ||
+ SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool) ||
(brush->sculpt_tool == SCULPT_TOOL_CLOTH) || (brush->sculpt_tool == SCULPT_TOOL_SMEAR) ||
(brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) ||
(brush->sculpt_tool == SCULPT_TOOL_DISPLACEMENT_SMEAR));
@@ -4950,7 +4965,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
SculptSession *ss = CTX_data_active_object(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
int mode = RNA_enum_get(op->ptr, "mode");
- bool is_smooth, needs_colors;
+ bool need_pmap, needs_colors;
bool need_mask = false;
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
@@ -4965,8 +4980,8 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
view3d_operator_needs_opengl(C);
sculpt_brush_init_tex(scene, sd, ss);
- is_smooth = sculpt_needs_connectivity_info(sd, brush, ss, mode);
- needs_colors = ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR);
+ need_pmap = sculpt_needs_connectivity_info(sd, brush, ss, mode);
+ needs_colors = SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool);
if (needs_colors) {
BKE_sculpt_color_layer_create_if_needed(ob);
@@ -4975,7 +4990,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
/* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
* earlier steps modifying the data. */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask, needs_colors);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, need_mask, needs_colors);
}
static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
@@ -5174,6 +5189,14 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (brush && SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool)) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d) {
+ v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
+ }
+ }
ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
@@ -5302,7 +5325,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
SCULPT_cache_free(ss->cache);
ss->cache = NULL;
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index a4cfb611138..dcf90f9e819 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -1493,7 +1493,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
SCULPT_filter_cache_free(ss);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index dd8921d575f..fe69cf6b84f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -117,7 +117,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
}
MEM_SAFE_FREE(nodes);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
/* Force rebuild of PBVH for better BB placement. */
SCULPT_pbvh_clear(ob);
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
index 58da5adc5e3..4f884420401 100644
--- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -274,7 +274,7 @@ void sculpt_dynamic_topology_disable_with_undo(Main *bmain,
}
SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, NULL);
if (use_undo) {
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
}
}
}
@@ -294,7 +294,7 @@ static void sculpt_dynamic_topology_enable_with_undo(Main *bmain,
SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
if (use_undo) {
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
}
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index 2ef35d540b9..46940b619e6 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -1128,7 +1128,7 @@ static void sculpt_expand_restore_color_data(SculptSession *ss, ExpandCache *exp
PBVHNode *node = nodes[n];
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
- copy_v4_v4(vd.col, expand_cache->original_colors[vd.index]);
+ SCULPT_vertex_color_set(ss, vd.index, expand_cache->original_colors[vd.index]);
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_redraw(node);
@@ -1192,7 +1192,7 @@ static void sculpt_expand_cancel(bContext *C, wmOperator *UNUSED(op))
sculpt_expand_restore_original_state(C, ob, ss->expand_cache);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
sculpt_expand_cache_free(ss);
}
@@ -1287,7 +1287,7 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
float initial_color[4];
- copy_v4_v4(initial_color, vd.col);
+ SCULPT_vertex_color_get(ss, vd.index, initial_color);
const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index);
float fade;
@@ -1314,7 +1314,8 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata,
continue;
}
- copy_v4_v4(vd.col, final_color);
+ SCULPT_vertex_color_set(ss, vd.index, final_color);
+
any_changed = true;
if (vd.mvert) {
BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
@@ -1370,7 +1371,7 @@ static void sculpt_expand_original_state_store(Object *ob, ExpandCache *expand_c
if (expand_cache->target == SCULPT_EXPAND_TARGET_COLORS) {
expand_cache->original_colors = MEM_malloc_arrayN(totvert, sizeof(float[4]), "initial colors");
for (int i = 0; i < totvert; i++) {
- copy_v4_v4(expand_cache->original_colors[i], SCULPT_vertex_color_get(ss, i));
+ SCULPT_vertex_color_get(ss, i, expand_cache->original_colors[i]);
}
}
}
@@ -1526,7 +1527,7 @@ static void sculpt_expand_finish(bContext *C)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
/* Tag all nodes to redraw to avoid artifacts after the fast partial updates. */
PBVHNode **nodes;
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 23bc9fbb54d..7171c241534 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -398,7 +398,7 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
MEM_SAFE_FREE(nodes);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
SCULPT_tag_update_overlays(C);
@@ -737,7 +737,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
break;
}
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
/* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
SCULPT_visibility_sync_all_face_sets_to_vertices(ob);
@@ -927,7 +927,7 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
/* Sync face sets visibility and vertex visibility. */
SCULPT_visibility_sync_all_face_sets_to_vertices(ob);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
for (int i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_update_visibility(nodes[i]);
@@ -1354,7 +1354,7 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob,
SCULPT_undo_push_begin(ob, "face set edit");
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
face_set_edit_do_post_visibility_updates(ob, nodes, totnode);
MEM_freeN(nodes);
}
@@ -1382,7 +1382,7 @@ static void sculpt_face_set_edit_modify_coordinates(bContext *C,
}
SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
MEM_freeN(nodes);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 377f1e0ed32..cbb9180a209 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -181,12 +181,16 @@ static void color_filter_task_cb(void *__restrict userdata,
fade = clamp_f(fade, -1.0f, 1.0f);
float smooth_color[4];
SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
- blend_color_interpolate_float(final_color, vd.col, smooth_color, fade);
+
+ float col[4];
+ SCULPT_vertex_color_get(ss, vd.index, col);
+
+ blend_color_interpolate_float(final_color, col, smooth_color, fade);
break;
}
}
- copy_v3_v3(vd.col, final_color);
+ SCULPT_vertex_color_set(ss, vd.index, final_color);
if (vd.mvert) {
BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
@@ -205,7 +209,7 @@ static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent
float filter_strength = RNA_float_get(op->ptr, "strength");
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
SCULPT_filter_cache_free(ss);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COLOR);
return OPERATOR_FINISHED;
@@ -247,7 +251,6 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
Object *ob = CTX_data_active_object(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = ob->sculpt;
- int mode = RNA_enum_get(op->ptr, "type");
PBVH *pbvh = ob->sculpt->pbvh;
const bool use_automasking = SCULPT_is_automasking_enabled(sd, ss, NULL);
@@ -269,7 +272,7 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
- if (!ss->vcol) {
+ if (!SCULPT_has_colors(ss)) {
return OPERATOR_CANCELLED;
}
@@ -280,10 +283,9 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
/* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
* earlier steps modifying the data. */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- const bool needs_topology_info = mode == COLOR_FILTER_SMOOTH || use_automasking;
- BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_topology_info, false, true);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true);
- if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_topology_info && !ob->sculpt->pmap) {
+ if (BKE_pbvh_type(pbvh) == PBVH_FACES && !ob->sculpt->pmap) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index e88265714b8..c8137301de5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -239,7 +239,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
MEM_SAFE_FREE(nodes);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
SCULPT_tag_update_overlays(C);
@@ -447,7 +447,7 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
ED_region_tag_redraw(region);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index b73e182fcab..4b832256dae 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -110,6 +110,10 @@ void SCULPT_filter_cache_init(bContext *C, Object *ob, Sculpt *sd, const int und
ss->filter_cache->random_seed = rand();
+ if (undo_type == SCULPT_UNDO_COLOR) {
+ BKE_pbvh_ensure_node_loops(ss->pbvh);
+ }
+
const float center[3] = {0.0f};
SculptSearchSphereData search_data = {
.original = true,
@@ -597,7 +601,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
SCULPT_filter_cache_free(ss);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 8cab0349356..73fc5bd68f3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -20,6 +20,10 @@
#include "BLI_gsqueue.h"
#include "BLI_threads.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AutomaskingCache;
struct KeyBlock;
struct Object;
@@ -139,9 +143,16 @@ typedef struct SculptUndoNode {
float *mask;
int totvert;
+ float (*loop_col)[4];
+ float (*orig_loop_col)[4];
+ int totloop;
+
/* non-multires */
int maxvert; /* to verify if totvert it still the same */
- int *index; /* to restore into right location */
+ int *index; /* Unique vertex indices, to restore into right location */
+ int maxloop;
+ int *loop_index;
+
BLI_bitmap *vert_hidden;
/* multires */
@@ -857,7 +868,14 @@ const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
-const float *SCULPT_vertex_color_get(SculptSession *ss, int index);
+void SCULPT_vertex_color_get(const SculptSession *ss, int index, float r_color[4]);
+void SCULPT_vertex_color_set(SculptSession *ss, int index, const float color[4]);
+
+/** Returns true if a color attribute exists in the current sculpt session. */
+bool SCULPT_has_colors(const SculptSession *ss);
+
+/** Returns true if the active color attribute is on loop (ATTR_DOMAIN_CORNER) domain. */
+bool SCULPT_has_loop_colors(const struct Object *ob);
const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
@@ -1416,8 +1434,8 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node);
SculptUndoNode *SCULPT_undo_get_first_node(void);
void SCULPT_undo_push_begin(struct Object *ob, const char *name);
-void SCULPT_undo_push_end(void);
-void SCULPT_undo_push_end_ex(bool use_nested_undo);
+void SCULPT_undo_push_end(struct Object *ob);
+void SCULPT_undo_push_end_ex(struct Object *ob, const bool use_nested_undo);
/** \} */
@@ -1720,3 +1738,9 @@ void SCULPT_bmesh_topology_rake(
void SCULPT_OT_brush_stroke(struct wmOperatorType *ot);
/* end sculpt_ops.c */
+
+#define SCULPT_TOOL_NEEDS_COLOR(tool) ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 8fc10061f83..201e02b8235 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -82,7 +82,7 @@ static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
}
SCULPT_filter_cache_free(ss);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
ED_workspace_status_text(C, NULL);
}
@@ -237,7 +237,7 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
SCULPT_filter_cache_free(ss);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
ED_workspace_status_text(C, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
index 42101988b11..025f34ab2d7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_init.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
@@ -150,7 +150,7 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
multires_stitch_grids(ob);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
MEM_SAFE_FREE(nodes);
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index cd174681ccb..f84852d1d0e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -234,7 +234,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
/* Finish undo. */
BM_log_all_added(ss->bm, ss->bm_log);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
break;
case PBVH_FACES:
@@ -396,7 +396,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
if (has_undo) {
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
}
}
else {
@@ -508,6 +508,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
if (wm->op_undo_depth <= 1) {
SCULPT_undo_push_begin(ob, op->type->name);
+ SCULPT_undo_push_end(ob);
}
}
}
@@ -749,11 +750,14 @@ static int sculpt_sample_color_invoke(bContext *C,
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
int active_vertex = SCULPT_active_vertex_get(ss);
- const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
- if (!active_vertex_color) {
+ float active_vertex_color[4];
+
+ if (!SCULPT_has_colors(ss)) {
return OPERATOR_CANCELLED;
}
+ SCULPT_vertex_color_get(ss, active_vertex, active_vertex_color);
+
float color_srgb[3];
copy_v3_v3(color_srgb, active_vertex_color);
IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
@@ -862,7 +866,7 @@ static void do_mask_by_color_contiguous_update_nodes_cb(
}
BKE_pbvh_vertex_iter_end;
if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ BKE_pbvh_node_mark_update_mask(data->nodes[n]);
}
}
@@ -870,7 +874,10 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
{
MaskByColorContiguousFloodFillData *data = userdata;
- const float *current_color = SCULPT_vertex_color_get(ss, to_v);
+ float current_color[4];
+
+ SCULPT_vertex_color_get(ss, to_v, current_color);
+
float new_vertex_mask = sculpt_mask_by_color_delta_get(
current_color, data->initial_color, data->threshold, data->invert);
data->new_mask[to_v] = new_vertex_mask;
@@ -909,7 +916,11 @@ static void sculpt_mask_by_color_contiguous(Object *object,
ffd.threshold = threshold;
ffd.invert = invert;
ffd.new_mask = new_mask;
- copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex));
+
+ float color[4];
+ SCULPT_vertex_color_get(ss, vertex, color);
+
+ copy_v3_v3(ffd.initial_color, color);
SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd);
SCULPT_floodfill_free(&flood);
@@ -951,12 +962,17 @@ static void do_mask_by_color_task_cb(void *__restrict userdata,
const float threshold = data->mask_by_color_threshold;
const bool invert = data->mask_by_color_invert;
const bool preserve_mask = data->mask_by_color_preserve_mask;
- const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
+ float active_color[4];
+
+ SCULPT_vertex_color_get(ss, data->mask_by_color_vertex, active_color);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ float col[4];
+ SCULPT_vertex_color_get(ss, vd.index, col);
+
const float current_mask = *vd.mask;
- const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
+ const float new_mask = sculpt_mask_by_color_delta_get(active_color, col, threshold, invert);
*vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
if (current_mask == *vd.mask) {
@@ -1014,10 +1030,14 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
return OPERATOR_CANCELLED;
}
- if (!ss->vcol) {
+ if (!SCULPT_has_colors(ss)) {
return OPERATOR_CANCELLED;
}
+ if (SCULPT_has_loop_colors(ob)) {
+ BKE_pbvh_ensure_node_loops(ss->pbvh);
+ }
+
SCULPT_vertex_random_access_ensure(ss);
/* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
@@ -1043,9 +1063,10 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
}
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
- SCULPT_undo_push_end();
+ SCULPT_undo_push_end(ob);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index 5d248cb520a..cc4392c6a8a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -85,7 +85,11 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
float smooth_color[4];
SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
- blend_color_interpolate_float(vd.col, vd.col, smooth_color, fade);
+ float col[4];
+
+ SCULPT_vertex_color_get(ss, vd.index, col);
+ blend_color_interpolate_float(col, col, smooth_color, fade);
+ SCULPT_vertex_color_set(ss, vd.index, col);
if (vd.mvert) {
BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
@@ -154,7 +158,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
float noise = 1.0f;
const float density = ss->cache->paint_brush.density;
if (density < 1.0f) {
- const float hash_noise = BLI_hash_int_01(ss->cache->density_seed * 1000 * vd.index);
+ const float hash_noise = (float) BLI_hash_int_01(ss->cache->density_seed * 1000 * vd.index);
if (hash_noise > density) {
noise = density * hash_noise;
fade = fade * noise;
@@ -177,9 +181,11 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
/* Final mix over the original color using brush alpha. */
mul_v4_v4fl(buffer_color, color_buffer->color[vd.i], brush->alpha);
- IMB_blend_color_float(vd.col, orig_data.col, buffer_color, brush->blend);
-
- CLAMP4(vd.col, 0.0f, 1.0f);
+ float col[4];
+ SCULPT_vertex_color_get(ss, vd.index, col);
+ IMB_blend_color_float(col, orig_data.col, buffer_color, brush->blend);
+ CLAMP4(col, 0.0f, 1.0f);
+ SCULPT_vertex_color_set(ss, vd.index, col);
if (vd.mvert) {
BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
@@ -214,7 +220,10 @@ static void do_sample_wet_paint_task_cb(void *__restrict userdata,
continue;
}
- add_v4_v4(swptd->color, vd.col);
+ float col[4];
+ SCULPT_vertex_color_get(ss, vd.index, col);
+
+ add_v4_v4(swptd->color, col);
swptd->tot_samples++;
}
BKE_pbvh_vertex_iter_end;
@@ -236,13 +245,13 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- if (!ss->vcol) {
+ if (!SCULPT_has_colors(ss)) {
return;
}
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
- ss->cache->density_seed = BLI_hash_int_01(ss->cache->location[0] * 1000);
+ ss->cache->density_seed = (float) BLI_hash_int_01(ss->cache->location[0] * 1000);
}
return;
}
@@ -384,6 +393,9 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
float interp_color[4];
copy_v4_v4(interp_color, ss->cache->prev_colors[vd.index]);
+ float no[3];
+ SCULPT_vertex_normal_get(ss, vd.index, no);
+
switch (brush->smear_deform_type) {
case BRUSH_SMEAR_DEFORM_DRAG:
sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
@@ -395,29 +407,89 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
break;
}
+
+ /* Project into vertex plane. */
+ madd_v3_v3fl(current_disp, no, -dot_v3v3(current_disp, no));
+
normalize_v3_v3(current_disp_norm, current_disp);
mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- float vertex_disp[3];
- float vertex_disp_norm[3];
- sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
- const float *neighbor_color = ss->cache->prev_colors[ni.index];
- normalize_v3_v3(vertex_disp_norm, vertex_disp);
- if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
- continue;
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float totw = 0.0f;
+
+ /*
+ * NOTE: we have to do a nested iteration here to avoid
+ * blocky artifacts on quad topologies. The runtime cost
+ * is not as bad as it seems due to neighbor iteration
+ * in the sculpt code being cache bound; once the data is in
+ * the cache iterating over it a few more times is not terribly
+ * costly.
+ */
+
+ SculptVertexNeighborIter ni2;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni2) {
+ const float *nco = SCULPT_vertex_co_get(ss, ni2.index);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, ni2.index, ni) {
+ if (ni.index == vd.index) {
+ continue;
+ }
+
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+
+ sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
+
+ /* Weight by how close we are to our target distance from vd.co. */
+ float w = (1.0f + fabsf(len_v3(vertex_disp) / ss->cache->bstrength - 1.0f));
+
+ /* TODO: use cotangents (or at least face areas) here. */
+ float len = len_v3v3(SCULPT_vertex_co_get(ss, ni.index), nco);
+ if (len > 0.0f) {
+ len = ss->cache->bstrength / len;
+ }
+ else { /* Coincident point. */
+ len = 1.0f;
+ }
+
+ /* Multiply weight with edge lengths (in the future this will be
+ cotangent weights or face areas). */
+ w *= len;
+
+ /* Build directional weight. */
+
+ /* Project into vertex plane. */
+ madd_v3_v3fl(vertex_disp, no, -dot_v3v3(no, vertex_disp));
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
+ continue;
+ }
+
+ const float *neighbor_color = ss->cache->prev_colors[ni.index];
+ float color_interp = -dot_v3v3(current_disp_norm, vertex_disp_norm);
+
+ /* Square directional weight to get a somewhat sharper result. */
+ w *= color_interp * color_interp;
+
+ madd_v4_v4fl(accum, neighbor_color, w);
+ totw += w;
}
- const float color_interp = clamp_f(
- -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
- float color_mix[4];
- copy_v4_v4(color_mix, neighbor_color);
- mul_v4_fl(color_mix, color_interp * fade);
- blend_color_mix_float(interp_color, interp_color, color_mix);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni2);
+
+ if (totw != 0.0f) {
+ mul_v4_fl(accum, 1.0f / totw);
+ }
+
+ blend_color_mix_float(interp_color, interp_color, accum);
- blend_color_interpolate_float(vd.col, ss->cache->prev_colors[vd.index], interp_color, fade);
+ float col[4];
+ SCULPT_vertex_color_get(ss, vd.index, col);
+ blend_color_interpolate_float(col, ss->cache->prev_colors[vd.index], interp_color, fade);
+ SCULPT_vertex_color_set(ss, vd.index, col);
if (vd.mvert) {
BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
@@ -435,7 +507,7 @@ static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.index));
+ SCULPT_vertex_color_get(ss, vd.index, ss->cache->prev_colors[vd.index]);
}
BKE_pbvh_vertex_iter_end;
}
@@ -445,7 +517,7 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- if (!ss->vcol) {
+ if (!SCULPT_has_colors(ss)) {
return;
}
@@ -455,7 +527,7 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
if (!ss->cache->prev_colors) {
ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
for (int i = 0; i < totvert; i++) {
- copy_v4_v4(ss->cache->prev_colors[i], SCULPT_vertex_color_get(ss, i));
+ SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]);
}
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 482bdf97d78..53babc3d36d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -179,7 +179,11 @@ void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
- add_v4_v4(avg, SCULPT_vertex_color_get(ss, ni.index));
+ float tmp[4] = {0};
+
+ SCULPT_vertex_color_get(ss, ni.index, tmp);
+
+ add_v4_v4(avg, tmp);
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -188,7 +192,7 @@ void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index
mul_v4_v4fl(result, avg, 1.0f / total);
}
else {
- copy_v4_v4(result, SCULPT_vertex_color_get(ss, index));
+ SCULPT_vertex_color_get(ss, index, result);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index 5f55546c8a0..b3616254b26 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -203,7 +203,7 @@ void ED_sculpt_end_transform(struct bContext *C, Object *ob)
* undo system works separate from regular undo and this is require to properly
* finish an undo step also when canceling. */
const bool use_nested_undo = true;
- SCULPT_undo_push_end_ex(use_nested_undo);
+ SCULPT_undo_push_end_ex(ob, use_nested_undo);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
}
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);
}
/** \} */