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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Eagar <joeedh@gmail.com>2022-04-05 21:42:55 +0300
committerJoseph Eagar <joeedh@gmail.com>2022-04-05 21:42:55 +0300
commiteae36be372a6b16ee3e76eff0485a47da4f3c230 (patch)
treed1ca2dc30951e31f1b91eed6a4edfdfb0824bf1f /source/blender/blenkernel/intern
parenta3e122b9aec59fc303c2375a78183cfb8642c14f (diff)
Refactor: Unify vertex and sculpt colors into new
color attribute system. This commit removes sculpt colors from experimental status and unifies it with vertex colors. It introduces the concept of "color attributes", which are any attributes that represents colors. Color attributes can be represented with byte or floating-point numbers and can be stored in either vertices or face corners. Color attributes share a common namespace (so you can no longer have a floating-point sculpt color attribute and a byte vertex color attribute with the same name). Note: this commit does not include vertex paint mode, which is a separate patch, see: https://developer.blender.org/D14179 Differential Revision: https://developer.blender.org/D12587 Ref D12587
Diffstat (limited to 'source/blender/blenkernel/intern')
-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
9 files changed, 726 insertions, 28 deletions
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 */