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/blenkernel')
-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
14 files changed, 873 insertions, 49 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 */