Refactor: Extract BMesh attribute lookup function

This is the second time I've needed a function to find an attribute by
name on all attribute domains, with a third time coming soon. It seems
time to put this in a BMesh header.

Pull Request: https://projects.blender.org/blender/blender/pulls/144039
This commit is contained in:
Hans Goudey
2025-08-06 13:40:51 +02:00
committed by Hans Goudey
parent b2d0b9535f
commit 3724ebeaa6
4 changed files with 63 additions and 90 deletions

View File

@@ -21,6 +21,8 @@
#include "BLI_task.h"
#include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_attribute_legacy_convert.hh"
#include "BKE_customdata.hh"
#include "BKE_multires.hh"
@@ -1067,6 +1069,40 @@ void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float
}
}
BMDataLayerLookup BM_data_layer_lookup(const BMesh &bm, const blender::StringRef name)
{
using namespace blender;
for (const CustomDataLayer &layer : Span(bm.vdata.layers, bm.vdata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Point,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
for (const CustomDataLayer &layer : Span(bm.edata.layers, bm.edata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Edge,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
for (const CustomDataLayer &layer : Span(bm.pdata.layers, bm.pdata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Face,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
for (const CustomDataLayer &layer : Span(bm.ldata.layers, bm.ldata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Corner,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
return {};
}
/* -------------------------------------------------------------------- */
/** \name Loop interpolation functions: BM_vert_loop_groups_data_layer_***
*

View File

@@ -15,6 +15,11 @@
struct LinkNode;
struct MemArena;
namespace blender::bke {
enum class AttrDomain : int8_t;
enum class AttrType : int16_t;
} // namespace blender::bke
void BM_loop_interp_multires_ex(BMesh *bm,
BMLoop *l_dst,
const BMFace *f_src,
@@ -88,6 +93,24 @@ bool BM_data_layer_free_named(BMesh *bm, CustomData *data, blender::StringRef na
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n);
void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n);
/* See #BM_data_layer_lookup. */
struct BMDataLayerLookup {
const int offset = -1;
blender::bke::AttrDomain domain;
blender::bke::AttrType type;
operator bool() const
{
return offset != -1;
}
};
/**
* Search for a named custom data layer on all attribute domains and return the domain and type.
* This is roughly analogous to #Mesh::attributes().lookup(...), but keep in mind that certain
* attributes stored on #Mesh are not stored as attributes on #BMesh.
*/
BMDataLayerLookup BM_data_layer_lookup(const BMesh &bm, const blender::StringRef name);
float BM_elem_float_data_get(CustomData *cd, void *element, int type);
void BM_elem_float_data_set(CustomData *cd, void *element, int type, float val);

View File

@@ -1054,49 +1054,6 @@ BLI_NOINLINE static void update_face_sets_bmesh(const Object &object,
}
}
struct BMeshAttributeLookup {
const int offset = -1;
bke::AttrDomain domain;
bke::AttrType type;
operator bool() const
{
return offset != -1;
}
};
static BMeshAttributeLookup lookup_bmesh_attribute(const BMesh &bm, const StringRef name)
{
for (const CustomDataLayer &layer : Span(bm.vdata.layers, bm.vdata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Point,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
for (const CustomDataLayer &layer : Span(bm.edata.layers, bm.edata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Edge,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
for (const CustomDataLayer &layer : Span(bm.pdata.layers, bm.pdata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Face,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
for (const CustomDataLayer &layer : Span(bm.ldata.layers, bm.ldata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Corner,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
return {};
}
BLI_NOINLINE static void update_generic_attribute_bmesh(const Object &object,
const OrigMeshData &orig_mesh_data,
const IndexMask &node_mask,
@@ -1106,7 +1063,7 @@ BLI_NOINLINE static void update_generic_attribute_bmesh(const Object &object,
const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
const Span<bke::pbvh::BMeshNode> nodes = pbvh.nodes<bke::pbvh::BMeshNode>();
const BMesh &bm = *object.sculpt->bm;
const BMeshAttributeLookup attr = lookup_bmesh_attribute(bm, name);
const BMDataLayerLookup attr = BM_data_layer_lookup(bm, name);
if (!attr || attr.domain == bke::AttrDomain::Edge) {
return;
}

View File

@@ -171,51 +171,8 @@ static void extract_data_bmesh_loop(const BMesh &bm, const int cd_offset, gpu::V
}
}
struct BMeshAttributeLookup {
const int offset = -1;
bke::AttrDomain domain;
bke::AttrType type;
operator bool() const
{
return offset != -1;
}
};
static BMeshAttributeLookup lookup_bmesh_attribute(const BMesh &bm, const StringRef name)
{
for (const CustomDataLayer &layer : Span(bm.vdata.layers, bm.vdata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Point,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
for (const CustomDataLayer &layer : Span(bm.edata.layers, bm.edata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Edge,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
for (const CustomDataLayer &layer : Span(bm.pdata.layers, bm.pdata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Face,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
for (const CustomDataLayer &layer : Span(bm.ldata.layers, bm.ldata.totlayer)) {
if (layer.name == name) {
return {layer.offset,
bke::AttrDomain::Corner,
*bke::custom_data_type_to_attr_type(eCustomDataType(layer.type))};
}
}
return {};
}
static void extract_attribute_data(const MeshRenderData &mr,
const BMeshAttributeLookup &attr,
const BMDataLayerLookup &attr,
gpu::VertBuf &vbo)
{
bke::attribute_math::convert_to_static_type(attr.type, [&](auto dummy) {
@@ -272,7 +229,7 @@ gpu::VertBufPtr extract_attribute(const MeshRenderData &mr, const StringRef name
{
gpu::VertBuf *vbo = GPU_vertbuf_calloc();
if (mr.extract_type == MeshExtractType::BMesh) {
const BMeshAttributeLookup attr = lookup_bmesh_attribute(*mr.bm, name);
const BMDataLayerLookup attr = BM_data_layer_lookup(*mr.bm, name);
if (!attr) {
return {};
}
@@ -313,7 +270,7 @@ gpu::VertBufPtr extract_attribute_subdiv(const MeshRenderData &mr,
gpu::VertBufPtr coarse_vbo;
bke::AttrType type;
if (mr.extract_type == MeshExtractType::BMesh) {
const BMeshAttributeLookup attr = lookup_bmesh_attribute(*mr.bm, name);
const BMDataLayerLookup attr = BM_data_layer_lookup(*mr.bm, name);
if (!attr) {
return {};
}