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')
-rw-r--r--source/blender/blenkernel/BKE_attribute.h65
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h41
-rw-r--r--source/blender/blenkernel/BKE_paint.h7
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h54
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/attribute.c298
-rw-r--r--source/blender/blenkernel/intern/brush.c3
-rw-r--r--source/blender/blenkernel/intern/customdata.cc3
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c25
-rw-r--r--source/blender/blenkernel/intern/mesh.cc2
-rw-r--r--source/blender/blenkernel/intern/paint.c54
-rw-r--r--source/blender/blenkernel/intern/pbvh.c143
-rw-r--r--source/blender/blenkernel/intern/pbvh.cc210
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h16
-rw-r--r--source/blender/blenloader/intern/versioning_300.c71
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c2
-rw-r--r--source/blender/bmesh/operators/bmo_utils.c164
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c33
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h3
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c177
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc11
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc324
-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
-rw-r--r--source/blender/gpu/GPU_buffers.h7
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c61
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c1
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h5
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h4
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c179
-rw-r--r--source/blender/makesrna/intern/rna_internal.h5
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c115
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c6
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c4
-rw-r--r--source/blender/makesrna/intern/rna_space.c2
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c4
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c29
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.cc17
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c5
72 files changed, 2629 insertions, 467 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 452d6a4316e..f3968c0d761 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -34,10 +34,25 @@ typedef enum AttributeDomain {
ATTR_DOMAIN_NUM
} AttributeDomain;
-/* Attributes */
+typedef enum AttributeDomainMask {
+ ATTR_DOMAIN_MASK_POINT = (1 << 0),
+ ATTR_DOMAIN_MASK_EDGE = (1 << 1),
+ ATTR_DOMAIN_MASK_FACE = (1 << 2),
+ ATTR_DOMAIN_MASK_CORNER = (1 << 3),
+ ATTR_DOMAIN_MASK_CURVE = (1 << 4),
+ ATTR_DOMAIN_MASK_ALL = (1 << 5) - 1
+} AttributeDomainMask;
+
+/* All domains that support color attributes. */
+#define ATTR_DOMAIN_MASK_COLOR \
+ ((AttributeDomainMask)((ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER)))
+
+/* Attributes. */
bool BKE_id_attributes_supported(struct ID *id);
+/** Create a new attribute layer.
+ */
struct CustomDataLayer *BKE_id_attribute_new(
struct ID *id, const char *name, int type, AttributeDomain domain, struct ReportList *reports);
bool BKE_id_attribute_remove(struct ID *id,
@@ -49,7 +64,7 @@ struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
int type,
AttributeDomain domain);
-AttributeDomain BKE_id_attribute_domain(struct ID *id, struct CustomDataLayer *layer);
+AttributeDomain BKE_id_attribute_domain(struct ID *id, const struct CustomDataLayer *layer);
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer);
bool BKE_id_attribute_rename(struct ID *id,
@@ -57,13 +72,57 @@ bool BKE_id_attribute_rename(struct ID *id,
const char *new_name,
struct ReportList *reports);
-int BKE_id_attributes_length(struct ID *id, CustomDataMask mask);
+int BKE_id_attributes_length(const struct ID *id,
+ AttributeDomainMask domain_mask,
+ CustomDataMask mask);
struct CustomDataLayer *BKE_id_attributes_active_get(struct ID *id);
void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer);
int *BKE_id_attributes_active_index_p(struct ID *id);
CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers);
+CustomDataLayer *BKE_id_attribute_from_index(struct ID *id,
+ int lookup_index,
+ AttributeDomainMask domain_mask,
+ CustomDataMask layer_mask);
+
+/** Layer is allowed to be nullptr; if so -1 (layer not found) will be returned. */
+int BKE_id_attribute_to_index(const struct ID *id,
+ const CustomDataLayer *layer,
+ AttributeDomainMask domain_mask,
+ CustomDataMask layer_mask);
+
+struct CustomDataLayer *BKE_id_attribute_subset_active_get(const struct ID *id,
+ int active_flag,
+ AttributeDomainMask domain_mask,
+ CustomDataMask mask);
+void BKE_id_attribute_subset_active_set(struct ID *id,
+ struct CustomDataLayer *layer,
+ int active_flag,
+ AttributeDomainMask domain_mask,
+ CustomDataMask mask);
+
+/**
+ * Sets up a temporary ID with arbitrary CustomData domains. r_id will
+ * be zero initialized with ID type id_type and any non-nullptr
+ * CustomData parameter will be copied into the appropriate struct members.
+ *
+ * \param r_id Pointer to storage sufficient for ID typecode id_type.
+ */
+void BKE_id_attribute_copy_domains_temp(short id_type,
+ const struct CustomData *vdata,
+ const struct CustomData *edata,
+ const struct CustomData *ldata,
+ const struct CustomData *pdata,
+ const struct CustomData *cdata,
+ struct ID *r_id);
+
+struct CustomDataLayer *BKE_id_attributes_active_color_get(const struct ID *id);
+void BKE_id_attributes_active_color_set(struct ID *id, struct CustomDataLayer *active_layer);
+struct CustomDataLayer *BKE_id_attributes_render_color_get(const struct ID *id);
+void BKE_id_attributes_render_color_set(struct ID *id, struct CustomDataLayer *active_layer);
+
+bool BKE_id_attribute_calc_unique_name(struct ID *id, const char *name, char *outname);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index fcf84edeb23..1b6c1dc4205 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -8,6 +8,7 @@
#pragma once
#include "BKE_customdata.h"
+#include "BLI_compiler_compat.h"
#ifdef __cplusplus
extern "C" {
@@ -32,18 +33,23 @@ enum {
DT_TYPE_BWEIGHT_EDGE = 1 << 11,
DT_TYPE_FREESTYLE_EDGE = 1 << 12,
- DT_TYPE_VCOL = 1 << 16,
+ DT_TYPE_MPROPCOL_VERT = 1 << 16,
DT_TYPE_LNOR = 1 << 17,
DT_TYPE_UV = 1 << 24,
DT_TYPE_SHARP_FACE = 1 << 25,
DT_TYPE_FREESTYLE_FACE = 1 << 26,
-#define DT_TYPE_MAX 27
-
- DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT,
+ DT_TYPE_MLOOPCOL_VERT = 1 << 27,
+ DT_TYPE_MPROPCOL_LOOP = 1 << 28,
+ DT_TYPE_MLOOPCOL_LOOP = 1 << 29,
+ DT_TYPE_VCOL_ALL = (1 << 16) | (1 << 27) | (1 << 28) | (1 << 29),
+#define DT_TYPE_MAX 30
+
+ DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT |
+ DT_TYPE_MPROPCOL_VERT | DT_TYPE_MLOOPCOL_VERT,
DT_TYPE_EDGE_ALL = DT_TYPE_SHARP_EDGE | DT_TYPE_SEAM | DT_TYPE_CREASE | DT_TYPE_BWEIGHT_EDGE |
DT_TYPE_FREESTYLE_EDGE,
- DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_LNOR | DT_TYPE_UV,
+ DT_TYPE_LOOP_ALL = DT_TYPE_LNOR | DT_TYPE_UV | DT_TYPE_MPROPCOL_LOOP | DT_TYPE_MLOOPCOL_LOOP,
DT_TYPE_POLY_ALL = DT_TYPE_UV | DT_TYPE_SHARP_FACE | DT_TYPE_FREESTYLE_FACE,
};
@@ -62,7 +68,13 @@ int BKE_object_data_transfer_dttype_to_cdtype(int dtdata_type);
int BKE_object_data_transfer_dttype_to_srcdst_index(int dtdata_type);
#define DT_DATATYPE_IS_VERT(_dt) \
- ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT)
+ ELEM(_dt, \
+ DT_TYPE_MDEFORMVERT, \
+ DT_TYPE_SHAPEKEY, \
+ DT_TYPE_SKIN, \
+ DT_TYPE_BWEIGHT_VERT, \
+ DT_TYPE_MLOOPCOL_VERT, \
+ DT_TYPE_MPROPCOL_VERT)
#define DT_DATATYPE_IS_EDGE(_dt) \
ELEM(_dt, \
DT_TYPE_CREASE, \
@@ -70,19 +82,28 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(int dtdata_type);
DT_TYPE_SEAM, \
DT_TYPE_BWEIGHT_EDGE, \
DT_TYPE_FREESTYLE_EDGE)
-#define DT_DATATYPE_IS_LOOP(_dt) ELEM(_dt, DT_TYPE_UV, DT_TYPE_VCOL, DT_TYPE_LNOR)
+#define DT_DATATYPE_IS_LOOP(_dt) \
+ ELEM(_dt, DT_TYPE_UV, DT_TYPE_LNOR, DT_TYPE_MLOOPCOL_LOOP, DT_TYPE_MPROPCOL_LOOP)
#define DT_DATATYPE_IS_POLY(_dt) ELEM(_dt, DT_TYPE_UV, DT_TYPE_SHARP_FACE, DT_TYPE_FREESTYLE_FACE)
#define DT_DATATYPE_IS_MULTILAYERS(_dt) \
- ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_VCOL, DT_TYPE_UV)
+ ELEM(_dt, \
+ DT_TYPE_MDEFORMVERT, \
+ DT_TYPE_SHAPEKEY, \
+ DT_TYPE_MPROPCOL_VERT, \
+ DT_TYPE_MLOOPCOL_VERT, \
+ DT_TYPE_MPROPCOL_LOOP, \
+ DT_TYPE_MLOOPCOL_LOOP, \
+ DT_TYPE_UV)
enum {
DT_MULTILAYER_INDEX_INVALID = -1,
DT_MULTILAYER_INDEX_MDEFORMVERT = 0,
DT_MULTILAYER_INDEX_SHAPEKEY = 1,
- DT_MULTILAYER_INDEX_VCOL = 2,
+ DT_MULTILAYER_INDEX_VCOL_LOOP = 2,
DT_MULTILAYER_INDEX_UV = 3,
- DT_MULTILAYER_INDEX_MAX = 4,
+ DT_MULTILAYER_INDEX_VCOL_VERT = 4,
+ DT_MULTILAYER_INDEX_MAX = 5,
};
/* Below we keep positive values for real layers idx (generated dynamically). */
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 8ab89b6c244..5633c476dc1 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -12,6 +12,8 @@
#include "DNA_brush_enums.h"
#include "DNA_object_enums.h"
+#include "BKE_attribute.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -493,6 +495,11 @@ typedef struct SculptSession {
struct KeyBlock *shapekey_active;
struct MPropCol *vcol;
+ struct MLoopCol *mcol;
+
+ AttributeDomain vcol_domain;
+ CustomDataType vcol_type;
+
float *vmask;
/* Mesh connectivity maps. */
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index eadbe52d091..775847f27f8 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -11,6 +11,7 @@
#include "BLI_ghash.h"
/* For embedding CCGKey in iterator. */
+#include "BKE_attribute.h"
#include "BKE_ccg.h"
#ifdef __cplusplus
@@ -34,6 +35,7 @@ struct PBVH;
struct PBVHNode;
struct SubdivCCG;
struct TaskParallelSettings;
+struct MeshElemMap;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
@@ -299,6 +301,10 @@ void BKE_pbvh_node_get_verts(PBVH *pbvh,
PBVHNode *node,
const int **r_vert_indices,
struct MVert **r_verts);
+void BKE_pbvh_node_get_loops(PBVH *pbvh,
+ PBVHNode *node,
+ const int **r_loop_indices,
+ const struct MLoop **r_loops);
void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
@@ -388,7 +394,6 @@ typedef struct PBVHVertexIter {
float (*vert_normals)[3];
int totvert;
const int *vert_indices;
- struct MPropCol *vcol;
float *vmask;
/* bmesh */
@@ -405,7 +410,6 @@ typedef struct PBVHVertexIter {
float *no;
float *fno;
float *mask;
- float *col;
bool visible;
} PBVHVertexIter;
@@ -461,17 +465,14 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
if (vi.vmask) { \
vi.mask = &vi.vmask[vi.index]; \
} \
- if (vi.vcol) { \
- vi.col = vi.vcol[vi.index].color; \
- } \
} \
else { \
if (!BLI_gsetIterator_done(&vi.bm_unique_verts)) { \
- vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_unique_verts); \
+ vi.bm_vert = (BMVert *)BLI_gsetIterator_getKey(&vi.bm_unique_verts); \
BLI_gsetIterator_step(&vi.bm_unique_verts); \
} \
else { \
- vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_other_verts); \
+ vi.bm_vert = (BMVert *)BLI_gsetIterator_getKey(&vi.bm_other_verts); \
BLI_gsetIterator_step(&vi.bm_other_verts); \
} \
vi.visible = !BM_elem_flag_test_bool(vi.bm_vert, BM_ELEM_HIDDEN); \
@@ -481,7 +482,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi.co = vi.bm_vert->co; \
vi.fno = vi.bm_vert->no; \
vi.index = BM_elem_index_get(vi.bm_vert); \
- vi.mask = BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
+ vi.mask = (float *)BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
}
#define BKE_pbvh_vertex_iter_end \
@@ -526,6 +527,43 @@ const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3];
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
+bool BKE_pbvh_get_color_layer(const struct Mesh *me,
+ CustomDataLayer **r_layer,
+ AttributeDomain *r_attr);
+
+/* Swaps colors at each element in indices (of domain pbvh->vcol_domain)
+ * with values in colors. */
+void BKE_pbvh_swap_colors(PBVH *pbvh,
+ const int *indices,
+ const int indices_num,
+ float (*colors)[4]);
+
+/* Stores colors from the elements in indices (of domain pbvh->vcol_domain)
+ * into colors. */
+void BKE_pbvh_store_colors(PBVH *pbvh,
+ const int *indices,
+ const int indices_num,
+ float (*colors)[4]);
+
+/* Like BKE_pbvh_store_colors but handles loop->vert conversion */
+void BKE_pbvh_store_colors_vertex(PBVH *pbvh,
+ const int *indices,
+ const int indices_num,
+ float (*colors)[4]);
+
+bool BKE_pbvh_is_drawing(const PBVH *pbvh);
+void BKE_pbvh_is_drawing_set(PBVH *pbvh, bool val);
+
+/* Do not call in PBVH_GRIDS mode */
+void BKE_pbvh_node_num_loops(PBVH *pbvh, PBVHNode *node, int *r_totloop);
+
+void BKE_pbvh_update_active_vcol(PBVH *pbvh, const struct Mesh *mesh);
+void BKE_pbvh_pmap_set(PBVH *pbvh, const struct MeshElemMap *pmap);
+
+void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4]);
+void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]);
+
+void BKE_pbvh_ensure_node_loops(PBVH *pbvh);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index c60d708c075..61131cff06d 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -239,6 +239,7 @@ set(SRC
intern/particle_child.c
intern/particle_distribute.c
intern/particle_system.c
+ intern/pbvh.cc
intern/pbvh.c
intern/pbvh_bmesh.c
intern/pointcache.c
diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c
index ba33a9fee97..13c896fd1ab 100644
--- a/source/blender/blenkernel/intern/attribute.c
+++ b/source/blender/blenkernel/intern/attribute.c
@@ -19,6 +19,7 @@
#include "DNA_pointcloud_types.h"
#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
#include "BKE_attribute.h"
#include "BKE_curves.h"
@@ -91,7 +92,8 @@ static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
CustomData *customdata = info[domain].customdata;
- if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) {
+ if (customdata &&
+ ARRAY_HAS_ITEM(layer, (CustomDataLayer const *)customdata->layers, customdata->totlayer)) {
return customdata;
}
}
@@ -132,6 +134,44 @@ bool BKE_id_attribute_rename(ID *id,
return true;
}
+typedef struct AttrUniqueData {
+ ID *id;
+} AttrUniqueData;
+
+static bool unique_name_cb(void *arg, const char *name)
+{
+ AttrUniqueData *data = (AttrUniqueData *)arg;
+
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(data->id, info);
+
+ for (AttributeDomain domain = ATTR_DOMAIN_POINT; domain < ATTR_DOMAIN_NUM; domain++) {
+ if (!info[domain].customdata) {
+ continue;
+ }
+
+ CustomData *cdata = info[domain].customdata;
+ for (int i = 0; i < cdata->totlayer; i++) {
+ CustomDataLayer *layer = cdata->layers + i;
+
+ if (STREQ(layer->name, name)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool BKE_id_attribute_calc_unique_name(ID *id, const char *name, char *outname)
+{
+ AttrUniqueData data = {.id = id};
+
+ BLI_strncpy_utf8(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
+
+ return BLI_uniquename_cb(unique_name_cb, &data, NULL, '.', outname, MAX_CUSTOMDATA_LAYER_NAME);
+}
+
CustomDataLayer *BKE_id_attribute_new(
ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
{
@@ -144,25 +184,30 @@ CustomDataLayer *BKE_id_attribute_new(
return NULL;
}
+ char uniquename[MAX_CUSTOMDATA_LAYER_NAME];
+ BKE_id_attribute_calc_unique_name(id, name, uniquename);
+
switch (GS(id->name)) {
case ID_ME: {
Mesh *me = (Mesh *)id;
BMEditMesh *em = me->edit_mesh;
if (em != NULL) {
- BM_data_layer_add_named(em->bm, customdata, type, name);
+ BM_data_layer_add_named(em->bm, customdata, type, uniquename);
}
else {
- CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name);
+ CustomData_add_layer_named(
+ customdata, type, CD_DEFAULT, NULL, info[domain].length, uniquename);
}
break;
}
default: {
- CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name);
+ CustomData_add_layer_named(
+ customdata, type, CD_DEFAULT, NULL, info[domain].length, uniquename);
break;
}
}
- const int index = CustomData_get_named_layer_index(customdata, type, name);
+ const int index = CustomData_get_named_layer_index(customdata, type, uniquename);
return (index == -1) ? NULL : &(customdata->layers[index]);
}
@@ -229,7 +274,7 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
return NULL;
}
-int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
+int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, CustomDataMask mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
@@ -238,7 +283,8 @@ int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
CustomData *customdata = info[domain].customdata;
- if (customdata) {
+
+ if (customdata && ((1 << (int)domain) & domain_mask)) {
length += CustomData_number_of_layers_typemask(customdata, mask);
}
}
@@ -246,7 +292,7 @@ int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
return length;
}
-AttributeDomain BKE_id_attribute_domain(ID *id, CustomDataLayer *layer)
+AttributeDomain BKE_id_attribute_domain(ID *id, const CustomDataLayer *layer)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
@@ -295,7 +341,7 @@ bool BKE_id_attribute_required(ID *id, CustomDataLayer *layer)
CustomDataLayer *BKE_id_attributes_active_get(ID *id)
{
int active_index = *BKE_id_attributes_active_index_p(id);
- if (active_index > BKE_id_attributes_length(id, CD_MASK_PROP_ALL)) {
+ if (active_index > BKE_id_attributes_length(id, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL)) {
active_index = 0;
}
@@ -384,3 +430,237 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye
return NULL;
}
+
+CustomDataLayer *BKE_id_attribute_from_index(ID *id,
+ int lookup_index,
+ AttributeDomainMask domain_mask,
+ CustomDataMask layer_mask)
+{
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+
+ int index = 0;
+ for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ CustomData *customdata = info[domain].customdata;
+
+ if (!customdata || !((1 << (int)domain) & domain_mask)) {
+ continue;
+ }
+
+ for (int i = 0; i < customdata->totlayer; i++) {
+ if (!(layer_mask & CD_TYPE_AS_MASK(customdata->layers[i].type)) ||
+ (CD_TYPE_AS_MASK(customdata->layers[i].type) & CD_FLAG_TEMPORARY)) {
+ continue;
+ }
+
+ if (index == lookup_index) {
+ return customdata->layers + i;
+ }
+
+ index++;
+ }
+ }
+
+ return NULL;
+}
+
+/** Get list of domain types but with ATTR_DOMAIN_FACE and
+ * ATTR_DOMAIN_CORNER swapped.
+ */
+static void get_domains_types(AttributeDomain domains[ATTR_DOMAIN_NUM])
+{
+ for (AttributeDomain i = 0; i < ATTR_DOMAIN_NUM; i++) {
+ domains[i] = i;
+ }
+
+ /* Swap corner and face. */
+ SWAP(AttributeDomain, domains[ATTR_DOMAIN_FACE], domains[ATTR_DOMAIN_CORNER]);
+}
+
+int BKE_id_attribute_to_index(const struct ID *id,
+ const CustomDataLayer *layer,
+ AttributeDomainMask domain_mask,
+ CustomDataMask layer_mask)
+{
+ if (!layer) {
+ return -1;
+ }
+
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ AttributeDomain domains[ATTR_DOMAIN_NUM];
+ get_domains_types(domains);
+ get_domains(id, info);
+
+ int index = 0;
+ for (int i = 0; i < ATTR_DOMAIN_NUM; i++) {
+ if (!(domain_mask & (1 << domains[i])) || !info[domains[i]].customdata) {
+ continue;
+ }
+
+ CustomData *cdata = info[domains[i]].customdata;
+ for (int j = 0; j < cdata->totlayer; j++) {
+ CustomDataLayer *layer_iter = cdata->layers + j;
+
+ if (!(CD_TYPE_AS_MASK(layer_iter->type) & layer_mask) ||
+ (CD_TYPE_AS_MASK(layer_iter->type) & CD_FLAG_TEMPORARY)) {
+ continue;
+ }
+
+ if (layer == layer_iter) {
+ return index;
+ }
+
+ index++;
+ }
+ }
+
+ return -1;
+}
+
+CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id,
+ int active_flag,
+ AttributeDomainMask domain_mask,
+ CustomDataMask mask)
+{
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ AttributeDomain domains[ATTR_DOMAIN_NUM];
+
+ get_domains_types(domains);
+ get_domains(id, info);
+
+ CustomDataLayer *candidate = NULL;
+ for (int i = 0; i < ARRAY_SIZE(domains); i++) {
+ if (!((1 << domains[i]) & domain_mask) || !info[domains[i]].customdata) {
+ continue;
+ }
+
+ CustomData *cdata = info[domains[i]].customdata;
+
+ for (int j = 0; j < cdata->totlayer; j++) {
+ CustomDataLayer *layer = cdata->layers + j;
+
+ if (!(CD_TYPE_AS_MASK(layer->type) & mask) ||
+ (CD_TYPE_AS_MASK(layer->type) & CD_FLAG_TEMPORARY)) {
+ continue;
+ }
+
+ if (layer->flag & active_flag) {
+ return layer;
+ }
+
+ candidate = layer;
+ }
+ }
+
+ return candidate;
+}
+
+void BKE_id_attribute_subset_active_set(ID *id,
+ CustomDataLayer *layer,
+ int active_flag,
+ AttributeDomainMask domain_mask,
+ CustomDataMask mask)
+{
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ AttributeDomain domains[ATTR_DOMAIN_NUM];
+
+ get_domains_types(domains);
+ get_domains(id, info);
+
+ for (int i = 0; i < ATTR_DOMAIN_NUM; i++) {
+ AttributeDomainMask domain_mask2 = (AttributeDomainMask)(1 << domains[i]);
+
+ if (!(domain_mask2 & domain_mask) || !info[domains[i]].customdata) {
+ continue;
+ }
+
+ CustomData *cdata = info[domains[i]].customdata;
+
+ for (int j = 0; j < cdata->totlayer; j++) {
+ CustomDataLayer *layer_iter = cdata->layers + j;
+
+ if (!(CD_TYPE_AS_MASK(layer_iter->type) & mask) ||
+ (CD_TYPE_AS_MASK(layer_iter->type) & CD_FLAG_TEMPORARY)) {
+ continue;
+ }
+
+ layer_iter->flag &= ~active_flag;
+ }
+ }
+
+ layer->flag |= active_flag;
+}
+
+CustomDataLayer *BKE_id_attributes_active_color_get(const ID *id)
+{
+ return BKE_id_attribute_subset_active_get(
+ id, CD_FLAG_COLOR_ACTIVE, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+}
+
+void BKE_id_attributes_active_color_set(ID *id, CustomDataLayer *active_layer)
+{
+ BKE_id_attribute_subset_active_set(
+ id, active_layer, CD_FLAG_COLOR_ACTIVE, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+}
+
+CustomDataLayer *BKE_id_attributes_render_color_get(const ID *id)
+{
+ return BKE_id_attribute_subset_active_get(
+ id, CD_FLAG_COLOR_RENDER, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+}
+
+void BKE_id_attributes_render_color_set(ID *id, CustomDataLayer *active_layer)
+{
+ BKE_id_attribute_subset_active_set(
+ id, active_layer, CD_FLAG_COLOR_RENDER, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+}
+
+void BKE_id_attribute_copy_domains_temp(short id_type,
+ const CustomData *vdata,
+ const CustomData *edata,
+ const CustomData *ldata,
+ const CustomData *pdata,
+ const CustomData *cdata,
+ ID *r_id)
+{
+ CustomData reset;
+
+ CustomData_reset(&reset);
+
+ switch (id_type) {
+ case ID_ME: {
+ Mesh *me = (Mesh *)r_id;
+ memset((void *)me, 0, sizeof(*me));
+
+ me->edit_mesh = NULL;
+
+ me->vdata = vdata ? *vdata : reset;
+ me->edata = edata ? *edata : reset;
+ me->ldata = ldata ? *ldata : reset;
+ me->pdata = pdata ? *pdata : reset;
+
+ break;
+ }
+ case ID_PT: {
+ PointCloud *pointcloud = (PointCloud *)r_id;
+
+ memset((void *)pointcloud, 0, sizeof(*pointcloud));
+
+ pointcloud->pdata = vdata ? *vdata : reset;
+ break;
+ }
+ case ID_CV: {
+ Curves *curves = (Curves *)r_id;
+
+ memset((void *)curves, 0, sizeof(*curves));
+
+ curves->geometry.point_data = vdata ? *vdata : reset;
+ curves->geometry.curve_data = cdata ? *cdata : reset;
+ break;
+ }
+ default:
+ break;
+ }
+
+ *((short *)r_id->name) = id_type;
+}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 601c867d8db..b9cd9e1ee59 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -1834,7 +1834,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->tip_roundness = 1.0f;
br->density = 1.0f;
br->flag &= ~BRUSH_SPACE_ATTEN;
- zero_v3(br->rgb);
+ copy_v3_fl(br->rgb, 1.0f);
+ zero_v3(br->secondary_rgb);
break;
case SCULPT_TOOL_SMEAR:
br->alpha = 1.0f;
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 9258c1ffb66..6dd9460aaa9 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -2279,7 +2279,8 @@ bool CustomData_merge(const struct CustomData *source,
newlayer->active_rnd = lastrender;
newlayer->active_clone = lastclone;
newlayer->active_mask = lastmask;
- newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY);
+ newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY | CD_FLAG_COLOR_ACTIVE |
+ CD_FLAG_COLOR_RENDER);
changed = true;
if (layer->anonymous_id != nullptr) {
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 5be993ca1f7..2369ce88ebc 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -19,6 +19,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h"
@@ -129,7 +130,10 @@ bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
case DT_TYPE_UV:
ret = true;
break;
- case DT_TYPE_VCOL:
+ case DT_TYPE_MPROPCOL_VERT:
+ case DT_TYPE_MLOOPCOL_VERT:
+ case DT_TYPE_MPROPCOL_LOOP:
+ case DT_TYPE_MLOOPCOL_LOOP:
*r_advanced_mixing = true;
*r_threshold = true;
ret = true;
@@ -209,12 +213,14 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
return CD_FAKE_SHARP;
case DT_TYPE_FREESTYLE_FACE:
return CD_FREESTYLE_FACE;
-
- case DT_TYPE_VCOL:
- return CD_MLOOPCOL;
case DT_TYPE_LNOR:
return CD_FAKE_LNOR;
-
+ case DT_TYPE_MLOOPCOL_VERT:
+ case DT_TYPE_MLOOPCOL_LOOP:
+ return CD_MLOOPCOL;
+ case DT_TYPE_MPROPCOL_VERT:
+ case DT_TYPE_MPROPCOL_LOOP:
+ return CD_PROP_COLOR;
default:
BLI_assert(0);
}
@@ -230,8 +236,12 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
return DT_MULTILAYER_INDEX_SHAPEKEY;
case DT_TYPE_UV:
return DT_MULTILAYER_INDEX_UV;
- case DT_TYPE_VCOL:
- return DT_MULTILAYER_INDEX_VCOL;
+ case DT_TYPE_MPROPCOL_VERT:
+ case DT_TYPE_MLOOPCOL_VERT:
+ return DT_MULTILAYER_INDEX_VCOL_VERT;
+ case DT_TYPE_MPROPCOL_LOOP:
+ case DT_TYPE_MLOOPCOL_LOOP:
+ return DT_MULTILAYER_INDEX_VCOL_LOOP;
default:
return DT_MULTILAYER_INDEX_INVALID;
}
@@ -1231,6 +1241,7 @@ void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
+
if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) {
fromlayers = fromlayers_select[fromto_idx];
tolayers = tolayers_select[fromto_idx];
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index b30d8f92cc6..5afc3c0be3b 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -433,7 +433,7 @@ static const char *cmpcode_to_str(int code)
case MESHCMP_DVERT_TOTGROUPMISMATCH:
return "Vertex Doesn't Belong To Same Number Of Groups";
case MESHCMP_LOOPCOLMISMATCH:
- return "Vertex Color Mismatch";
+ return "Color Attribute Mismatch";
case MESHCMP_LOOPUVMISMATCH:
return "UV Mismatch";
case MESHCMP_LOOPMISMATCH:
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 1c58173f570..80c3ead3039 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -29,6 +29,7 @@
#include "BLT_translation.h"
+#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_colortools.h"
@@ -1666,7 +1667,28 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->multires.modifier = NULL;
ss->multires.level = 0;
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
- ss->vcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
+
+ CustomDataLayer *layer;
+ AttributeDomain domain;
+
+ if (BKE_pbvh_get_color_layer(me, &layer, &domain)) {
+ if (layer->type == CD_PROP_COLOR) {
+ ss->vcol = layer->data;
+ }
+ else {
+ ss->mcol = layer->data;
+ }
+
+ ss->vcol_domain = domain;
+ ss->vcol_type = layer->type;
+ }
+ else {
+ ss->vcol = NULL;
+ ss->mcol = NULL;
+
+ ss->vcol_type = -1;
+ ss->vcol_domain = ATTR_DOMAIN_NUM;
+ }
}
/* Sculpt Face Sets. */
@@ -1692,6 +1714,10 @@ static void sculpt_update_object(Depsgraph *depsgraph,
if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
BKE_mesh_vert_poly_map_create(
&ss->pmap, &ss->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
+
+ if (ss->pbvh) {
+ BKE_pbvh_pmap_set(ss->pbvh, ss->pmap);
+ }
}
pbvh_show_mask_set(ss->pbvh, ss->show_mask);
@@ -1791,16 +1817,30 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval)
void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
{
Mesh *orig_me = BKE_object_get_original_mesh(object);
- if (!U.experimental.use_sculpt_vertex_colors) {
- return;
+
+ int types[] = {CD_PROP_COLOR, CD_MLOOPCOL};
+ bool has_color = false;
+
+ for (int i = 0; i < ARRAY_SIZE(types); i++) {
+ has_color = CustomData_has_layer(&orig_me->vdata, types[i]) ||
+ CustomData_has_layer(&orig_me->ldata, types[i]);
+
+ if (has_color) {
+ break;
+ }
}
- if (CustomData_has_layer(&orig_me->vdata, CD_PROP_COLOR)) {
+ if (has_color) {
return;
}
CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert);
+ CustomDataLayer *layer = orig_me->vdata.layers +
+ CustomData_get_layer_index(&orig_me->vdata, CD_PROP_COLOR);
+
BKE_mesh_update_customdata_pointers(orig_me, true);
+
+ BKE_id_attributes_active_color_set(&orig_me->id, layer);
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY_ALL_MODES);
}
@@ -2173,6 +2213,10 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg);
}
}
+
+ BKE_pbvh_update_active_vcol(pbvh, BKE_object_get_original_mesh(ob));
+ BKE_pbvh_pmap_set(pbvh, ob->sculpt->pmap);
+
return pbvh;
}
@@ -2192,6 +2236,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
}
}
+ BKE_pbvh_pmap_set(pbvh, ob->sculpt->pmap);
+
ob->sculpt->pbvh = pbvh;
return pbvh;
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 3ed3c7badc3..5d307697208 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -17,8 +17,10 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_attribute.h"
#include "BKE_ccg.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_subdiv_ccg.h"
@@ -599,6 +601,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
/* Clear the bitmap so it can be used as an update tag later on. */
BLI_bitmap_set_all(pbvh->vert_bitmap, false, totvert);
+
+ BKE_pbvh_update_active_vcol(pbvh, mesh);
}
void BKE_pbvh_build_grids(PBVH *pbvh,
@@ -667,6 +671,9 @@ void BKE_pbvh_free(PBVH *pbvh)
if (node->vert_indices) {
MEM_freeN((void *)node->vert_indices);
}
+ if (node->loop_indices) {
+ MEM_freeN(node->loop_indices);
+ }
if (node->face_vert_indices) {
MEM_freeN((void *)node->face_vert_indices);
}
@@ -1254,6 +1261,30 @@ static int pbvh_get_buffers_update_flags(PBVH *UNUSED(pbvh))
return update_flags;
}
+bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, AttributeDomain *r_attr)
+{
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)me);
+
+ if (!layer || !ELEM(layer->type, CD_PROP_COLOR, CD_MLOOPCOL)) {
+ *r_layer = NULL;
+ *r_attr = ATTR_DOMAIN_NUM;
+ return false;
+ }
+
+ AttributeDomain domain = BKE_id_attribute_domain((ID *)me, layer);
+
+ if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
+ *r_layer = NULL;
+ *r_attr = ATTR_DOMAIN_NUM;
+ return false;
+ }
+
+ *r_layer = layer;
+ *r_attr = domain;
+
+ return true;
+}
+
static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -1304,18 +1335,25 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
&pbvh->gridkey,
update_flags);
break;
- case PBVH_FACES:
+ case PBVH_FACES: {
+ CustomDataLayer *layer = NULL;
+ AttributeDomain domain;
+
+ BKE_pbvh_get_color_layer(pbvh->mesh, &layer, &domain);
+
GPU_pbvh_mesh_buffers_update(node->draw_buffers,
pbvh->verts,
pbvh->vert_normals,
CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
- CustomData_get_layer(pbvh->ldata, CD_MLOOPCOL),
+ layer ? layer->data : NULL,
+ layer ? layer->type : -1,
+ layer ? domain : ATTR_DOMAIN_AUTO,
CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
pbvh->face_sets_color_seed,
pbvh->face_sets_color_default,
- CustomData_get_layer(pbvh->vdata, CD_PROP_COLOR),
update_flags);
break;
+ }
case PBVH_BMESH:
GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
pbvh->bm,
@@ -1442,7 +1480,9 @@ void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flag)
}
if (flag & (PBVH_UpdateColor)) {
- /* Do nothing */
+ for (int i = 0; i < totnode; i++) {
+ nodes[i]->flag |= PBVH_UpdateRedraw | PBVH_UpdateDrawBuffers | PBVH_UpdateColor;
+ }
}
if (flag & (PBVH_UpdateVisibility)) {
@@ -1820,6 +1860,22 @@ void BKE_pbvh_vert_mark_update(PBVH *pbvh, int index)
BLI_BITMAP_ENABLE(pbvh->vert_bitmap, index);
}
+void BKE_pbvh_node_get_loops(PBVH *pbvh,
+ PBVHNode *node,
+ const int **r_loop_indices,
+ const MLoop **r_loops)
+{
+ BLI_assert(BKE_pbvh_type(pbvh) == PBVH_FACES);
+
+ if (r_loop_indices) {
+ *r_loop_indices = node->loop_indices;
+ }
+
+ if (r_loops) {
+ *r_loops = pbvh->mloop;
+ }
+}
+
void BKE_pbvh_node_get_verts(PBVH *pbvh,
PBVHNode *node,
const int **r_vert_indices,
@@ -2980,7 +3036,6 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->vert_normals = pbvh->vert_normals;
vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK);
- vi->vcol = CustomData_get_layer(pbvh->vdata, CD_PROP_COLOR);
}
}
@@ -3072,3 +3127,81 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
{
pbvh->respect_hide = respect_hide;
}
+bool BKE_pbvh_is_drawing(const PBVH *pbvh)
+{
+ return pbvh->is_drawing;
+}
+
+void BKE_pbvh_is_drawing_set(PBVH *pbvh, bool val)
+{
+ pbvh->is_drawing = val;
+}
+
+void BKE_pbvh_node_num_loops(PBVH *pbvh, PBVHNode *node, int *r_totloop)
+{
+ UNUSED_VARS(pbvh);
+ BLI_assert(BKE_pbvh_type(pbvh) == PBVH_FACES);
+
+ if (r_totloop) {
+ *r_totloop = node->loop_indices_num;
+ }
+}
+
+void BKE_pbvh_update_active_vcol(PBVH *pbvh, const Mesh *mesh)
+{
+ BKE_pbvh_get_color_layer(mesh, &pbvh->color_layer, &pbvh->color_domain);
+}
+
+void BKE_pbvh_pmap_set(PBVH *pbvh, const MeshElemMap *pmap)
+{
+ pbvh->pmap = pmap;
+}
+
+void BKE_pbvh_ensure_node_loops(PBVH *pbvh)
+{
+ BLI_assert(BKE_pbvh_type(pbvh) == PBVH_FACES);
+
+ int totloop = 0;
+
+ /* Check if nodes already have loop indices. */
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ if (node->loop_indices) {
+ return;
+ }
+
+ totloop += node->totprim * 3;
+ }
+
+ BLI_bitmap *visit = BLI_BITMAP_NEW(totloop, __func__);
+
+ /* Create loop indices from node loop triangles. */
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ node->loop_indices = MEM_malloc_arrayN(node->totprim * 3, sizeof(int), __func__);
+ node->loop_indices_num = 0;
+
+ for (int j = 0; j < node->totprim; j++) {
+ const MLoopTri *mlt = pbvh->looptri + node->prim_indices[j];
+
+ for (int k = 0; k < 3; k++) {
+ if (!BLI_BITMAP_TEST(visit, mlt->tri[k])) {
+ node->loop_indices[node->loop_indices_num++] = mlt->tri[k];
+ BLI_BITMAP_ENABLE(visit, mlt->tri[k]);
+ }
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(visit);
+}
diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc
new file mode 100644
index 00000000000..d32a03186e3
--- /dev/null
+++ b/source/blender/blenkernel/intern/pbvh.cc
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_ghash.h"
+#include "BLI_index_range.hh"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_span.hh"
+#include "BLI_task.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute.h"
+#include "BKE_ccg.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_subdiv_ccg.h"
+
+#include "PIL_time.h"
+
+#include "GPU_buffers.h"
+
+#include "bmesh.h"
+
+#include "atomic_ops.h"
+
+#include "pbvh_intern.h"
+
+#include <climits>
+
+using blender::IndexRange;
+
+namespace blender::bke {
+
+template<typename Func>
+inline void to_static_color_type(const CustomDataType type, const Func &func)
+{
+ switch (type) {
+ case CD_PROP_COLOR:
+ func(MPropCol());
+ break;
+ case CD_MLOOPCOL:
+ func(MLoopCol());
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+}
+
+template<typename T> void to_float(const T &src, float dst[4]);
+
+template<> void to_float(const MLoopCol &src, float dst[4])
+{
+ rgba_uchar_to_float(dst, reinterpret_cast<const unsigned char *>(&src));
+ srgb_to_linearrgb_v3_v3(dst, dst);
+}
+template<> void to_float(const MPropCol &src, float dst[4])
+{
+ copy_v4_v4(dst, src.color);
+}
+
+template<typename T> void from_float(const float src[4], T &dst);
+
+template<> void from_float(const float src[4], MLoopCol &dst)
+{
+ float temp[4];
+ linearrgb_to_srgb_v3_v3(temp, src);
+ temp[3] = src[3];
+ rgba_float_to_uchar(reinterpret_cast<unsigned char *>(&dst), temp);
+}
+template<> void from_float(const float src[4], MPropCol &dst)
+{
+ copy_v4_v4(dst.color, src);
+}
+
+template<typename T>
+static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4])
+{
+ if (pbvh.color_domain == ATTR_DOMAIN_CORNER) {
+ const MeshElemMap &melem = pbvh.pmap[vertex];
+
+ int count = 0;
+ zero_v4(r_color);
+ for (const int i_poly : Span(melem.indices, melem.count)) {
+ const MPoly &mp = pbvh.mpoly[i_poly];
+ Span<T> colors{static_cast<const T *>(pbvh.color_layer->data) + mp.loopstart, mp.totloop};
+ Span<MLoop> loops{pbvh.mloop + mp.loopstart, mp.totloop};
+
+ for (const int i_loop : IndexRange(mp.totloop)) {
+ if (loops[i_loop].v == vertex) {
+ float temp[4];
+ to_float(colors[i_loop], temp);
+
+ add_v4_v4(r_color, temp);
+ count++;
+ }
+ }
+ }
+
+ if (count) {
+ mul_v4_fl(r_color, 1.0f / (float)count);
+ }
+ }
+ else {
+ to_float(static_cast<T *>(pbvh.color_layer->data)[vertex], r_color);
+ }
+}
+
+template<typename T>
+static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4])
+{
+ if (pbvh.color_domain == ATTR_DOMAIN_CORNER) {
+ const MeshElemMap &melem = pbvh.pmap[vertex];
+
+ for (const int i_poly : Span(melem.indices, melem.count)) {
+ const MPoly &mp = pbvh.mpoly[i_poly];
+ MutableSpan<T> colors{static_cast<T *>(pbvh.color_layer->data) + mp.loopstart, mp.totloop};
+ Span<MLoop> loops{pbvh.mloop + mp.loopstart, mp.totloop};
+
+ for (const int i_loop : IndexRange(mp.totloop)) {
+ if (loops[i_loop].v == vertex) {
+ from_float(color, colors[i_loop]);
+ }
+ }
+ }
+ }
+ else {
+ from_float(color, static_cast<T *>(pbvh.color_layer->data)[vertex]);
+ }
+}
+
+} // namespace blender::bke
+
+extern "C" {
+void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4])
+{
+ blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ using T = decltype(dummy);
+ blender::bke::pbvh_vertex_color_get<T>(*pbvh, vertex, r_color);
+ });
+}
+
+void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4])
+{
+ blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ using T = decltype(dummy);
+ blender::bke::pbvh_vertex_color_set<T>(*pbvh, vertex, color);
+ });
+}
+
+void BKE_pbvh_swap_colors(PBVH *pbvh,
+ const int *indices,
+ const int indices_num,
+ float (*r_colors)[4])
+{
+ blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ using T = decltype(dummy);
+ T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data);
+ for (const int i : IndexRange(indices_num)) {
+ T temp = pbvh_colors[indices[i]];
+ blender::bke::from_float(r_colors[i], pbvh_colors[indices[i]]);
+ blender::bke::to_float(temp, r_colors[i]);
+ }
+ });
+}
+
+void BKE_pbvh_store_colors(PBVH *pbvh,
+ const int *indices,
+ const int indices_num,
+ float (*r_colors)[4])
+{
+ blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ using T = decltype(dummy);
+ T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data);
+ for (const int i : IndexRange(indices_num)) {
+ blender::bke::to_float(pbvh_colors[indices[i]], r_colors[i]);
+ }
+ });
+}
+
+void BKE_pbvh_store_colors_vertex(PBVH *pbvh,
+ const int *indices,
+ const int indices_num,
+ float (*r_colors)[4])
+{
+ if (pbvh->color_domain == ATTR_DOMAIN_POINT) {
+ BKE_pbvh_store_colors(pbvh, indices, indices_num, r_colors);
+ }
+ else {
+ blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ using T = decltype(dummy);
+ for (const int i : IndexRange(indices_num)) {
+ blender::bke::pbvh_vertex_color_get<T>(*pbvh, indices[i], r_colors[i]);
+ }
+ });
+ }
+}
+}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index a10d09e106c..37f8dfd9b6b 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -16,6 +16,8 @@ typedef struct {
float bmin[3], bmax[3], bcentroid[3];
} BBC;
+struct MeshElemMap;
+
/* NOTE: this structure is getting large, might want to split it into
* union'd structs */
struct PBVHNode {
@@ -60,6 +62,13 @@ struct PBVHNode {
const int *vert_indices;
unsigned int uniq_verts, face_verts;
+ /* Array of indices into the Mesh's MLoop array.
+ * PBVH_FACES only. The first part of the array
+ * are loops unique to this node, see comment for
+ * vert_indices for more details.*/
+ int *loop_indices;
+ unsigned int loop_indices_num;
+
/* An array mapping face corners into the vert_indices
* array. The array is sized to match 'totprim', and each of
* the face's corners gets an index into the vert_indices
@@ -165,6 +174,13 @@ struct PBVH {
struct BMLog *bm_log;
struct SubdivCCG *subdiv_ccg;
+
+ const struct MeshElemMap *pmap;
+
+ CustomDataLayer *color_layer;
+ AttributeDomain color_domain;
+
+ bool is_drawing;
};
/* pbvh.c */
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 3088dc4c7e8..5ba7dc74e3d 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -30,6 +30,7 @@
#include "DNA_lineart_types.h"
#include "DNA_listBase.h"
#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -41,8 +42,10 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_asset.h"
+#include "BKE_attribute.h"
#include "BKE_collection.h"
#include "BKE_curve.h"
+#include "BKE_data_transfer.h"
#include "BKE_deform.h"
#include "BKE_fcurve.h"
#include "BKE_fcurve_driver.h"
@@ -2566,6 +2569,74 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 10)) {
+ /* While vertex-colors were experimental the smear tool became corrupt due
+ * to bugs in the wm_toolsystem API (auto-creation of sculpt brushes
+ * was broken). Go through and reset all smear brushes. */
+ LISTBASE_FOREACH (Brush *, br, &bmain->brushes) {
+ if (br->sculpt_tool == SCULPT_TOOL_SMEAR) {
+ br->alpha = 1.0f;
+ br->spacing = 5;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->curve_preset = BRUSH_CURVE_SPHERE;
+ }
+ }
+
+ /* Rebuild active/render color attribute references. */
+ LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) {
+ for (int step = 0; step < 2; step++) {
+ CustomDataLayer *actlayer = NULL;
+
+ int vact1, vact2;
+
+ if (step) {
+ vact1 = CustomData_get_render_layer_index(&me->vdata, CD_PROP_COLOR);
+ vact2 = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL);
+ }
+ else {
+ vact1 = CustomData_get_active_layer_index(&me->vdata, CD_PROP_COLOR);
+ vact2 = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPCOL);
+ }
+
+ if (vact1 != -1) {
+ actlayer = me->vdata.layers + vact1;
+ }
+ else if (vact2 != -1) {
+ actlayer = me->ldata.layers + vact2;
+ }
+
+ if (actlayer) {
+ if (step) {
+ BKE_id_attributes_render_color_set(&me->id, actlayer);
+ }
+ else {
+ BKE_id_attributes_active_color_set(&me->id, actlayer);
+ }
+ }
+ }
+ }
+
+ /* Update data transfer modifiers */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_DataTransfer) {
+ DataTransferModifierData *dtmd = (DataTransferModifierData *)md;
+
+ for (int i = 0; i < DT_MULTILAYER_INDEX_MAX; i++) {
+ if (dtmd->layers_select_src[i] == 0) {
+ dtmd->layers_select_src[i] = DT_LAYERS_ALL_SRC;
+ }
+
+ if (dtmd->layers_select_dst[i] == 0) {
+ dtmd->layers_select_dst[i] = DT_LAYERS_NAME_DST;
+ }
+ }
+ }
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 276a8abb731..7424fdb9247 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1493,6 +1493,7 @@ static BMOpDefine bmo_rotate_colors_def = {
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
{"use_ccw", BMO_OP_SLOT_BOOL}, /* rotate counter-clockwise if true, otherwise clockwise */
+ {"color_index", BMO_OP_SLOT_INT}, /* index into color attribute list */
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -1509,6 +1510,7 @@ static BMOpDefine bmo_reverse_colors_def = {
"reverse_colors",
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
+ {"color_index", BMO_OP_SLOT_INT}, /* index into color attribute list */
{{'\0'}},
},
{{{'\0'}}}, /* no output */
diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c
index c79eecaf1a0..60a893ab5da 100644
--- a/source/blender/bmesh/operators/bmo_utils.c
+++ b/source/blender/bmesh/operators/bmo_utils.c
@@ -9,12 +9,16 @@
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
#include "BLI_alloca.h"
#include "BLI_math.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
+#include "BKE_object.h"
#include "bmesh.h"
@@ -553,6 +557,28 @@ void bmo_reverse_uvs_exec(BMesh *bm, BMOperator *op)
/**************************************************************************** *
* Cycle colors for a face
**************************************************************************** */
+static void bmo_get_loop_color_ref(BMesh *bm,
+ int index,
+ int *r_cd_color_offset,
+ int *r_cd_color_type)
+{
+ Mesh me_query;
+
+ BKE_id_attribute_copy_domains_temp(ID_ME, &bm->vdata, NULL, &bm->ldata, NULL, NULL, &me_query.id);
+
+ CustomDataLayer *layer = BKE_id_attribute_from_index(
+ &me_query.id, index, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ if (!layer || BKE_id_attribute_domain(&me_query.id, layer) != ATTR_DOMAIN_CORNER) {
+ *r_cd_color_offset = -1;
+ return;
+ }
+
+ int layer_i = CustomData_get_layer_index(&bm->ldata, layer->type);
+
+ *r_cd_color_offset = bm->ldata.layers[layer_i].offset;
+ *r_cd_color_type = layer->type;
+}
void bmo_rotate_colors_exec(BMesh *bm, BMOperator *op)
{
@@ -561,57 +587,67 @@ void bmo_rotate_colors_exec(BMesh *bm, BMOperator *op)
BMIter l_iter; /* iteration loop */
const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw");
- const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
- if (cd_loop_color_offset != -1) {
- BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
- if (use_ccw == false) { /* same loops direction */
- BMLoop *lf; /* current face loops */
- MLoopCol *f_lcol; /* first face loop color */
- MLoopCol p_col; /* previous color */
- MLoopCol t_col; /* tmp color */
+ const int color_index = BMO_slot_int_get(op->slots_in, "color_index");
- int n = 0;
- BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
- /* current loop color is the previous loop color */
- MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
- if (n == 0) {
- f_lcol = lcol;
- p_col = *lcol;
- }
- else {
- t_col = *lcol;
- *lcol = p_col;
- p_col = t_col;
- }
- n++;
- }
+ int cd_loop_color_offset;
+ int cd_loop_color_type;
- *f_lcol = p_col;
- }
- else { /* counter loop direction */
- BMLoop *lf; /* current face loops */
- MLoopCol *p_lcol; /* previous loop color */
- MLoopCol *lcol;
- MLoopCol t_col; /* current color */
+ bmo_get_loop_color_ref(bm, color_index, &cd_loop_color_offset, &cd_loop_color_type);
- int n = 0;
- BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
- /* previous loop color is the current loop color */
- lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
- if (n == 0) {
- p_lcol = lcol;
- t_col = *lcol;
- }
- else {
- *p_lcol = *lcol;
- p_lcol = lcol;
- }
- n++;
+ if (cd_loop_color_offset == -1) {
+ BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "color_index is invalid");
+ return;
+ }
+
+ const size_t size = cd_loop_color_type == CD_PROP_COLOR ? sizeof(MPropCol) : sizeof(MLoopCol);
+ void *p_col; /* previous color */
+ void *t_col = alloca(size); /* tmp color */
+
+ BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
+ if (use_ccw == false) { /* same loops direction */
+ BMLoop *lf; /* current face loops */
+ void *f_lcol; /* first face loop color */
+
+ int n = 0;
+ BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
+ /* current loop color is the previous loop color */
+ void *lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
+
+ if (n == 0) {
+ f_lcol = lcol;
+ p_col = lcol;
}
+ else {
+ memcpy(t_col, lcol, size);
+ memcpy(lcol, p_col, size);
+ memcpy(p_col, t_col, size);
+ }
+ n++;
+ }
- *lcol = t_col;
+ memcpy(f_lcol, p_col, size);
+ }
+ else { /* counter loop direction */
+ BMLoop *lf; /* current face loops */
+ void *lcol, *p_lcol;
+
+ int n = 0;
+ BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
+ /* previous loop color is the current loop color */
+ lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
+ if (n == 0) {
+ p_lcol = lcol;
+ memcpy(t_col, lcol, size);
+ }
+ else {
+ memcpy(p_lcol, lcol, size);
+ p_lcol = lcol;
+ }
+ n++;
}
+
+ memcpy(lcol, t_col, size);
}
}
}
@@ -619,35 +655,53 @@ void bmo_rotate_colors_exec(BMesh *bm, BMOperator *op)
/*************************************************************************** *
* Reverse colors for a face
*************************************************************************** */
-static void bm_face_reverse_colors(BMFace *f, const int cd_loop_color_offset)
+static void bm_face_reverse_colors(BMFace *f,
+ const int cd_loop_color_offset,
+ const int cd_loop_color_type)
{
BMIter iter;
BMLoop *l;
int i;
- MLoopCol *cols = BLI_array_alloca(cols, f->len);
+ const size_t size = cd_loop_color_type == CD_PROP_COLOR ? sizeof(MPropCol) : sizeof(MLoopCol);
+
+ char *cols = alloca(size * f->len);
+ char *col = cols;
BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
- MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
- cols[i] = *lcol;
+ void *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
+ memcpy((void *)col, lcol, size);
+ col += size;
}
/* now that we have the uvs in the array, reverse! */
BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
/* current loop uv is the previous loop color */
- MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
- *lcol = cols[(f->len - i - 1)];
+ void *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
+
+ col = cols + (f->len - i - 1) * size;
+ memcpy(lcol, (void *)col, size);
}
}
+
void bmo_reverse_colors_exec(BMesh *bm, BMOperator *op)
{
BMOIter iter;
BMFace *f;
- const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
- if (cd_loop_color_offset != -1) {
- BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) {
- bm_face_reverse_colors(f, cd_loop_color_offset);
- }
+ const int color_index = BMO_slot_int_get(op->slots_in, "color_index");
+
+ int cd_loop_color_offset;
+ int cd_loop_color_type;
+
+ bmo_get_loop_color_ref(bm, color_index, &cd_loop_color_offset, &cd_loop_color_type);
+
+ if (cd_loop_color_offset == -1) {
+ BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "color_index is invalid");
+ return;
+ }
+
+ BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) {
+ bm_face_reverse_colors(f, cd_loop_color_offset, cd_loop_color_type);
}
}
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index f97db2fcda9..8da95c8387b 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -18,6 +18,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
+#include "BKE_pbvh.h"
#include "DNA_curves_types.h"
#include "DNA_fluid_types.h"
@@ -170,12 +171,7 @@ static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd,
geom = DRW_cache_mesh_surface_vertpaint_get(ob);
}
else {
- if (U.experimental.use_sculpt_vertex_colors) {
- geom = DRW_cache_mesh_surface_sculptcolors_get(ob);
- }
- else {
- geom = DRW_cache_mesh_surface_vertpaint_get(ob);
- }
+ geom = DRW_cache_mesh_surface_sculptcolors_get(ob);
}
}
else {
@@ -258,7 +254,6 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
eV3DShadingColorType color_type = wpd->shading.color_type;
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
const CustomData *ldata = (me == NULL) ? NULL : workbench_mesh_get_loop_custom_data(me);
- const CustomData *vdata = (me == NULL) ? NULL : workbench_mesh_get_vert_custom_data(me);
const DRWContextState *draw_ctx = DRW_context_state_get();
const bool is_active = (ob == draw_ctx->obact);
@@ -268,6 +263,14 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE);
const bool is_vertpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_VERTEX);
+ /* Needed for mesh cache validation, to prevent two copies of
+ * of vertex color arrays from being sent to the GPU (e.g.
+ * when switching from eevee to workbench).
+ */
+ if (ob->sculpt && ob->sculpt->pbvh) {
+ BKE_pbvh_is_drawing_set(ob->sculpt->pbvh, is_sculpt_pbvh);
+ }
+
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
if (ob->dt < OB_TEXTURE) {
color_type = V3D_SHADING_MATERIAL_COLOR;
@@ -278,13 +281,19 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
}
}
else if (color_type == V3D_SHADING_VERTEX_COLOR) {
- if (U.experimental.use_sculpt_vertex_colors) {
- if ((me == NULL) || !CustomData_has_layer(vdata, CD_PROP_COLOR)) {
- color_type = V3D_SHADING_OBJECT_COLOR;
- }
+ if (!me) {
+ color_type = V3D_SHADING_OBJECT_COLOR;
}
else {
- if ((me == NULL) || !CustomData_has_layer(ldata, CD_MLOOPCOL)) {
+ const CustomData *cd_vdata = workbench_mesh_get_vert_custom_data(me);
+ const CustomData *cd_ldata = workbench_mesh_get_loop_custom_data(me);
+
+ bool has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) ||
+ CustomData_has_layer(cd_vdata, CD_MLOOPCOL) ||
+ CustomData_has_layer(cd_ldata, CD_PROP_COLOR) ||
+ CustomData_has_layer(cd_ldata, CD_MLOOPCOL));
+
+ if (!has_color) {
color_type = V3D_SHADING_OBJECT_COLOR;
}
}
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index aaec47b4dce..4567e470146 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -308,6 +308,9 @@ typedef struct MeshBatchCache {
float tot_area, tot_uv_area;
bool no_loose_wire;
+
+ eV3DShadingColorType color_type;
+ bool pbvh_is_drawing;
} MeshBatchCache;
#define MBC_EDITUV \
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 79a080cfccd..e6f34d3dd0d 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -454,29 +454,24 @@ static void mesh_cd_calc_active_mask_uv_layer(const Object *object,
}
}
-static void mesh_cd_calc_active_vcol_layer(const Object *object,
- const Mesh *me,
- DRW_MeshAttributes *attrs_used)
-{
- const Mesh *me_final = editmesh_final_or_this(object, me);
- const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
-
- int layer = CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR);
- if (layer != -1) {
- drw_mesh_attributes_add_request(attrs_used, CD_PROP_COLOR, layer, ATTR_DOMAIN_POINT);
- }
-}
-
static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
const Mesh *me,
DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
+ Mesh me_query = {0};
+
+ const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
- int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
- if (layer != -1) {
- cd_used->vcol |= (1 << layer);
+ BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id);
+
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id);
+ int layer_i = BKE_id_attribute_to_index(
+ &me_query.id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ if (layer_i != -1) {
+ cd_used->vcol |= (1UL << (uint)layer_i);
}
}
@@ -510,6 +505,51 @@ static bool custom_data_match_attribute(const CustomData *custom_data,
return false;
}
+static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
+ const CustomData *cd_vdata,
+ const CustomData *cd_ldata,
+ const char name[])
+{
+ CustomDataLayer *layer = NULL;
+ AttributeDomain domain;
+
+ if (name[0]) {
+ int layer_i = 0;
+
+ domain = ATTR_DOMAIN_POINT;
+ layer_i = CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, name);
+ layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_vdata, CD_MLOOPCOL, name) :
+ layer_i;
+
+ if (layer_i == -1) {
+ domain = ATTR_DOMAIN_CORNER;
+ layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_ldata, CD_PROP_COLOR, name) :
+ layer_i;
+ layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_ldata, CD_MLOOPCOL, name) :
+ layer_i;
+ }
+
+ /* Note: this is not the same as the layer_i below. */
+ if (layer_i != -1) {
+ layer = (domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata)->layers + layer_i;
+ }
+ }
+ else {
+ layer = BKE_id_attributes_render_color_get(&me_query->id);
+ }
+
+ if (!layer) {
+ return -1;
+ }
+
+ /* Note: this is the logical index into the color attribute list,
+ * not the customdata index. */
+ int vcol_i = BKE_id_attribute_to_index(
+ (ID *)me_query, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ return vcol_i;
+}
+
static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
const Mesh *me,
struct GPUMaterial **gpumat_array,
@@ -522,6 +562,13 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_edata = mesh_cd_edata_get_from_mesh(me_final);
+ /* Create a mesh with final customdata domains
+ * we can query with attribute API. */
+ Mesh me_query = {0};
+
+ BKE_id_attribute_copy_domains_temp(
+ ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, NULL, &me_query.id);
+
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;
mesh_cd_layers_type_clear(&cd_used);
@@ -547,8 +594,35 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
type = CD_MTFACE;
if (layer == -1) {
+ layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name);
+ if (layer != -1) {
+ type = CD_PROP_COLOR;
+ domain = ATTR_DOMAIN_POINT;
+ }
+ }
+
+ if (layer == -1) {
+ layer = CustomData_get_named_layer(cd_ldata, CD_PROP_COLOR, name);
+ if (layer != -1) {
+ type = CD_PROP_COLOR;
+ domain = ATTR_DOMAIN_CORNER;
+ }
+ }
+
+ if (layer == -1) {
+ layer = CustomData_get_named_layer(cd_vdata, CD_MLOOPCOL, name);
+ if (layer != -1) {
+ type = CD_MLOOPCOL;
+ domain = ATTR_DOMAIN_POINT;
+ }
+ }
+
+ if (layer == -1) {
layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name);
- type = CD_MCOL;
+ if (layer != -1) {
+ type = CD_MLOOPCOL;
+ domain = ATTR_DOMAIN_CORNER;
+ }
}
#if 0 /* Tangents are always from UV's - this will never happen. */
@@ -619,29 +693,33 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
}
break;
}
- case CD_MCOL: {
- /* Vertex Color Data */
- if (layer == -1) {
- layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name) :
- CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL);
- }
- if (layer != -1) {
- cd_used.vcol |= (1 << layer);
- }
- break;
- }
case CD_ORCO: {
cd_used.orco = 1;
break;
}
+
+ /* Note: attr->type will always be CD_PROP_COLOR even for
+ * CD_MLOOPCOL layers, see node_shader_gpu_vertex_color in
+ * node_shader_vertex_color.cc.
+ */
+ case CD_MCOL:
+ case CD_MLOOPCOL:
+ case CD_PROP_COLOR: {
+ int vcol_bit = mesh_cd_calc_gpu_layers_vcol_used(&me_query, cd_vdata, cd_ldata, name);
+
+ if (vcol_bit != -1) {
+ cd_used.vcol |= 1UL << (uint)vcol_bit;
+ }
+
+ break;
+ }
+ case CD_PROP_FLOAT3:
case CD_PROP_BOOL:
case CD_PROP_INT8:
case CD_PROP_INT32:
case CD_PROP_FLOAT:
- case CD_PROP_FLOAT2:
- case CD_PROP_FLOAT3:
- case CD_PROP_COLOR: {
+ case CD_PROP_FLOAT2: {
if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
drw_mesh_attributes_add_request(attributes, type, layer, domain);
}
@@ -799,6 +877,12 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
return false;
}
+ if (object->sculpt && object->sculpt->pbvh) {
+ if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) {
+ return false;
+ }
+ }
+
if (cache->is_editmode != (me->edit_mesh != NULL)) {
return false;
}
@@ -827,6 +911,10 @@ static void mesh_batch_cache_init(Object *object, Mesh *me)
cache->is_editmode = me->edit_mesh != NULL;
+ if (object->sculpt && object->sculpt->pbvh) {
+ cache->pbvh_is_drawing = BKE_pbvh_is_drawing(object->sculpt->pbvh);
+ }
+
if (cache->is_editmode == false) {
// cache->edge_len = mesh_render_edges_len_get(me);
// cache->tri_len = mesh_render_looptri_len_get(me);
@@ -1120,14 +1208,28 @@ static void texpaint_request_active_vcol(MeshBatchCache *cache, Object *object,
static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me)
{
- DRW_MeshAttributes attrs_needed;
- drw_mesh_attributes_clear(&attrs_needed);
- mesh_cd_calc_active_vcol_layer(object, me, &attrs_needed);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
+ const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
+ const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
+
+ Mesh me_query = {0};
+ BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id);
- BLI_assert(attrs_needed.num_requests != 0 &&
- "No MPropCol layer available in Sculpt, but batches requested anyway!");
+ CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id);
+ CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id);
- drw_mesh_attributes_merge(&cache->attr_needed, &attrs_needed, me->runtime.render_mutex);
+ int active_i = BKE_id_attribute_to_index(
+ &me_query.id, active, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+ int render_i = BKE_id_attribute_to_index(
+ &me_query.id, render, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ if (active_i >= 0) {
+ cache->cd_used.vcol |= 1UL << (uint)active_i;
+ }
+
+ if (render_i >= 0) {
+ cache->cd_used.vcol |= 1UL << (uint)render_i;
+ }
}
GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me)
@@ -1148,6 +1250,7 @@ GPUBatch *DRW_mesh_batch_cache_get_surface(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_request_surface_batches(cache);
+
return cache->batch.surface;
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
index 4f4aa764fbc..f9e58709c6e 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -159,17 +159,6 @@ static void init_vbo_for_attribute(const MeshRenderData *mr,
GPU_vertformat_deinterleave(&format);
GPU_vertformat_attr_add(&format, attr_name, comp_type, comp_size, fetch_mode);
- /* Ensure Sculpt Vertex Colors are properly aliased. */
- if (request.cd_type == CD_PROP_COLOR && request.domain == ATTR_DOMAIN_POINT) {
- CustomData *cd_vdata = get_custom_data_for_domain(mr, ATTR_DOMAIN_POINT);
- if (request.layer_index == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) {
- GPU_vertformat_alias_add(&format, "c");
- }
- if (request.layer_index == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) {
- GPU_vertformat_alias_add(&format, "ac");
- }
- }
-
if (build_on_device) {
GPU_vertbuf_init_build_on_device(vbo, &format, len);
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
index 7a8f4a9a17e..7d159eb3df2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
@@ -7,11 +7,63 @@
#include "MEM_guardedalloc.h"
+#include "BKE_attribute.h"
#include "BLI_string.h"
+#include "BLI_vector.hh"
#include "draw_subdivision.h"
#include "extract_mesh.h"
+struct VColRef {
+ const CustomDataLayer *layer;
+ AttributeDomain domain;
+};
+
+/** Get all vcol layers as AttributeRefs.
+ *
+ * \param vcol_layers: bitmask to filter vcol layers by, each bit
+ * corresponds to the integer position of the attribute
+ * within the global color attribute list.
+ */
+static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
+ const CustomData *cd_ldata,
+ const uint vcol_layers)
+{
+ blender::Vector<VColRef> refs;
+ uint layeri = 0;
+
+ auto buildList = [&](const CustomData *cdata, AttributeDomain domain) {
+ for (int i = 0; i < cdata->totlayer; i++) {
+ const CustomDataLayer *layer = cdata->layers + i;
+
+ if (!(CD_TYPE_AS_MASK(layer->type) & CD_MASK_COLOR_ALL)) {
+ continue;
+ }
+
+ if (layer->flag & CD_FLAG_TEMPORARY) {
+ continue;
+ }
+
+ if (!(vcol_layers & (1UL << layeri))) {
+ layeri++;
+ continue;
+ }
+
+ VColRef ref;
+ ref.domain = domain;
+ ref.layer = layer;
+
+ refs.append(ref);
+ layeri++;
+ }
+ };
+
+ buildList(cd_vdata, ATTR_DOMAIN_POINT);
+ buildList(cd_ldata, ATTR_DOMAIN_CORNER);
+
+ return refs;
+}
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -21,34 +73,44 @@ namespace blender::draw {
/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */
static void init_vcol_format(GPUVertFormat *format,
const MeshBatchCache *cache,
- CustomData *cd_ldata)
+ CustomData *cd_vdata,
+ CustomData *cd_ldata,
+ CustomDataLayer *active,
+ CustomDataLayer *render)
{
GPU_vertformat_deinterleave(format);
const uint32_t vcol_layers = cache->cd_used.vcol;
- for (int i = 0; i < MAX_MCOL; i++) {
- if (vcol_layers & (1 << i)) {
- char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
- GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+ blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
- BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
- GPU_vertformat_attr_add(format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ for (const VColRef &ref : refs) {
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
- GPU_vertformat_alias_add(format, "c");
- }
- if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) {
- GPU_vertformat_alias_add(format, "ac");
- }
+ GPU_vertformat_safe_attr_name(ref.layer->name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
- /* Gather number of auto layers. */
- /* We only do `vcols` that are not overridden by `uvs`. */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
- BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(format, attr_name);
- }
+ /* VCol layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
+ GPU_vertformat_attr_add(format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ /* Active layer name. */
+ if (ref.layer == active) {
+ GPU_vertformat_alias_add(format, "ac");
+ }
+
+ /* Active render layer name. */
+ if (ref.layer == render) {
+ GPU_vertformat_alias_add(format, "c");
+ }
+
+ /* Gather number of auto layers. */
+ /* We only do `vcols` that are not overridden by `uvs`. */
+ bool bad = ref.domain == ATTR_DOMAIN_CORNER;
+ bad = bad && CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, ref.layer->name) != -1;
+
+ if (!bad) {
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+ GPU_vertformat_alias_add(format, attr_name);
}
}
}
@@ -77,41 +139,101 @@ static void extract_vcol_init(const MeshRenderData *mr,
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
GPUVertFormat format = {0};
+
+ CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+
+ Mesh me_query = {0};
+
+ BKE_id_attribute_copy_domains_temp(
+ ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
+
+ CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
+ CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
+
const uint32_t vcol_layers = cache->cd_used.vcol;
- init_vcol_format(&format, cache, cd_ldata);
+ init_vcol_format(&format, cache, cd_vdata, cd_ldata, active_color, render_color);
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
- for (int i = 0; i < MAX_MCOL; i++) {
- if (vcol_layers & (1 << i)) {
- if (mr->extract_type == MR_EXTRACT_BMESH) {
- int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i);
- BMIter f_iter;
- BMFace *efa;
- BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const MLoopCol *mloopcol = (const MLoopCol *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs);
+ blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+
+ for (const VColRef &ref : refs) {
+ CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ int cd_ofs = ref.layer->offset;
+
+ if (cd_ofs == -1) {
+ vcol_data += ref.domain == ATTR_DOMAIN_POINT ? mr->bm->totvert : mr->bm->totloop;
+ continue;
+ }
+
+ BMIter iter;
+ const bool is_byte = ref.layer->type == CD_MLOOPCOL;
+ const bool is_point = ref.domain == ATTR_DOMAIN_POINT;
+
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) {
+ BMLoop *l_iter = f->l_first;
+ do {
+ BMElem *elem = is_point ? reinterpret_cast<BMElem *>(l_iter->v) :
+ reinterpret_cast<BMElem *>(l_iter);
+ if (is_byte) {
+ const MLoopCol *mloopcol = (const MLoopCol *)BM_ELEM_CD_GET_VOID_P(elem, cd_ofs);
vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
vcol_data++;
- } while ((l_iter = l_iter->next) != l_first);
- }
+ }
+ else {
+ const MPropCol *mpcol = (const MPropCol *)BM_ELEM_CD_GET_VOID_P(elem, cd_ofs);
+ vcol_data->r = unit_float_to_ushort_clamp(mpcol->color[0]);
+ vcol_data->g = unit_float_to_ushort_clamp(mpcol->color[1]);
+ vcol_data->b = unit_float_to_ushort_clamp(mpcol->color[2]);
+ vcol_data->a = unit_float_to_ushort_clamp(mpcol->color[3]);
+ vcol_data++;
+ }
+ } while ((l_iter = l_iter->next) != f->l_first);
+ }
+ }
+ else {
+ int totloop = mr->loop_len;
+ int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
+
+ MLoopCol *mcol = nullptr;
+ MPropCol *pcol = nullptr;
+ const MLoop *mloop = mr->mloop;
+
+ if (ref.layer->type == CD_PROP_COLOR) {
+ pcol = static_cast<MPropCol *>(cdata->layers[idx].data);
}
else {
- const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
- for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, mloopcol++, vcol_data++) {
- vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
- vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
- vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
- vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
+ mcol = static_cast<MLoopCol *>(cdata->layers[idx].data);
+ }
+
+ const bool is_corner = ref.domain == ATTR_DOMAIN_CORNER;
+
+ for (int i = 0; i < totloop; i++, mloop++) {
+ const int v_i = is_corner ? i : mloop->v;
+
+ if (mcol) {
+ vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[v_i].r]);
+ vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[v_i].g]);
+ vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[v_i].b]);
+ vcol_data->a = unit_float_to_ushort_clamp(mcol[v_i].a * (1.0f / 255.0f));
+ vcol_data++;
+ }
+ else if (pcol) {
+ vcol_data->r = unit_float_to_ushort_clamp(pcol[v_i].color[0]);
+ vcol_data->g = unit_float_to_ushort_clamp(pcol[v_i].color[1]);
+ vcol_data->b = unit_float_to_ushort_clamp(pcol[v_i].color[2]);
+ vcol_data->a = unit_float_to_ushort_clamp(pcol[v_i].color[3]);
+ vcol_data++;
}
}
}
@@ -119,7 +241,7 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *UNUSED(mr),
+ const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
@@ -127,8 +249,23 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
Mesh *coarse_mesh = subdiv_cache->mesh;
+ bool extract_bmesh = mr->extract_type == MR_EXTRACT_BMESH;
+
+ const CustomData *cd_vdata = extract_bmesh ? &coarse_mesh->edit_mesh->bm->vdata :
+ &coarse_mesh->vdata;
+ const CustomData *cd_ldata = extract_bmesh ? &coarse_mesh->edit_mesh->bm->ldata :
+ &coarse_mesh->ldata;
+
+ Mesh me_query = *coarse_mesh;
+ BKE_id_attribute_copy_domains_temp(
+ ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
+
+ CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
+ CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
+
GPUVertFormat format = {0};
- init_vcol_format(&format, cache, &coarse_mesh->ldata);
+ init_vcol_format(
+ &format, cache, &coarse_mesh->vdata, &coarse_mesh->ldata, active_color, render_color);
GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
@@ -140,32 +277,97 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data);
- const CustomData *cd_ldata = &coarse_mesh->ldata;
-
const uint vcol_layers = cache->cd_used.vcol;
+ blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+
+ gpuMeshVcol *vcol = mesh_vcol;
+
/* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in
* a single buffer. */
int pack_layer_index = 0;
- for (int i = 0; i < MAX_MTFACE; i++) {
- if (vcol_layers & (1 << i)) {
- /* Include stride in offset, we use a stride of 2 since colors are packed into 2 uints. */
- const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++;
- const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
-
- gpuMeshVcol *vcol = mesh_vcol;
-
- for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, mloopcol++) {
- vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
- vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
- vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
- vcol->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
- }
+ for (const VColRef &ref : refs) {
+ /* Include stride in offset, we use a stride of 2 since colors are packed into 2 uints. */
+ const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++;
+
+ const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
+ const MLoop *ml = coarse_mesh->mloop;
+
+ int layer_i = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
- /* Ensure data is uploaded properly. */
- GPU_vertbuf_tag_dirty(src_data);
- draw_subdiv_interp_custom_data(subdiv_cache, src_data, dst_buffer, 4, dst_offset, true);
+ if (layer_i == -1) {
+ printf("%s: missing color layer %s\n", __func__, ref.layer->name);
+ vcol += coarse_mesh->totloop;
+ continue;
+ }
+
+ MLoopCol *mcol = nullptr;
+ MPropCol *pcol = nullptr;
+
+ if (ref.layer->type == CD_PROP_COLOR) {
+ pcol = static_cast<MPropCol *>(cdata->layers[layer_i].data);
+ }
+ else {
+ mcol = static_cast<MLoopCol *>(cdata->layers[layer_i].data);
}
+
+ const bool is_vert = ref.domain == ATTR_DOMAIN_POINT;
+
+ if (extract_bmesh) {
+ BMesh *bm = coarse_mesh->edit_mesh->bm;
+ BMIter iter;
+ BMFace *f;
+ int cd_ofs = cdata->layers[layer_i].offset;
+ const bool is_byte = ref.layer->type == CD_MLOOPCOL;
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ BMLoop *l_iter = f->l_first;
+
+ do {
+ BMElem *elem = is_vert ? reinterpret_cast<BMElem *>(l_iter->v) :
+ reinterpret_cast<BMElem *>(l_iter);
+
+ if (is_byte) {
+ MLoopCol *mcol2 = static_cast<MLoopCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
+
+ vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
+ vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
+ vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->b]);
+ vcol->a = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
+ }
+ else {
+ MPropCol *pcol2 = static_cast<MPropCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
+
+ vcol->r = unit_float_to_ushort_clamp(pcol2->color[0]);
+ vcol->g = unit_float_to_ushort_clamp(pcol2->color[1]);
+ vcol->b = unit_float_to_ushort_clamp(pcol2->color[2]);
+ vcol->a = unit_float_to_ushort_clamp(pcol2->color[3]);
+ }
+ } while ((l_iter = l_iter->next) != f->l_first);
+ }
+ }
+ else {
+ for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, ml++) {
+ int idx = is_vert ? ml->v : ml_index;
+
+ if (mcol) {
+ vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[idx].r]);
+ vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[idx].g]);
+ vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[idx].b]);
+ vcol->a = unit_float_to_ushort_clamp(mcol[idx].a * (1.0f / 255.0f));
+ }
+ else if (pcol) {
+ vcol->r = unit_float_to_ushort_clamp(pcol[idx].color[0]);
+ vcol->g = unit_float_to_ushort_clamp(pcol[idx].color[1]);
+ vcol->b = unit_float_to_ushort_clamp(pcol[idx].color[2]);
+ vcol->a = unit_float_to_ushort_clamp(pcol[idx].color[3]);
+ }
+ }
+ }
+
+ /* Ensure data is uploaded properly. */
+ GPU_vertbuf_tag_dirty(src_data);
+ draw_subdiv_interp_custom_data(subdiv_cache, src_data, dst_buffer, 4, dst_offset, true);
}
GPU_vertbuf_discard(src_data);
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);
}
/** \} */
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 610b0f384a2..1af0080baef 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -9,6 +9,8 @@
#include <stddef.h>
+#include "BKE_attribute.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -82,11 +84,12 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
const float (*vert_normals)[3],
const float *vmask,
- const struct MLoopCol *vcol,
+ const void *vcol_data,
+ int vcol_type,
+ AttributeDomain vcol_domain,
const int *sculpt_face_sets,
int face_sets_color_seed,
int face_sets_color_default,
- const struct MPropCol *vtcol,
int update_flags);
/**
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index b90dd9c2a8a..110fdfbd2d9 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -25,7 +25,9 @@
#include "DNA_userdef_types.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_attribute.h"
#include "BKE_ccg.h"
+#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
@@ -196,18 +198,25 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
const float (*vert_normals)[3],
const float *vmask,
- const MLoopCol *vcol,
+ const void *vcol_data,
+ int vcol_type,
+ AttributeDomain vcol_domain,
const int *sculpt_face_sets,
- const int face_sets_color_seed,
- const int face_sets_color_default,
- const MPropCol *vtcol,
- const int update_flags)
+ int face_sets_color_seed,
+ int face_sets_color_default,
+ int update_flags)
{
+ const MPropCol *vtcol = vcol_type == CD_PROP_COLOR ? vcol_data : NULL;
+ const MLoopCol *vcol = vcol_type == CD_MLOOPCOL ? vcol_data : NULL;
+ const float(*f3col)[3] = vcol_type == CD_PROP_FLOAT3 ? vcol_data : NULL;
+
+ const bool color_loops = vcol_domain == ATTR_DOMAIN_CORNER;
+ const bool show_vcol = (vtcol || vcol || f3col) &&
+ (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+
const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_face_sets = sculpt_face_sets &&
(update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0;
- const bool show_vcol = (vcol || (vtcol && U.experimental.use_sculpt_vertex_colors)) &&
- (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
bool empty_mask = true;
bool default_face_set = true;
@@ -290,16 +299,40 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Vertex Colors. */
if (show_vcol) {
ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- if (vtcol && U.experimental.use_sculpt_vertex_colors) {
- scol[0] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[0]);
- scol[1] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[1]);
- scol[2] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[2]);
- scol[3] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[3]);
+ if (vtcol) {
+ if (color_loops) {
+ scol[0] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[0]);
+ scol[1] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[1]);
+ scol[2] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[2]);
+ scol[3] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[3]);
+ }
+ else {
+ scol[0] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[0]);
+ scol[1] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[1]);
+ scol[2] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[2]);
+ scol[3] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[3]);
+ }
memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
}
- else {
+ else if (f3col) {
+ if (color_loops) {
+ scol[0] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][0]);
+ scol[1] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][1]);
+ scol[2] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][2]);
+ scol[3] = USHRT_MAX;
+ }
+ else {
+ scol[0] = unit_float_to_ushort_clamp(f3col[vtri[j]][0]);
+ scol[1] = unit_float_to_ushort_clamp(f3col[vtri[j]][1]);
+ scol[2] = unit_float_to_ushort_clamp(f3col[vtri[j]][2]);
+ scol[3] = USHRT_MAX;
+ }
+ memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
+ }
+ else if (vcol) {
const uint loop_index = lt->tri[j];
- const MLoopCol *mcol = &vcol[loop_index];
+ const MLoopCol *mcol = vcol + (color_loops ? loop_index : vtri[j]);
+
scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index a96f157981f..e462308d3ee 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -635,6 +635,7 @@ static const char *attr_prefix_get(CustomDataType type)
case CD_TANGENT:
return "t";
case CD_MCOL:
+ case CD_MLOOPCOL:
return "c";
case CD_PROP_COLOR:
return "c";
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 05d300dcb63..858de733558 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -227,6 +227,9 @@ typedef enum CustomDataType {
CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_MLOOPCOL | CD_MASK_PROP_BOOL | \
CD_MASK_PROP_INT8)
+/* All color attributes */
+#define CD_MASK_COLOR_ALL (CD_MASK_PROP_COLOR | CD_MASK_MLOOPCOL)
+
typedef struct CustomData_MeshMasks {
uint64_t vmask;
uint64_t emask;
@@ -247,6 +250,8 @@ enum {
CD_FLAG_EXTERNAL = (1 << 3),
/* Indicates external data is read into memory */
CD_FLAG_IN_MEMORY = (1 << 4),
+ CD_FLAG_COLOR_ACTIVE = (1 << 5),
+ CD_FLAG_COLOR_RENDER = (1 << 6)
};
/* Limits */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 11825de4b33..73c4eeaaab3 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -2103,9 +2103,9 @@ typedef struct DataTransferModifierData {
char _pad1[4];
/** DT_MULTILAYER_INDEX_MAX; See DT_FROMLAYERS_ enum in ED_object.h. */
- int layers_select_src[4];
+ int layers_select_src[5];
/** DT_MULTILAYER_INDEX_MAX; See DT_TOLAYERS_ enum in ED_object.h. */
- int layers_select_dst[4];
+ int layers_select_dst[5];
/** See CDT_MIX_ enum in BKE_customdata.h. */
int mix_mode;
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 8a698050629..0f6c32e4ddf 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -645,7 +645,6 @@ typedef struct UserDef_Experimental {
char use_new_curves_type;
char use_new_point_cloud_type;
char use_full_frame_compositor;
- char use_sculpt_vertex_colors;
char use_sculpt_tools_tilt;
char use_extended_asset_browser;
char use_override_templates;
@@ -653,7 +652,6 @@ typedef struct UserDef_Experimental {
char use_select_nearest_on_first_click;
char enable_eevee_next;
char use_sculpt_texture_paint;
- char _pad[7];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index f86383a6328..01266a26104 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -339,6 +339,12 @@ static int rna_Attributes_layer_skip(CollectionPropertyIterator *UNUSED(iter), v
return !(CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL);
}
+static int rna_Attributes_noncolor_layer_skip(CollectionPropertyIterator *UNUSED(iter), void *data)
+{
+ CustomDataLayer *layer = (CustomDataLayer *)data;
+ return !(CD_TYPE_AS_MASK(layer->type) & CD_MASK_COLOR_ALL) || (layer->flag & CD_FLAG_TEMPORARY);
+}
+
/* Attributes are spread over multiple domains in separate CustomData, we use repeated
* array iterators to loop over all. */
static void rna_AttributeGroup_next_domain(ID *id,
@@ -377,7 +383,34 @@ void rna_AttributeGroup_iterator_next(CollectionPropertyIterator *iter)
PointerRNA rna_AttributeGroup_iterator_get(CollectionPropertyIterator *iter)
{
- /* refine to the proper type */
+ /* Refine to the proper type. */
+ CustomDataLayer *layer = rna_iterator_array_get(iter);
+ StructRNA *type = srna_by_custom_data_layer_type(layer->type);
+ if (type == NULL) {
+ return PointerRNA_NULL;
+ }
+ return rna_pointer_inherit_refine(&iter->parent, type, layer);
+}
+
+void rna_AttributeGroup_color_iterator_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ memset(&iter->internal.array, 0, sizeof(iter->internal.array));
+ rna_AttributeGroup_next_domain(ptr->owner_id, iter, rna_Attributes_noncolor_layer_skip);
+}
+
+void rna_AttributeGroup_color_iterator_next(CollectionPropertyIterator *iter)
+{
+ rna_iterator_array_next(iter);
+
+ if (!iter->valid) {
+ ID *id = iter->parent.owner_id;
+ rna_AttributeGroup_next_domain(id, iter, rna_Attributes_noncolor_layer_skip);
+ }
+}
+
+PointerRNA rna_AttributeGroup_color_iterator_get(CollectionPropertyIterator *iter)
+{
+ /* Refine to the proper type. */
CustomDataLayer *layer = rna_iterator_array_get(iter);
StructRNA *type = srna_by_custom_data_layer_type(layer->type);
if (type == NULL) {
@@ -386,9 +419,16 @@ PointerRNA rna_AttributeGroup_iterator_get(CollectionPropertyIterator *iter)
return rna_pointer_inherit_refine(&iter->parent, type, layer);
}
+int rna_AttributeGroup_color_length(PointerRNA *ptr)
+{
+ return BKE_id_attributes_length(ptr->owner_id,
+ ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER,
+ CD_MASK_PROP_COLOR | CD_MASK_MLOOPCOL);
+}
+
int rna_AttributeGroup_length(PointerRNA *ptr)
{
- return BKE_id_attributes_length(ptr->owner_id, CD_MASK_PROP_ALL);
+ return BKE_id_attributes_length(ptr->owner_id, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL);
}
static int rna_AttributeGroup_active_index_get(PointerRNA *ptr)
@@ -424,7 +464,7 @@ static void rna_AttributeGroup_active_index_range(
PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
{
*min = 0;
- *max = BKE_id_attributes_length(ptr->owner_id, CD_MASK_PROP_ALL);
+ *max = BKE_id_attributes_length(ptr->owner_id, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL);
*softmin = *min;
*softmax = *max;
@@ -435,6 +475,98 @@ static void rna_AttributeGroup_update_active(Main *bmain, Scene *scene, PointerR
rna_Attribute_update_data(bmain, scene, ptr);
}
+static PointerRNA rna_AttributeGroup_active_color_get(PointerRNA *ptr)
+{
+ ID *id = ptr->owner_id;
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
+
+ PointerRNA attribute_ptr;
+ RNA_pointer_create(id, &RNA_Attribute, layer, &attribute_ptr);
+ return attribute_ptr;
+}
+
+static void rna_AttributeGroup_active_color_set(PointerRNA *ptr,
+ PointerRNA attribute_ptr,
+ ReportList *UNUSED(reports))
+{
+ ID *id = ptr->owner_id;
+ CustomDataLayer *layer = attribute_ptr.data;
+
+ BKE_id_attributes_active_color_set(id, layer);
+}
+
+static int rna_AttributeGroup_active_color_index_get(PointerRNA *ptr)
+{
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id);
+
+ return BKE_id_attribute_to_index(
+ ptr->owner_id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+}
+
+static void rna_AttributeGroup_active_color_index_set(PointerRNA *ptr, int value)
+{
+ CustomDataLayer *layer = BKE_id_attribute_from_index(
+ ptr->owner_id, value, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ if (!layer) {
+ fprintf(stderr, "%s: error setting active color index to %d\n", __func__, value);
+ return;
+ }
+
+ BKE_id_attributes_active_color_set(ptr->owner_id, layer);
+}
+
+static void rna_AttributeGroup_active_color_index_range(
+ PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
+{
+ *min = 0;
+ *max = BKE_id_attributes_length(ptr->owner_id, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ *softmin = *min;
+ *softmax = *max;
+}
+
+static void rna_AttributeGroup_update_active_color(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ID *id = ptr->owner_id;
+
+ /* Cheating way for importers to avoid slow updates. */
+ if (id->us > 0) {
+ DEG_id_tag_update(id, 0);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+ }
+}
+
+static int rna_AttributeGroup_render_color_index_get(PointerRNA *ptr)
+{
+ CustomDataLayer *layer = BKE_id_attributes_render_color_get(ptr->owner_id);
+
+ return BKE_id_attribute_to_index(
+ ptr->owner_id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+}
+
+static void rna_AttributeGroup_render_color_index_set(PointerRNA *ptr, int value)
+{
+ CustomDataLayer *layer = BKE_id_attribute_from_index(
+ ptr->owner_id, value, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ if (!layer) {
+ fprintf(stderr, "%s: error setting render color index to %d\n", __func__, value);
+ return;
+ }
+
+ BKE_id_attributes_render_color_set(ptr->owner_id, layer);
+}
+
+static void rna_AttributeGroup_render_color_index_range(
+ PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
+{
+ *min = 0;
+ *max = BKE_id_attributes_length(ptr->owner_id, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
+
+ *softmin = *min;
+ *softmax = *max;
+}
#else
static void rna_def_attribute_float(BlenderRNA *brna)
@@ -826,6 +958,33 @@ static void rna_def_attribute_group(BlenderRNA *brna)
"rna_AttributeGroup_active_index_set",
"rna_AttributeGroup_active_index_range");
RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active");
+
+ prop = RNA_def_property(srna, "active_color", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Attribute");
+ RNA_def_property_pointer_funcs(prop,
+ "rna_AttributeGroup_active_color_get",
+ "rna_AttributeGroup_active_color_set",
+ NULL,
+ NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
+ RNA_def_property_ui_text(prop, "Active Color", "Active color attribute");
+ RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active_color");
+
+ prop = RNA_def_property(srna, "active_color_index", PROP_INT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_funcs(prop,
+ "rna_AttributeGroup_active_color_index_get",
+ "rna_AttributeGroup_active_color_index_set",
+ "rna_AttributeGroup_active_color_index_range");
+ RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active_color");
+
+ prop = RNA_def_property(srna, "render_color_index", PROP_INT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_funcs(prop,
+ "rna_AttributeGroup_render_color_index_get",
+ "rna_AttributeGroup_render_color_index_set",
+ "rna_AttributeGroup_render_color_index_range");
+ RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active_color");
}
void rna_def_attributes_common(StructRNA *srna)
@@ -846,6 +1005,20 @@ void rna_def_attributes_common(StructRNA *srna)
RNA_def_property_struct_type(prop, "Attribute");
RNA_def_property_ui_text(prop, "Attributes", "Geometry attributes");
RNA_def_property_srna(prop, "AttributeGroup");
+
+ prop = RNA_def_property(srna, "color_attributes", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop,
+ "rna_AttributeGroup_color_iterator_begin",
+ "rna_AttributeGroup_color_iterator_next",
+ "rna_iterator_array_end",
+ "rna_AttributeGroup_color_iterator_get",
+ "rna_AttributeGroup_color_length",
+ NULL,
+ NULL,
+ NULL);
+ RNA_def_property_struct_type(prop, "Attribute");
+ RNA_def_property_ui_text(prop, "Color Attributes", "Geometry color attributes");
+ RNA_def_property_srna(prop, "AttributeGroup");
}
void RNA_def_attribute(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 0df0be07fee..ba040f88b55 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -217,6 +217,11 @@ void rna_AttributeGroup_iterator_next(CollectionPropertyIterator *iter);
PointerRNA rna_AttributeGroup_iterator_get(CollectionPropertyIterator *iter);
int rna_AttributeGroup_length(PointerRNA *ptr);
+void rna_AttributeGroup_color_iterator_begin(CollectionPropertyIterator *iter, PointerRNA *ptr);
+void rna_AttributeGroup_color_iterator_next(CollectionPropertyIterator *iter);
+PointerRNA rna_AttributeGroup_color_iterator_get(CollectionPropertyIterator *iter);
+int rna_AttributeGroup_color_length(PointerRNA *ptr);
+
void rna_def_animdata_common(struct StructRNA *srna);
bool rna_AnimaData_override_apply(struct Main *bmain,
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 4f9a10c9993..54031f5a416 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -23,6 +23,7 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
+#include "BKE_attribute.h"
#include "BKE_curveprofile.h"
#include "BKE_data_transfer.h"
#include "BKE_dynamicpaint.h"
@@ -1360,29 +1361,47 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
}
}
}
- else if (STREQ(RNA_property_identifier(prop), "layers_vcol_select_src")) {
+ else if (STREQ(RNA_property_identifier(prop), "layers_vcol_select_vert_src") ||
+ STREQ(RNA_property_identifier(prop), "layers_vcol_select_loop_src")) {
Object *ob_src = dtmd->ob_source;
if (ob_src) {
- Mesh *me_eval;
- int num_data, i;
+ AttributeDomain domain = STREQ(RNA_property_identifier(prop),
+ "layers_vcol_select_vert_src") ?
+ ATTR_DOMAIN_POINT :
+ ATTR_DOMAIN_CORNER;
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;
- me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks);
- num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL);
+ CustomData *cdata;
- RNA_enum_item_add_separator(&item, &totitem);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks);
- for (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);
+ if (domain == ATTR_DOMAIN_POINT) {
+ cddata_masks.vmask |= CD_MASK_COLOR_ALL;
+ cdata = &me_eval->vdata;
+ }
+ else {
+ cddata_masks.lmask |= CD_MASK_COLOR_ALL;
+ cdata = &me_eval->ldata;
+ }
+
+ CustomDataType types[2] = {CD_PROP_COLOR, CD_MLOOPCOL};
+
+ int idx = 0;
+ for (int i = 0; i < 2; i++) {
+ int num_data = CustomData_number_of_layers(cdata, types[i]);
+
+ RNA_enum_item_add_separator(&item, &totitem);
+
+ for (int j = 0; j < num_data; j++) {
+ tmp_item.value = idx++;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(cdata, types[i], j);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
+ }
}
}
}
@@ -1459,26 +1478,31 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf(
}
}
}
- else if (STREQ(RNA_property_identifier(prop), "layers_vcol_select_dst")) {
+ else if (STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_dst") ||
+ STREQ(RNA_property_identifier(prop), "layers_vcol_loop_select_dst")) {
/* Only list destination layers if we have a single source! */
- if (dtmd->layers_select_src[DT_MULTILAYER_INDEX_VCOL] >= 0) {
+ if (dtmd->layers_select_src[DT_MULTILAYER_INDEX_VCOL_LOOP] >= 0) {
Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */
if (ob_dst && ob_dst->data) {
- Mesh *me_dst;
- CustomData *ldata;
- int num_data, i;
+ CustomDataType types[2] = {CD_PROP_COLOR, CD_MLOOPCOL};
- me_dst = ob_dst->data;
- ldata = &me_dst->ldata;
- num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ Mesh *me_dst = ob_dst->data;
+ CustomData *cdata = STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_dst") ?
+ &me_dst->vdata :
+ &me_dst->ldata;
- RNA_enum_item_add_separator(&item, &totitem);
+ int idx = 0;
+ for (int i = 0; i < 2; i++) {
+ int num_data = CustomData_number_of_layers(cdata, types[i]);
- for (i = 0; i < num_data; i++) {
- tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i);
- RNA_enum_item_add(&item, &totitem, &tmp_item);
+ RNA_enum_item_add_separator(&item, &totitem);
+
+ for (int j = 0; j < num_data; j++) {
+ tmp_item.value = idx++;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(cdata, types[i], j);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
+ }
}
}
}
@@ -6330,6 +6354,11 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
{DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"},
# endif
{DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"},
+ {DT_TYPE_MPROPCOL_VERT | DT_TYPE_MLOOPCOL_VERT,
+ "VCOL",
+ 0,
+ "Colors",
+ "Transfer color attributes"},
{0, NULL, 0, NULL, NULL},
};
@@ -6344,7 +6373,11 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
static const EnumPropertyItem DT_layer_loop_items[] = {
{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",
+ "Transfer color attributes"},
{DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
{0, NULL, 0, NULL, NULL},
};
@@ -6562,12 +6595,23 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
# endif
prop = RNA_def_enum(srna,
- "layers_vcol_select_src",
+ "layers_vcol_vert_select_src",
rna_enum_dt_layers_select_src_items,
DT_LAYERS_ALL_SRC,
"Source Layers Selection",
"Which layers to transfer, in case of multi-layers types");
- RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_VCOL]");
+ RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_VCOL_VERT]");
+ RNA_def_property_enum_funcs(
+ prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_enum(srna,
+ "layers_vcol_loop_select_src",
+ rna_enum_dt_layers_select_src_items,
+ DT_LAYERS_ALL_SRC,
+ "Source Layers Selection",
+ "Which layers to transfer, in case of multi-layers types");
+ RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_VCOL_LOOP]");
RNA_def_property_enum_funcs(
prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -6608,12 +6652,23 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
# endif
prop = RNA_def_enum(srna,
- "layers_vcol_select_dst",
+ "layers_vcol_vert_select_dst",
+ rna_enum_dt_layers_select_dst_items,
+ DT_LAYERS_NAME_DST,
+ "Destination Layers Matching",
+ "How to match source and destination layers");
+ RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_VCOL_VERT]");
+ RNA_def_property_enum_funcs(
+ prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_enum(srna,
+ "layers_vcol_loop_select_dst",
rna_enum_dt_layers_select_dst_items,
DT_LAYERS_NAME_DST,
"Destination Layers Matching",
"How to match source and destination layers");
- RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_VCOL]");
+ RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_VCOL_LOOP]");
RNA_def_property_enum_funcs(
prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 70b335446fc..cbac6aefc10 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -6056,7 +6056,7 @@ static void def_sh_vertex_color(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeShaderVertexColor", "storage");
prop = RNA_def_property(srna, "layer_name", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Vertex Color", "Vertex Color");
+ RNA_def_property_ui_text(prop, "Color Attribute", "Color Attribute");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "bNode", NULL);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 0960d246257..7095d8a4172 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -447,8 +447,8 @@ const EnumPropertyItem rna_enum_bake_target_items[] = {
{R_BAKE_TARGET_VERTEX_COLORS,
"VERTEX_COLORS",
0,
- "Vertex Colors",
- "Bake to active vertex color layer on meshes"},
+ "Color Attributes",
+ "Bake to active color attribute layer on meshes"},
{0, NULL, 0, NULL, NULL},
};
@@ -3204,7 +3204,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "uvcalc_flag", UVCALC_TRANSFORM_CORRECT);
RNA_def_property_ui_text(prop,
"Correct Face Attributes",
- "Correct data such as UV's and vertex colors when transforming");
+ "Correct data such as UV's and color attributes when transforming");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_transform_correct_keep_connected", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 75b41e4c7b9..200e1d65caf 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -357,7 +357,7 @@ void RNA_api_scene(StructRNA *srna)
RNA_def_boolean(func, "selected_only", 0, "Selected only", "Export only selected objects");
RNA_def_boolean(func, "uvs", 1, "UVs", "Export UVs");
RNA_def_boolean(func, "normals", 1, "Normals", "Export normals");
- RNA_def_boolean(func, "vcolors", 0, "Vertex colors", "Export vertex colors");
+ RNA_def_boolean(func, "vcolors", 0, "Color Attributes", "Export color attributes");
RNA_def_boolean(
func, "apply_subdiv", 1, "Subsurfs as meshes", "Export subdivision surfaces as meshes");
RNA_def_boolean(func, "flatten", 0, "Flatten hierarchy", "Flatten hierarchy");
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 97e1f325816..1ea7b35cedb 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -78,8 +78,8 @@ static const EnumPropertyItem rna_enum_gpencil_paint_mode[] = {
{GPPAINT_FLAG_USE_VERTEXCOLOR,
"VERTEXCOLOR",
0,
- "Vertex Color",
- "Paint the material with custom vertex color"},
+ "Color Attribute",
+ "Paint the material with a color attribute"},
{0, NULL, 0, NULL, NULL},
};
#endif
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index ff272c34c65..a74019f9569 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -424,7 +424,7 @@ static const EnumPropertyItem rna_enum_shading_color_type_items[] = {
{V3D_SHADING_SINGLE_COLOR, "SINGLE", 0, "Single", "Show scene in a single color"},
{V3D_SHADING_OBJECT_COLOR, "OBJECT", 0, "Object", "Show object color"},
{V3D_SHADING_RANDOM_COLOR, "RANDOM", 0, "Random", "Show random object color"},
- {V3D_SHADING_VERTEX_COLOR, "VERTEX", 0, "Vertex", "Show active vertex color"},
+ {V3D_SHADING_VERTEX_COLOR, "VERTEX", 0, "Color", "Show active color attribute"},
{V3D_SHADING_TEXTURE_COLOR, "TEXTURE", 0, "Texture", "Show texture"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index cbc13943c1f..cf622818a3d 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6399,10 +6399,6 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Cycles Debug", "Enable Cycles debugging options for developers");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "use_sculpt_vertex_colors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_sculpt_vertex_colors", 1);
- RNA_def_property_ui_text(prop, "Sculpt Vertex Colors", "Use the new Vertex Painting system");
-
prop = RNA_def_property(srna, "use_sculpt_tools_tilt", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_sculpt_tools_tilt", 1);
RNA_def_property_ui_text(
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index fa50403d91a..a3b088799cc 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -346,6 +346,22 @@ static void face_corner_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "loop_mapping", 0, IFACE_("Mapping"), ICON_NONE);
}
+static void vert_vcol_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiLayoutSetActive(layout,
+ RNA_enum_get(ptr, "data_types_verts") &
+ (DT_TYPE_MPROPCOL_VERT | DT_TYPE_MLOOPCOL_VERT));
+
+ uiItemR(layout, ptr, "layers_vcol_vert_select_src", 0, IFACE_("Layer Selection"), ICON_NONE);
+ uiItemR(layout, ptr, "layers_vcol_vert_select_dst", 0, IFACE_("Layer Mapping"), ICON_NONE);
+}
+
static void face_corner_vcol_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -354,10 +370,12 @@ static void face_corner_vcol_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
- uiLayoutSetActive(layout, RNA_enum_get(ptr, "data_types_loops") & DT_TYPE_VCOL);
+ uiLayoutSetActive(layout,
+ RNA_enum_get(ptr, "data_types_loops") &
+ (DT_TYPE_MPROPCOL_LOOP | DT_TYPE_MLOOPCOL_LOOP));
- uiItemR(layout, ptr, "layers_vcol_select_src", 0, IFACE_("Layer Selection"), ICON_NONE);
- uiItemR(layout, ptr, "layers_vcol_select_dst", 0, IFACE_("Layer Mapping"), ICON_NONE);
+ uiItemR(layout, ptr, "layers_vcol_loop_select_src", 0, IFACE_("Layer Selection"), ICON_NONE);
+ uiItemR(layout, ptr, "layers_vcol_loop_select_dst", 0, IFACE_("Layer Mapping"), ICON_NONE);
}
static void face_corner_uv_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -427,6 +445,9 @@ static void panelRegister(ARegionType *region_type)
region_type, "vertex_vgroup", "Vertex Groups", NULL, vertex_vgroup_panel_draw, vertex_panel);
modifier_subpanel_register(
+ region_type, "vert_vcol", "Colors", NULL, vert_vcol_panel_draw, vertex_panel);
+
+ modifier_subpanel_register(
region_type, "edge", "", edge_panel_draw_header, edge_panel_draw, panel_type);
PanelType *face_corner_panel = modifier_subpanel_register(region_type,
@@ -437,7 +458,7 @@ static void panelRegister(ARegionType *region_type)
panel_type);
modifier_subpanel_register(region_type,
"face_corner_vcol",
- "Vertex Colors",
+ "Colors",
NULL,
face_corner_vcol_panel_draw,
face_corner_panel);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 0e1f181eff1..af27ed9bc06 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -109,7 +109,7 @@ DefNode(ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VEC
DefNode(ShaderNode, SH_NODE_SEPHSV, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
DefNode(ShaderNode, SH_NODE_COMBHSV, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
DefNode(ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "" )
-DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Vertex Color", "" )
+DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Color Attribute", "" )
DefNode(ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" )
DefNode(ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" )
DefNode(ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" )
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
index 95e6e42cdff..22b0744333d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
@@ -22,14 +22,7 @@ static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, Pointer
if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- if (U.experimental.use_sculpt_vertex_colors &&
- !RNA_collection_is_empty(&dataptr, "sculpt_vertex_colors")) {
- uiItemPointerR(
- layout, ptr, "layer_name", &dataptr, "sculpt_vertex_colors", "", ICON_GROUP_VCOL);
- }
- else {
- uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL);
- }
+ uiItemPointerR(layout, ptr, "layer_name", &dataptr, "color_attributes", "", ICON_GROUP_VCOL);
}
else {
uiItemL(layout, TIP_("No mesh in active object"), ICON_ERROR);
@@ -49,11 +42,7 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
GPUNodeStack *out)
{
NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
- if (U.experimental.use_sculpt_vertex_colors) {
- GPUNodeLink *vertexColorLink = GPU_attribute(mat, CD_PROP_COLOR, vertexColor->layer_name);
- return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
- }
- GPUNodeLink *vertexColorLink = GPU_attribute(mat, CD_MCOL, vertexColor->layer_name);
+ GPUNodeLink *vertexColorLink = GPU_attribute(mat, CD_PROP_COLOR, vertexColor->layer_name);
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}
@@ -65,7 +54,7 @@ void register_node_type_sh_vertex_color()
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT);
+ sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Color Attribute", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_shader_buts_vertex_color;
node_type_init(&ntype, file_ns::node_shader_init_vertex_color);
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index bc4bbc86367..a8d4ca0f02b 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -197,7 +197,12 @@ static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tre
}
else {
brush = BKE_brush_add(bmain, items[i].name, paint->runtime.ob_mode);
+
BKE_brush_tool_set(brush, paint, slot_index);
+
+ if (paint_mode == PAINT_MODE_SCULPT) {
+ BKE_brush_sculpt_reset(brush);
+ }
}
BKE_paint_brush_set(paint, brush);
}