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
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')
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt4
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc213
-rw-r--r--source/blender/editors/geometry/geometry_intern.hh3
-rw-r--r--source/blender/editors/geometry/geometry_ops.cc3
-rw-r--r--source/blender/editors/include/UI_icons.h1
-rw-r--r--source/blender/editors/io/io_alembic.c2
-rw-r--r--source/blender/editors/io/io_usd.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c33
-rw-r--r--source/blender/editors/mesh/mesh_data.c4
-rw-r--r--source/blender/editors/object/object_bake_api.c6
-rw-r--r--source/blender/editors/object/object_data_transfer.c59
-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
31 files changed, 779 insertions, 158 deletions
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index ebe61d217ed..8fca0c46c82 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -748,11 +748,13 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.mask
brush.sculpt.multiplane_scrape
brush.sculpt.nudge
+ brush.sculpt.paint
brush.sculpt.pinch
brush.sculpt.pose
brush.sculpt.rotate
brush.sculpt.scrape
brush.sculpt.simplify
+ brush.sculpt.smear
brush.sculpt.smooth
brush.sculpt.snake_hook
brush.sculpt.thumb
@@ -845,6 +847,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.sculpt.border_hide
ops.sculpt.border_mask
ops.sculpt.box_trim
+ ops.sculpt.color_filter
ops.sculpt.cloth_filter
ops.sculpt.face_set_edit
ops.sculpt.lasso_face_set
@@ -852,6 +855,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.sculpt.lasso_trim
ops.sculpt.line_mask
ops.sculpt.line_project
+ ops.sculpt.mask_by_color
ops.sculpt.mesh_filter
ops.sequencer.blade
ops.transform.bone_envelope
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index 5d9d02db660..75094b46c8b 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -16,6 +16,7 @@
#include "BKE_deform.h"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
@@ -103,6 +104,35 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static void next_color_attribute(struct ID *id, CustomDataLayer *layer, bool is_render)
+{
+ int index = BKE_id_attribute_to_index(id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ index++;
+
+ layer = BKE_id_attribute_from_index(id, index, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ if (!layer) {
+ index = 0;
+ layer = BKE_id_attribute_from_index(id, index, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+ }
+
+ if (layer) {
+ if (is_render) {
+ BKE_id_attributes_active_color_set(id, layer);
+ }
+ else {
+ BKE_id_attributes_render_color_set(id, layer);
+ }
+ }
+}
+
+static void next_color_attributes(struct ID *id, CustomDataLayer *layer)
+{
+ next_color_attribute(id, layer, false); /* active */
+ next_color_attribute(id, layer, true); /* render */
+}
+
void GEOMETRY_OT_attribute_add(wmOperatorType *ot)
{
/* identifiers */
@@ -148,9 +178,7 @@ static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
ID *id = static_cast<ID *>(ob->data);
CustomDataLayer *layer = BKE_id_attributes_active_get(id);
- if (layer == nullptr) {
- return OPERATOR_CANCELLED;
- }
+ next_color_attributes(id, layer);
if (!BKE_id_attribute_remove(id, layer, op->reports)) {
return OPERATOR_CANCELLED;
@@ -182,6 +210,33 @@ void GEOMETRY_OT_attribute_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static int geometry_color_attribute_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+
+ char name[MAX_NAME];
+ RNA_string_get(op->ptr, "name", name);
+ CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type");
+ AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain");
+ CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_id_attributes_active_color_set(id, layer);
+
+ if (!BKE_id_attributes_render_color_get(id)) {
+ BKE_id_attributes_render_color_set(id, layer);
+ }
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
enum class ConvertAttributeMode {
Generic,
UVMap,
@@ -304,6 +359,156 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+void GEOMETRY_OT_color_attribute_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Geometry Attribute";
+ ot->description = "Add attribute to geometry";
+ ot->idname = "GEOMETRY_OT_color_attribute_add";
+
+ /* api callbacks */
+ ot->poll = geometry_attributes_poll;
+ ot->exec = geometry_color_attribute_add_exec;
+ ot->invoke = WM_operator_props_popup_confirm;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", "Color", MAX_NAME, "Name", "Name of color attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ static EnumPropertyItem domains[3] = {{ATTR_DOMAIN_POINT, "POINT", 0, "Point", ""},
+ {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""},
+ {0, nullptr, 0, nullptr, nullptr}};
+
+ static EnumPropertyItem types[3] = {{CD_PROP_COLOR, "COLOR", 0, "Color", ""},
+ {CD_MLOOPCOL, "BYTE_COLOR", 0, "Byte Color", ""},
+ {0, nullptr, 0, nullptr, nullptr}};
+
+ prop = RNA_def_enum(ot->srna,
+ "domain",
+ domains,
+ ATTR_DOMAIN_POINT,
+ "Domain",
+ "Type of element that attribute is stored on");
+
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "data_type",
+ types,
+ CD_PROP_COLOR,
+ "Data Type",
+ "Type of data stored in attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+static int geometry_color_attribute_set_render_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+
+ char name[MAX_NAME];
+ RNA_string_get(op->ptr, "name", name);
+
+ CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT);
+ layer = !layer ? BKE_id_attribute_find(id, name, CD_MLOOPCOL, ATTR_DOMAIN_POINT) : layer;
+ layer = !layer ? BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER) : layer;
+ layer = !layer ? BKE_id_attribute_find(id, name, CD_MLOOPCOL, ATTR_DOMAIN_CORNER) : layer;
+
+ if (layer) {
+ BKE_id_attributes_render_color_set(id, layer);
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void GEOMETRY_OT_color_attribute_render_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Render Color Attribute";
+ ot->description = "Set default color attribute used for rendering";
+ ot->idname = "GEOMETRY_OT_color_attribute_render_set";
+
+ /* api callbacks */
+ ot->poll = geometry_attributes_poll;
+ ot->exec = geometry_color_attribute_set_render_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", "Color", MAX_NAME, "Name", "Name of color attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+static int geometry_color_attribute_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ next_color_attributes(id, layer);
+
+ if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (GS(id->name) == ID_ME) {
+ Mesh *me = static_cast<Mesh *>(ob->data);
+ BKE_mesh_update_customdata_pointers(me, true);
+ }
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool geometry_color_attributes_remove_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = ob ? static_cast<ID *>(ob->data) : nullptr;
+
+ if (BKE_id_attributes_active_color_get(data) != nullptr) {
+ return true;
+ }
+
+ return false;
+}
+void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Color Attribute";
+ ot->description = "Remove color attribute from geometry";
+ ot->idname = "GEOMETRY_OT_color_attribute_remove";
+
+ /* api callbacks */
+ ot->exec = geometry_color_attribute_remove_exec;
+ ot->poll = geometry_color_attributes_remove_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
@@ -345,7 +550,7 @@ void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
{int(ConvertAttributeMode::Generic), "GENERIC", 0, "Generic", ""},
{int(ConvertAttributeMode::UVMap), "UV_MAP", 0, "UV Map", ""},
{int(ConvertAttributeMode::VertexGroup), "VERTEX_GROUP", 0, "Vertex Group", ""},
- {int(ConvertAttributeMode::VertexColor), "VERTEX_COLOR", 0, "Vertex Color", ""},
+ {int(ConvertAttributeMode::VertexColor), "VERTEX_COLOR", 0, "Color Attribute", ""},
{0, nullptr, 0, nullptr, nullptr},
};
diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh
index fe56bea9f43..bbcb682d6bf 100644
--- a/source/blender/editors/geometry/geometry_intern.hh
+++ b/source/blender/editors/geometry/geometry_intern.hh
@@ -14,6 +14,9 @@ namespace blender::ed::geometry {
/* *** geometry_attributes.cc *** */
void GEOMETRY_OT_attribute_add(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot);
+void GEOMETRY_OT_color_attribute_add(struct wmOperatorType *ot);
+void GEOMETRY_OT_color_attribute_remove(struct wmOperatorType *ot);
+void GEOMETRY_OT_color_attribute_render_set(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot);
} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc
index a87b09f8ff3..23f6e6f29f4 100644
--- a/source/blender/editors/geometry/geometry_ops.cc
+++ b/source/blender/editors/geometry/geometry_ops.cc
@@ -19,5 +19,8 @@ void ED_operatortypes_geometry(void)
WM_operatortype_append(GEOMETRY_OT_attribute_add);
WM_operatortype_append(GEOMETRY_OT_attribute_remove);
+ WM_operatortype_append(GEOMETRY_OT_color_attribute_add);
+ WM_operatortype_append(GEOMETRY_OT_color_attribute_remove);
+ WM_operatortype_append(GEOMETRY_OT_color_attribute_render_set);
WM_operatortype_append(GEOMETRY_OT_attribute_convert);
}
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 94232a5108d..d1a6501408c 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -903,6 +903,7 @@ DEF_ICON_COLOR(BRUSH_TEXFILL)
DEF_ICON_COLOR(BRUSH_TEXMASK)
DEF_ICON_COLOR(BRUSH_THUMB)
DEF_ICON_COLOR(BRUSH_ROTATE)
+DEF_ICON_COLOR(BRUSH_PAINT)
/* grease pencil sculpt */
DEF_ICON_COLOR(GPBRUSH_SMOOTH)
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index c9421d9aace..fd454083653 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -374,7 +374,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "normals", 1, "Normals", "Export normals");
- RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex Colors", "Export vertex colors");
+ RNA_def_boolean(ot->srna, "vcolors", 0, "Color Attributes", "Export color attributes");
RNA_def_boolean(ot->srna,
"orcos",
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index cf28c88edf0..51181f7caaa 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -524,7 +524,7 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
RNA_def_boolean(ot->srna, "read_mesh_uvs", true, "UV Coordinates", "Read mesh UV coordinates");
- RNA_def_boolean(ot->srna, "read_mesh_colors", false, "Vertex Colors", "Read mesh vertex colors");
+ RNA_def_boolean(ot->srna, "read_mesh_colors", false, "Color Attributes", "Read mesh color attributes");
RNA_def_string(ot->srna,
"prim_path_mask",
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 0b2944657fd..5a0a2b7a09a 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -27,6 +27,7 @@
#include "BLI_sort_utils.h"
#include "BLI_string.h"
+#include "BKE_attribute.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@@ -37,6 +38,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_texture.h"
@@ -726,7 +728,7 @@ void MESH_OT_edge_collapse(wmOperatorType *ot)
/* identifiers */
ot->name = "Collapse Edges & Faces";
ot->description =
- "Collapse isolated edge and face regions, merging data such as UV's and vertex colors. "
+ "Collapse isolated edge and face regions, merging data such as UV's and color attributes. "
"This can collapse edge-rings as well as regions of connected faces into vertices";
ot->idname = "MESH_OT_edge_collapse";
@@ -3090,7 +3092,22 @@ static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
BMOperator bmop;
- EDBM_op_init(em, &bmop, op, "rotate_colors faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+
+ if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
+ continue;
+ }
+
+ int color_index = BKE_id_attribute_to_index(
+ &me->id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+ EDBM_op_init(em,
+ &bmop,
+ op,
+ "rotate_colors faces=%hf use_ccw=%b color_index=%i",
+ BM_ELEM_SELECT,
+ use_ccw,
+ color_index);
BMO_op_exec(em->bm, &bmop);
@@ -3127,9 +3144,17 @@ static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
continue;
}
+ Mesh *me = BKE_object_get_original_mesh(obedit);
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+
+ if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
+ continue;
+ }
+
BMOperator bmop;
- EDBM_op_init(em, &bmop, op, "reverse_colors faces=%hf", BM_ELEM_SELECT);
+ int color_index = BKE_id_attribute_to_index(&me->id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+ EDBM_op_init(em, &bmop, op, "reverse_colors faces=%hf color_index=%i", BM_ELEM_SELECT, color_index);
BMO_op_exec(em->bm, &bmop);
@@ -3190,7 +3215,7 @@ void MESH_OT_colors_rotate(wmOperatorType *ot)
/* identifiers */
ot->name = "Rotate Colors";
ot->idname = "MESH_OT_colors_rotate";
- ot->description = "Rotate vertex colors inside faces";
+ ot->description = "Rotate color attributes inside faces";
/* api callbacks */
ot->exec = edbm_rotate_colors_exec;
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 630ef66504f..6f5c9d410c7 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -17,6 +17,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BKE_attribute.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
@@ -429,6 +430,9 @@ bool ED_mesh_color_ensure(struct Mesh *me, const char *name)
if (!me->mloopcol && me->totloop) {
CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name);
+ int layer_i = CustomData_get_layer_index(&me->ldata, CD_MLOOPCOL);
+
+ BKE_id_attributes_active_color_set(&me->id, me->ldata.layers + layer_i);
BKE_mesh_update_customdata_pointers(me, true);
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 44f05600d7d..fec87fbfa95 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -442,7 +442,7 @@ static bool bake_object_check(ViewLayer *view_layer,
if (target == R_BAKE_TARGET_VERTEX_COLORS) {
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL && U.experimental.use_sculpt_vertex_colors);
+ const bool mcol_valid = (mcol != NULL);
MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
if (mloopcol == NULL && !mcol_valid) {
BKE_reportf(reports,
@@ -926,7 +926,7 @@ static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, Re
Mesh *me = ob->data;
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL && U.experimental.use_sculpt_vertex_colors);
+ const bool mcol_valid = (mcol != NULL);
MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
if (mloopcol == NULL && !mcol_valid) {
BKE_report(reports, RPT_ERROR, "No vertex colors layer found to bake to");
@@ -1080,7 +1080,7 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
{
Mesh *me = ob->data;
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL && U.experimental.use_sculpt_vertex_colors);
+ const bool mcol_valid = (mcol != NULL);
MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
const int channels_num = targets->channels_num;
const float *result = targets->result;
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 6805c9144d6..3447ded5f68 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -72,7 +72,7 @@ static const EnumPropertyItem DT_layer_items[] = {
"Transfer Freestyle edge mark"},
{0, "", 0, "Face Corner Data", ""},
{DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
- {DT_TYPE_VCOL, "VCOL", 0, "Vertex Colors", "Vertex (face corners) colors"},
+ {DT_TYPE_MPROPCOL_LOOP | DT_TYPE_MLOOPCOL_LOOP, "VCOL", 0, "Colors", "Color Attributes"},
{DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
{0, "", 0, "Face Data", ""},
{DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"},
@@ -84,6 +84,33 @@ static const EnumPropertyItem DT_layer_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static void dt_add_vcol_layers(CustomData *cdata,
+ CustomDataMask mask,
+ EnumPropertyItem **r_item,
+ int *r_totitem)
+{
+ int types[2] = {CD_PROP_COLOR, CD_MLOOPCOL};
+
+ for (int i = 0; i < 2; i++) {
+ CustomDataType type = types[i];
+
+ if (!(mask & CD_TYPE_AS_MASK(type))) {
+ continue;
+ }
+
+ int num_data = CustomData_number_of_layers(cdata, type);
+
+ RNA_enum_item_add_separator(r_item, r_totitem);
+
+ for (int j = 0; j < num_data; j++) {
+ EnumPropertyItem tmp_item;
+
+ tmp_item.value = j;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(cdata, type, j);
+ RNA_enum_item_add(r_item, r_totitem, &tmp_item);
+ }
+ }
+}
/* NOTE: #rna_enum_dt_layers_select_src_items enum is from rna_modifier.c. */
static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C,
PointerRNA *ptr,
@@ -159,23 +186,33 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C,
RNA_enum_item_add(&item, &totitem, &tmp_item);
}
}
- else if (data_type == DT_TYPE_VCOL) {
+ else if (data_type & DT_TYPE_VCOL_ALL) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src);
CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH;
- cddata_masks.lmask |= CD_MASK_MLOOPCOL;
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks);
- int num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL);
+ if (data_type & (DT_TYPE_MPROPCOL_VERT)) {
+ cddata_masks.vmask |= CD_MASK_PROP_COLOR;
+ }
+ if (data_type & (DT_TYPE_MLOOPCOL_VERT)) {
+ cddata_masks.vmask |= CD_MASK_MLOOPCOL;
+ }
- RNA_enum_item_add_separator(&item, &totitem);
+ if (data_type & (DT_TYPE_MPROPCOL_LOOP)) {
+ cddata_masks.lmask |= CD_MASK_PROP_COLOR;
+ }
+ if (data_type & (DT_TYPE_MLOOPCOL_LOOP)) {
+ cddata_masks.lmask |= CD_MASK_MLOOPCOL;
+ }
- for (int i = 0; i < num_data; i++) {
- tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(
- &me_eval->ldata, CD_MLOOPCOL, i);
- RNA_enum_item_add(&item, &totitem, &tmp_item);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks);
+
+ if (data_type & (DT_TYPE_MLOOPCOL_VERT | DT_TYPE_MPROPCOL_VERT)) {
+ dt_add_vcol_layers(&me_eval->vdata, cddata_masks.vmask, &item, &totitem);
+ }
+ if (data_type & (DT_TYPE_MLOOPCOL_LOOP | DT_TYPE_MPROPCOL_LOOP)) {
+ dt_add_vcol_layers(&me_eval->ldata, cddata_masks.lmask, &item, &totitem);
}
}
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);
}
/** \} */