Merge branch 'blender-v4.0-release'

This commit is contained in:
Hans Goudey 2023-10-31 18:12:18 +01:00
commit acbab3550f

@ -36,7 +36,8 @@
#include "DNA_meshdata_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_attribute_math.hh"
#include "BKE_ccg.h"
#include "BKE_customdata.h"
#include "BKE_mesh.hh"
@ -75,20 +76,147 @@ using blender::ushort3;
using blender::ushort4;
using blender::Vector;
static bool valid_pbvh_attr(int type)
/**
* Component length of 3 is used for scalars because implicit conversion is done by OpenGL from a
* scalar `s` will produce `vec4(s, 0, 0, 1)`. However, following the Blender convention, it should
* be `vec4(s, s, s, 1)`.
*/
constexpr int COMPONENT_LEN_SCALAR = 3;
namespace blender::draw {
/** Similar to #AttributeTypeConverter. */
template<typename T> struct AttributeConverter {
using VBOT = void;
};
template<> struct AttributeConverter<bool> {
using VBOT = VecBase<int, COMPONENT_LEN_SCALAR>;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_I32;
static constexpr int gpu_component_len = COMPONENT_LEN_SCALAR;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT;
static VBOT convert(const bool &value)
{
switch (type) {
case CD_PBVH_CO_TYPE:
case CD_PBVH_NO_TYPE:
case CD_PBVH_FSET_TYPE:
case CD_PBVH_MASK_TYPE:
case CD_PROP_COLOR:
case CD_PROP_BYTE_COLOR:
case CD_PROP_FLOAT2:
return VBOT(value);
}
};
template<> struct AttributeConverter<int8_t> {
using VBOT = VecBase<int, COMPONENT_LEN_SCALAR>;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_I32;
static constexpr int gpu_component_len = COMPONENT_LEN_SCALAR;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT;
static VBOT convert(const int8_t &value)
{
return VecBase<int, COMPONENT_LEN_SCALAR>(value);
}
};
template<> struct AttributeConverter<int> {
using VBOT = VecBase<int, COMPONENT_LEN_SCALAR>;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_I32;
static constexpr int gpu_component_len = COMPONENT_LEN_SCALAR;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT;
static VBOT convert(const int &value)
{
return int3(value);
}
};
template<> struct AttributeConverter<int2> {
using VBOT = int2;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_I32;
static constexpr int gpu_component_len = 2;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT;
static VBOT convert(const int2 &value)
{
return int2(value.x, value.y);
}
};
template<> struct AttributeConverter<float> {
using VBOT = VecBase<float, COMPONENT_LEN_SCALAR>;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32;
static constexpr int gpu_component_len = COMPONENT_LEN_SCALAR;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT;
static VBOT convert(const float &value)
{
return VBOT(value);
}
};
template<> struct AttributeConverter<float2> {
using VBOT = float2;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32;
static constexpr int gpu_component_len = 2;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT;
static VBOT convert(const float2 &value)
{
return value;
}
};
template<> struct AttributeConverter<float3> {
using VBOT = float3;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32;
static constexpr int gpu_component_len = 3;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT;
static VBOT convert(const float3 &value)
{
return value;
}
};
template<> struct AttributeConverter<ColorGeometry4b> {
/* 16 bits are required to store the color in linear space without precision loss. */
using VBOT = ushort4;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_U16;
static constexpr int gpu_component_len = 4;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT_UNIT;
static VBOT convert(const ColorGeometry4b &value)
{
return {unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.r]),
unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.g]),
unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.b]),
ushort(value.a * 257)};
}
};
template<> struct AttributeConverter<ColorGeometry4f> {
using VBOT = ColorGeometry4f;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32;
static constexpr int gpu_component_len = 4;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT;
static VBOT convert(const ColorGeometry4f &value)
{
return value;
}
};
template<> struct AttributeConverter<blender::math::Quaternion> {
using VBOT = float4;
static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32;
static constexpr int gpu_component_len = 4;
static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT;
static VBOT convert(const blender::math::Quaternion &value)
{
return float4(value.w, value.x, value.y, value.z);
}
};
} // namespace blender::draw
static bool pbvh_attr_supported(int type, const eAttrDomain domain)
{
using namespace blender;
if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER)) {
/* PBVH drawing does not support edge domain attributes. */
return false;
}
if (ELEM(type, CD_PBVH_CO_TYPE, CD_PBVH_NO_TYPE, CD_PBVH_FSET_TYPE, CD_PBVH_MASK_TYPE)) {
return true;
}
return false;
bool type_supported = false;
bke::attribute_math::convert_to_static_type(eCustomDataType(type), [&](auto dummy) {
using T = decltype(dummy);
using Converter = draw::AttributeConverter<T>;
using VBOT = typename Converter::VBOT;
if constexpr (!std::is_void_v<VBOT>) {
type_supported = true;
}
});
return type_supported;
}
struct PBVHVbo {
@ -118,46 +246,18 @@ struct PBVHVbo {
}
};
template<typename AttributeT, typename VBOT> VBOT convert_value(const AttributeT &value)
{
if constexpr (std::is_same_v<AttributeT, VBOT>) {
return value;
}
}
template<> inline uchar convert_value(const float &value)
{
return uchar(value * 255.0f);
}
template<> inline ushort4 convert_value(const MPropCol &value)
{
return {unit_float_to_ushort_clamp(value.color[0]),
unit_float_to_ushort_clamp(value.color[1]),
unit_float_to_ushort_clamp(value.color[2]),
unit_float_to_ushort_clamp(value.color[3])};
}
template<> inline ushort4 convert_value(const MLoopCol &value)
{
return {unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.r]),
unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.g]),
unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.b]),
ushort(value.a * 257)};
}
template<> inline short4 convert_value(const float3 &value)
inline short4 normal_float_to_short(const float3 &value)
{
short3 result;
normal_float_to_short_v3(result, value);
return short4(result.x, result.y, result.z, 0);
}
template<typename AttributeT, typename VBOT>
void extract_data_vert_faces(const PBVH_GPU_Args &args,
const Span<AttributeT> attribute,
GPUVertBuf &vbo)
template<typename T>
void extract_data_vert_faces(const PBVH_GPU_Args &args, const Span<T> attribute, GPUVertBuf &vbo)
{
using Converter = blender::draw::AttributeConverter<T>;
using VBOT = typename Converter::VBOT;
const Span<int> corner_verts = args.corner_verts;
const Span<MLoopTri> looptris = args.mlooptri;
const Span<int> looptri_faces = args.looptri_faces;
@ -170,17 +270,38 @@ void extract_data_vert_faces(const PBVH_GPU_Args &args,
}
for (int i : IndexRange(3)) {
const int vert = corner_verts[looptris[looptri_i].tri[i]];
*data = convert_value<AttributeT, VBOT>(attribute[vert]);
*data = Converter::convert(attribute[vert]);
data++;
}
}
}
template<typename AttributeT, typename VBOT>
void extract_data_corner_faces(const PBVH_GPU_Args &args,
const Span<AttributeT> attribute,
GPUVertBuf &vbo)
template<typename T>
void extract_data_face_faces(const PBVH_GPU_Args &args, const Span<T> attribute, GPUVertBuf &vbo)
{
using Converter = blender::draw::AttributeConverter<T>;
using VBOT = typename Converter::VBOT;
const Span<int> looptri_faces = args.looptri_faces;
const bool *hide_poly = args.hide_poly;
VBOT *data = static_cast<VBOT *>(GPU_vertbuf_get_data(&vbo));
for (const int looptri_i : args.prim_indices) {
const int face = looptri_faces[looptri_i];
if (hide_poly && hide_poly[face]) {
continue;
}
std::fill_n(data, 3, Converter::convert(attribute[face]));
data += 3;
}
}
template<typename T>
void extract_data_corner_faces(const PBVH_GPU_Args &args, const Span<T> attribute, GPUVertBuf &vbo)
{
using Converter = blender::draw::AttributeConverter<T>;
using VBOT = typename Converter::VBOT;
const Span<MLoopTri> looptris = args.mlooptri;
const Span<int> looptri_faces = args.looptri_faces;
const bool *hide_poly = args.hide_poly;
@ -192,7 +313,7 @@ void extract_data_corner_faces(const PBVH_GPU_Args &args,
}
for (int i : IndexRange(3)) {
const int corner = looptris[looptri_i].tri[i];
*data = convert_value<AttributeT, VBOT>(attribute[corner]);
*data = Converter::convert(attribute[corner]);
data++;
}
}
@ -213,9 +334,11 @@ template<typename T> const T &bmesh_cd_face_get(const BMFace &face, const int of
return *static_cast<const T *>(POINTER_OFFSET(face.head.data, offset));
}
template<typename AttributeT, typename VBOT>
template<typename T>
void extract_data_vert_bmesh(const PBVH_GPU_Args &args, const int cd_offset, GPUVertBuf &vbo)
{
using Converter = blender::draw::AttributeConverter<T>;
using VBOT = typename Converter::VBOT;
VBOT *data = static_cast<VBOT *>(GPU_vertbuf_get_data(&vbo));
for (const BMFace *f : *args.bm_faces) {
@ -223,18 +346,36 @@ void extract_data_vert_bmesh(const PBVH_GPU_Args &args, const int cd_offset, GPU
continue;
}
const BMLoop *l = f->l_first;
*data = convert_value<AttributeT, VBOT>(bmesh_cd_vert_get<AttributeT>(*l->prev->v, cd_offset));
*data = Converter::convert(bmesh_cd_vert_get<T>(*l->prev->v, cd_offset));
data++;
*data = convert_value<AttributeT, VBOT>(bmesh_cd_vert_get<AttributeT>(*l->v, cd_offset));
*data = Converter::convert(bmesh_cd_vert_get<T>(*l->v, cd_offset));
data++;
*data = convert_value<AttributeT, VBOT>(bmesh_cd_vert_get<AttributeT>(*l->next->v, cd_offset));
*data = Converter::convert(bmesh_cd_vert_get<T>(*l->next->v, cd_offset));
data++;
}
}
template<typename AttributeT, typename VBOT>
template<typename T>
void extract_data_face_bmesh(const PBVH_GPU_Args &args, const int cd_offset, GPUVertBuf &vbo)
{
using Converter = blender::draw::AttributeConverter<T>;
using VBOT = typename Converter::VBOT;
VBOT *data = static_cast<VBOT *>(GPU_vertbuf_get_data(&vbo));
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
std::fill_n(data, 3, Converter::convert(bmesh_cd_face_get<T>(*f, cd_offset)));
data += 3;
}
}
template<typename T>
void extract_data_corner_bmesh(const PBVH_GPU_Args &args, const int cd_offset, GPUVertBuf &vbo)
{
using Converter = blender::draw::AttributeConverter<T>;
using VBOT = typename Converter::VBOT;
VBOT *data = static_cast<VBOT *>(GPU_vertbuf_get_data(&vbo));
for (const BMFace *f : *args.bm_faces) {
@ -242,11 +383,11 @@ void extract_data_corner_bmesh(const PBVH_GPU_Args &args, const int cd_offset, G
continue;
}
const BMLoop *l = f->l_first;
*data = convert_value<AttributeT, VBOT>(bmesh_cd_loop_get<AttributeT>(*l->prev, cd_offset));
*data = Converter::convert(bmesh_cd_loop_get<T>(*l->prev, cd_offset));
data++;
*data = convert_value<AttributeT, VBOT>(bmesh_cd_loop_get<AttributeT>(*l, cd_offset));
*data = Converter::convert(bmesh_cd_loop_get<T>(*l, cd_offset));
data++;
*data = convert_value<AttributeT, VBOT>(bmesh_cd_loop_get<AttributeT>(*l->next, cd_offset));
*data = Converter::convert(bmesh_cd_loop_get<T>(*l->next, cd_offset));
data++;
}
}
@ -396,7 +537,7 @@ struct PBVHBatches {
for (int i : IndexRange(attrs_num)) {
PBVHAttrReq *attr = attrs + i;
if (!valid_pbvh_attr(attr->type)) {
if (!pbvh_attr_supported(attr->type, attr->domain)) {
continue;
}
@ -476,7 +617,7 @@ struct PBVHBatches {
}
if (sharp_faces && sharp_faces[face_i]) {
if (face_i != last_face) {
face_no = convert_value<float3, short4>(args.face_normals[face_i]);
face_no = normal_float_to_short(args.face_normals[face_i]);
last_face = face_i;
}
std::fill_n(data, 3, face_no);
@ -485,7 +626,7 @@ struct PBVHBatches {
else {
for (const int i : IndexRange(3)) {
const int vert = args.corner_verts[args.mlooptri[looptri_i].tri[i]];
*data = convert_value<float3, short4>(args.vert_normals[vert]);
*data = normal_float_to_short(args.vert_normals[vert]);
data++;
}
}
@ -498,6 +639,7 @@ struct PBVHBatches {
FunctionRef<void(FunctionRef<void(int x, int y, int grid_index, CCGElem *elems[4], int i)>
func)> foreach_grids)
{
using namespace blender;
uint vert_per_grid = square_i(args.ccg_key.grid_size - 1) * 4;
uint vert_count = args.grid_indices.size() * vert_per_grid;
@ -512,29 +654,14 @@ struct PBVHBatches {
GPUVertBufRaw access;
GPU_vertbuf_attr_get_raw_data(vbo.vert_buf, 0, &access);
switch (vbo.type) {
case CD_PROP_COLOR:
case CD_PROP_BYTE_COLOR: {
/* TODO: Implement color support for multires similar to the mesh cache
* extractor code. For now just upload white.
*/
const ushort4 white(USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX);
foreach_grids(
[&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) {
*static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = white;
});
break;
}
case CD_PBVH_CO_TYPE:
if (vbo.type == CD_PBVH_CO_TYPE) {
foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) {
float *co = CCG_elem_co(&args.ccg_key, elems[i]);
*static_cast<float3 *>(GPU_vertbuf_raw_step(&access)) = co;
});
break;
case CD_PBVH_NO_TYPE:
}
else if (vbo.type == CD_PBVH_NO_TYPE) {
foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) {
float3 no(0.0f, 0.0f, 0.0f);
@ -557,9 +684,8 @@ struct PBVHBatches {
*static_cast<short3 *>(GPU_vertbuf_raw_step(&access)) = sno;
});
break;
case CD_PBVH_MASK_TYPE:
}
else if (vbo.type == CD_PBVH_MASK_TYPE) {
if (args.ccg_key.has_mask) {
foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) {
float *mask = CCG_elem_mask(&args.ccg_key, elems[i]);
@ -573,11 +699,8 @@ struct PBVHBatches {
*static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = 0;
});
}
break;
case CD_PBVH_FSET_TYPE: {
BLI_assert(vbo.domain == ATTR_DOMAIN_FACE);
}
else if (vbo.type == CD_PBVH_FSET_TYPE) {
const int *face_sets = args.face_sets;
if (!face_sets) {
@ -608,8 +731,16 @@ struct PBVHBatches {
*static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = face_set_color;
});
}
break;
}
else {
bke::attribute_math::convert_to_static_type(eCustomDataType(vbo.type), [&](auto dummy) {
using T = decltype(dummy);
using Converter = draw::AttributeConverter<T>;
using VBOT = typename Converter::VBOT;
std::fill_n(static_cast<VBOT *>(GPU_vertbuf_get_data(vbo.vert_buf)),
GPU_vertbuf_get_vertex_len(vbo.vert_buf),
VBOT());
});
}
}
@ -679,6 +810,7 @@ struct PBVHBatches {
void fill_vbo_faces(PBVHVbo &vbo, const PBVH_GPU_Args &args)
{
using namespace blender;
const int totvert = this->count_faces(args) * 3;
int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf);
@ -691,28 +823,38 @@ struct PBVHBatches {
GPUVertBuf &vert_buf = *vbo.vert_buf;
switch (vbo.type) {
case CD_PBVH_CO_TYPE:
extract_data_vert_faces<float3, float3>(args, args.vert_positions, vert_buf);
break;
case CD_PBVH_NO_TYPE:
if (vbo.type == CD_PBVH_CO_TYPE) {
extract_data_vert_faces<float3>(args, args.vert_positions, vert_buf);
}
else if (vbo.type == CD_PBVH_NO_TYPE) {
fill_vbo_normal_faces(args, vert_buf);
break;
case CD_PBVH_MASK_TYPE: {
}
else if (vbo.type == CD_PBVH_MASK_TYPE) {
if (const float *mask = static_cast<const float *>(
CustomData_get_layer(args.vert_data, CD_PAINT_MASK)))
{
extract_data_vert_faces<float, float>(args, {mask, args.me->totvert}, vert_buf);
const Span<int> corner_verts = args.corner_verts;
const Span<MLoopTri> looptris = args.mlooptri;
const Span<int> looptri_faces = args.looptri_faces;
const bool *hide_poly = args.hide_poly;
float *data = static_cast<float *>(GPU_vertbuf_get_data(&vert_buf));
for (const int looptri_i : args.prim_indices) {
if (hide_poly && hide_poly[looptri_faces[looptri_i]]) {
continue;
}
for (int i : IndexRange(3)) {
const int vert = corner_verts[looptris[looptri_i].tri[i]];
*data = mask[vert];
data++;
}
}
}
else {
MutableSpan(static_cast<float *>(GPU_vertbuf_get_data(vbo.vert_buf)), totvert)
.fill(0.0f);
MutableSpan(static_cast<float *>(GPU_vertbuf_get_data(vbo.vert_buf)), totvert).fill(0);
}
break;
}
case CD_PBVH_FSET_TYPE: {
BLI_assert(vbo.domain == ATTR_DOMAIN_FACE);
else if (vbo.type == CD_PBVH_FSET_TYPE) {
const int *face_sets = static_cast<const int *>(
CustomData_get_layer_named(args.face_data, CD_PROP_INT32, ".sculpt_face_set"));
uchar4 *data = static_cast<uchar4 *>(GPU_vertbuf_get_data(vbo.vert_buf));
@ -745,41 +887,27 @@ struct PBVHBatches {
else {
MutableSpan(data, totvert).fill(uchar4(255));
}
}
else {
const bke::AttributeAccessor attributes = args.me->attributes();
const eCustomDataType data_type = eCustomDataType(vbo.type);
const GVArraySpan attribute = *attributes.lookup_or_default(vbo.name, vbo.domain, data_type);
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
switch (vbo.domain) {
case ATTR_DOMAIN_POINT:
extract_data_vert_faces<T>(args, attribute.typed<T>(), vert_buf);
break;
}
case CD_PROP_COLOR: {
const MPropCol *data = static_cast<const MPropCol *>(CustomData_get_layer_named(
get_cdata(vbo.domain, args), CD_PROP_COLOR, vbo.name.c_str()));
if (vbo.domain == ATTR_DOMAIN_POINT) {
extract_data_vert_faces<MPropCol, ushort4>(args, {data, args.me->totvert}, vert_buf);
}
else if (vbo.domain == ATTR_DOMAIN_CORNER) {
extract_data_corner_faces<MPropCol, ushort4>(args, {data, args.me->totloop}, vert_buf);
}
case ATTR_DOMAIN_FACE:
extract_data_face_faces<T>(args, attribute.typed<T>(), vert_buf);
break;
}
case CD_PROP_BYTE_COLOR: {
const MLoopCol *data = static_cast<const MLoopCol *>(CustomData_get_layer_named(
get_cdata(vbo.domain, args), CD_PROP_BYTE_COLOR, vbo.name.c_str()));
if (vbo.domain == ATTR_DOMAIN_POINT) {
extract_data_vert_faces<MLoopCol, ushort4>(args, {data, args.me->totvert}, vert_buf);
}
else if (vbo.domain == ATTR_DOMAIN_CORNER) {
extract_data_corner_faces<MLoopCol, ushort4>(args, {data, args.me->totloop}, vert_buf);
}
break;
}
case CD_PROP_FLOAT2: {
const float2 *data = static_cast<const float2 *>(CustomData_get_layer_named(
get_cdata(vbo.domain, args), CD_PROP_FLOAT2, vbo.name.c_str()));
if (vbo.domain == ATTR_DOMAIN_POINT) {
extract_data_vert_faces<float2, float2>(args, {data, args.me->totvert}, vert_buf);
}
else if (vbo.domain == ATTR_DOMAIN_CORNER) {
extract_data_corner_faces<float2, float2>(args, {data, args.me->totloop}, vert_buf);
}
case ATTR_DOMAIN_CORNER:
extract_data_corner_faces<T>(args, attribute.typed<T>(), vert_buf);
break;
default:
BLI_assert_unreachable();
}
});
}
}
@ -803,6 +931,7 @@ struct PBVHBatches {
void fill_vbo_bmesh(PBVHVbo &vbo, const PBVH_GPU_Args &args)
{
using namespace blender;
faces_count = tris_count = count_faces(args);
int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf);
@ -826,42 +955,7 @@ struct PBVHBatches {
}
#endif
const eCustomDataType type = eCustomDataType(vbo.type);
if (vbo.domain == ATTR_DOMAIN_POINT) {
const int cd_offset = CustomData_get_offset_named(&args.bm->vdata, type, vbo.name.c_str());
switch (type) {
case CD_PROP_COLOR:
extract_data_vert_bmesh<MPropCol, ushort4>(args, cd_offset, *vbo.vert_buf);
return;
case CD_PROP_BYTE_COLOR:
extract_data_vert_bmesh<MLoopCol, ushort4>(args, cd_offset, *vbo.vert_buf);
return;
case CD_PROP_FLOAT2:
extract_data_vert_bmesh<float2, float2>(args, cd_offset, *vbo.vert_buf);
return;
default:
break;
}
}
else if (vbo.domain == ATTR_DOMAIN_CORNER) {
const int cd_offset = CustomData_get_offset_named(&args.bm->ldata, type, vbo.name.c_str());
switch (type) {
case CD_PROP_COLOR:
extract_data_corner_bmesh<MPropCol, ushort4>(args, cd_offset, *vbo.vert_buf);
return;
case CD_PROP_BYTE_COLOR:
extract_data_corner_bmesh<MLoopCol, ushort4>(args, cd_offset, *vbo.vert_buf);
return;
case CD_PROP_FLOAT2:
extract_data_corner_bmesh<float2, float2>(args, cd_offset, *vbo.vert_buf);
return;
default:
break;
}
}
switch (vbo.type) {
case CD_PBVH_CO_TYPE: {
if (vbo.type == CD_PBVH_CO_TYPE) {
float3 *data = static_cast<float3 *>(GPU_vertbuf_get_data(vbo.vert_buf));
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
@ -875,9 +969,8 @@ struct PBVHBatches {
*data = l->next->v->co;
data++;
}
break;
}
case CD_PBVH_NO_TYPE: {
else if (vbo.type == CD_PBVH_NO_TYPE) {
short4 *data = static_cast<short4 *>(GPU_vertbuf_get_data(vbo.vert_buf));
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
@ -885,32 +978,44 @@ struct PBVHBatches {
}
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
const BMLoop *l = f->l_first;
*data = convert_value<float3, short4>(l->prev->v->no);
*data = normal_float_to_short(l->prev->v->no);
data++;
*data = convert_value<float3, short4>(l->v->no);
*data = normal_float_to_short(l->v->no);
data++;
*data = convert_value<float3, short4>(l->next->v->no);
*data = normal_float_to_short(l->next->v->no);
data++;
}
else {
std::fill_n(data, 3, convert_value<float3, short4>(f->no));
std::fill_n(data, 3, normal_float_to_short(f->no));
data += 3;
}
}
break;
}
case CD_PBVH_MASK_TYPE: {
if (args.cd_mask_layer != -1) {
extract_data_vert_bmesh<float, float>(args, args.cd_mask_layer, *vbo.vert_buf);
else if (vbo.type == CD_PBVH_MASK_TYPE) {
const int cd_offset = args.cd_mask_layer;
if (cd_offset != -1) {
float *data = static_cast<float *>(GPU_vertbuf_get_data(vbo.vert_buf));
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
const BMLoop *l = f->l_first;
*data = bmesh_cd_vert_get<float>(*l->prev->v, cd_offset);
data++;
*data = bmesh_cd_vert_get<float>(*l->v, cd_offset);
data++;
*data = bmesh_cd_vert_get<float>(*l->next->v, cd_offset);
data++;
}
}
else {
MutableSpan(static_cast<float *>(GPU_vertbuf_get_data(vbo.vert_buf)),
GPU_vertbuf_get_vertex_len(vbo.vert_buf))
.fill(0.0f);
}
break;
}
case CD_PBVH_FSET_TYPE: {
else if (vbo.type == CD_PBVH_FSET_TYPE) {
BLI_assert(vbo.domain == ATTR_DOMAIN_FACE);
const int cd_offset = CustomData_get_offset_named(
@ -940,8 +1045,28 @@ struct PBVHBatches {
else {
MutableSpan(data, GPU_vertbuf_get_vertex_len(vbo.vert_buf)).fill(uchar4(255));
}
break;
}
else {
const eCustomDataType type = eCustomDataType(vbo.type);
const CustomData &custom_data = *get_cdata(vbo.domain, args);
const int cd_offset = CustomData_get_offset_named(&custom_data, type, vbo.name.c_str());
bke::attribute_math::convert_to_static_type(eCustomDataType(vbo.type), [&](auto dummy) {
using T = decltype(dummy);
switch (vbo.domain) {
case ATTR_DOMAIN_POINT:
extract_data_vert_bmesh<T>(args, cd_offset, *vbo.vert_buf);
break;
case ATTR_DOMAIN_FACE:
extract_data_face_bmesh<T>(args, cd_offset, *vbo.vert_buf);
break;
case ATTR_DOMAIN_CORNER:
extract_data_corner_bmesh<T>(args, cd_offset, *vbo.vert_buf);
break;
default:
BLI_assert_unreachable();
}
});
}
}
@ -965,6 +1090,7 @@ struct PBVHBatches {
const StringRefNull name,
const PBVH_GPU_Args &args)
{
using namespace blender;
PBVHVbo vbo(domain, type, name);
GPUVertFormat format;
@ -973,42 +1099,29 @@ struct PBVHBatches {
GPU_vertformat_clear(&format);
switch (type) {
case CD_PBVH_CO_TYPE:
if (type == CD_PBVH_CO_TYPE) {
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
break;
case CD_PROP_FLOAT3:
GPU_vertformat_attr_add(&format, "a", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
need_aliases = true;
break;
case CD_PBVH_NO_TYPE:
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
break;
case CD_PROP_FLOAT2:
GPU_vertformat_attr_add(&format, "a", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
need_aliases = true;
break;
case CD_PBVH_FSET_TYPE:
GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
break;
case CD_PBVH_MASK_TYPE:
GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
break;
case CD_PROP_FLOAT:
GPU_vertformat_attr_add(&format, "f", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
need_aliases = true;
break;
case CD_PROP_COLOR:
case CD_PROP_BYTE_COLOR: {
GPU_vertformat_attr_add(&format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
need_aliases = true;
break;
}
default:
printf("%s: Unsupported attribute type %u\n", __func__, type);
BLI_assert_unreachable();
return;
else if (type == CD_PBVH_NO_TYPE) {
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
else if (type == CD_PBVH_FSET_TYPE) {
GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
else if (type == CD_PBVH_MASK_TYPE) {
GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
else {
bke::attribute_math::convert_to_static_type(eCustomDataType(type), [&](auto dummy) {
using T = decltype(dummy);
using Converter = draw::AttributeConverter<T>;
GPU_vertformat_attr_add(&format,
"data",
Converter::gpu_component_type,
Converter::gpu_component_len,
Converter::gpu_fetch_mode);
});
need_aliases = true;
}
if (need_aliases) {
@ -1403,7 +1516,7 @@ struct PBVHBatches {
for (int i : IndexRange(attrs_num)) {
PBVHAttrReq *attr = attrs + i;
if (!valid_pbvh_attr(attr->type)) {
if (!pbvh_attr_supported(attr->type, attr->domain)) {
continue;
}