Refactor: Sculpt: Move some drawing code out of classes
Most functions in `draw_pbvh.cc` are inside of the `PBVHBatch` or `PBVHBatches` classes, besides the more recently added attribute copying code. This means they have access to "all the information" and it's hard to get a sense for the proper order of calculation and what each function is responsible for. This commit is an attempt to clarify things a bit by changing to regular static functions.
This commit is contained in:
@@ -345,478 +345,484 @@ struct PBVHBatches {
|
||||
int coarse_level = 0; /* Coarse multires depth. */
|
||||
int tris_count_coarse = 0, lines_count_coarse = 0;
|
||||
|
||||
int count_faces(const PBVH_GPU_Args &args)
|
||||
{
|
||||
int count = 0;
|
||||
PBVHBatches(const PBVH_GPU_Args &args);
|
||||
~PBVHBatches();
|
||||
|
||||
switch (args.pbvh_type) {
|
||||
case PBVH_FACES: {
|
||||
if (!args.hide_poly.is_empty()) {
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
if (!args.hide_poly[args.tri_faces[tri_i]]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
count = args.prim_indices.size();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PBVH_GRIDS: {
|
||||
count = bke::pbvh::count_grid_quads(args.subdiv_ccg->grid_hidden,
|
||||
args.grid_indices,
|
||||
args.ccg_key.grid_size,
|
||||
args.ccg_key.grid_size);
|
||||
void update(const PBVH_GPU_Args &args);
|
||||
void update_pre(const PBVH_GPU_Args &args);
|
||||
|
||||
break;
|
||||
}
|
||||
case PBVH_BMESH: {
|
||||
for (const BMFace *f : *args.bm_faces) {
|
||||
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
int create_vbo(const AttributeRequest &request, const PBVH_GPU_Args &args);
|
||||
int ensure_vbo(const AttributeRequest &request, const PBVH_GPU_Args &args);
|
||||
|
||||
void create_index(const PBVH_GPU_Args &args);
|
||||
};
|
||||
|
||||
static PBVHBatch create_batch(PBVHBatches &batches,
|
||||
const Span<AttributeRequest> requests,
|
||||
const PBVH_GPU_Args &args,
|
||||
bool do_coarse_grids);
|
||||
|
||||
static int count_faces(const PBVH_GPU_Args &args)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
switch (args.pbvh_type) {
|
||||
case PBVH_FACES: {
|
||||
if (!args.hide_poly.is_empty()) {
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
if (!args.hide_poly[args.tri_faces[tri_i]]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
PBVHBatches(const PBVH_GPU_Args &args)
|
||||
{
|
||||
faces_count = count_faces(args);
|
||||
}
|
||||
|
||||
~PBVHBatches()
|
||||
{
|
||||
for (PBVHBatch &batch : batches.values()) {
|
||||
GPU_BATCH_DISCARD_SAFE(batch.tris);
|
||||
GPU_BATCH_DISCARD_SAFE(batch.lines);
|
||||
}
|
||||
|
||||
for (PBVHVbo &vbo : vbos) {
|
||||
GPU_vertbuf_discard(vbo.vert_buf);
|
||||
}
|
||||
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index_coarse);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index_coarse);
|
||||
}
|
||||
|
||||
std::string build_key(const Span<AttributeRequest> requests, bool do_coarse_grids)
|
||||
{
|
||||
PBVHBatch batch;
|
||||
Vector<PBVHVbo> vbos;
|
||||
|
||||
for (const int i : requests.index_range()) {
|
||||
const AttributeRequest &request = requests[i];
|
||||
if (!pbvh_attr_supported(request)) {
|
||||
continue;
|
||||
}
|
||||
vbos.append_as(request);
|
||||
batch.vbos.append(i);
|
||||
}
|
||||
|
||||
batch.is_coarse = do_coarse_grids;
|
||||
return batch.build_key(vbos);
|
||||
}
|
||||
|
||||
int ensure_vbo(const AttributeRequest &request, const PBVH_GPU_Args &args)
|
||||
{
|
||||
for (const int i : vbos.index_range()) {
|
||||
if (this->vbos[i].request == request) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return this->create_vbo(request, args);
|
||||
}
|
||||
|
||||
PBVHBatch &ensure_batch(const Span<AttributeRequest> requests,
|
||||
const PBVH_GPU_Args &args,
|
||||
bool do_coarse_grids)
|
||||
{
|
||||
std::string key = this->build_key(requests, do_coarse_grids);
|
||||
if (PBVHBatch *batch = batches.lookup_ptr(key)) {
|
||||
return *batch;
|
||||
}
|
||||
return batches.lookup_or_add(std::move(key), create_batch(requests, args, do_coarse_grids));
|
||||
}
|
||||
|
||||
void fill_vbo_normal_faces(const PBVH_GPU_Args &args, gpu::VertBuf &vert_buf)
|
||||
{
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
|
||||
|
||||
short4 *data = static_cast<short4 *>(GPU_vertbuf_get_data(vert_buf));
|
||||
|
||||
short4 face_no;
|
||||
int last_face = -1;
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
const int face_i = args.tri_faces[tri_i];
|
||||
if (!args.hide_poly.is_empty() && args.hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
if (!sharp_faces.is_empty() && sharp_faces[face_i]) {
|
||||
if (face_i != last_face) {
|
||||
face_no = normal_float_to_short(args.face_normals[face_i]);
|
||||
last_face = face_i;
|
||||
}
|
||||
std::fill_n(data, 3, face_no);
|
||||
data += 3;
|
||||
}
|
||||
else {
|
||||
for (const int i : IndexRange(3)) {
|
||||
const int vert = args.corner_verts[args.corner_tris[tri_i][i]];
|
||||
*data = normal_float_to_short(args.vert_normals[vert]);
|
||||
data++;
|
||||
count = args.prim_indices.size();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PBVH_GRIDS: {
|
||||
count = bke::pbvh::count_grid_quads(args.subdiv_ccg->grid_hidden,
|
||||
args.grid_indices,
|
||||
args.ccg_key.grid_size,
|
||||
args.ccg_key.grid_size);
|
||||
|
||||
break;
|
||||
}
|
||||
case PBVH_BMESH: {
|
||||
for (const BMFace *f : *args.bm_faces) {
|
||||
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fill_vbo_grids_intern(
|
||||
PBVHVbo &vbo,
|
||||
const PBVH_GPU_Args &args,
|
||||
FunctionRef<void(FunctionRef<void(int x, int y, int grid_index, CCGElem *elems[4], int i)>
|
||||
func)> foreach_grids)
|
||||
{
|
||||
uint vert_per_grid = square_i(args.ccg_key.grid_size - 1) * 4;
|
||||
uint vert_count = args.grid_indices.size() * vert_per_grid;
|
||||
return count;
|
||||
}
|
||||
|
||||
int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf);
|
||||
void *existing_data = GPU_vertbuf_get_data(*vbo.vert_buf);
|
||||
PBVHBatches::PBVHBatches(const PBVH_GPU_Args &args)
|
||||
{
|
||||
faces_count = count_faces(args);
|
||||
}
|
||||
|
||||
if (existing_data == nullptr || existing_num != vert_count) {
|
||||
/* Allocate buffer if not allocated yet or size changed. */
|
||||
GPU_vertbuf_data_alloc(*vbo.vert_buf, vert_count);
|
||||
PBVHBatches::~PBVHBatches()
|
||||
{
|
||||
for (PBVHBatch &batch : batches.values()) {
|
||||
GPU_BATCH_DISCARD_SAFE(batch.tris);
|
||||
GPU_BATCH_DISCARD_SAFE(batch.lines);
|
||||
}
|
||||
|
||||
for (PBVHVbo &vbo : vbos) {
|
||||
GPU_vertbuf_discard(vbo.vert_buf);
|
||||
}
|
||||
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index_coarse);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index_coarse);
|
||||
}
|
||||
|
||||
static std::string build_key(const Span<AttributeRequest> requests, bool do_coarse_grids)
|
||||
{
|
||||
PBVHBatch batch;
|
||||
Vector<PBVHVbo> vbos;
|
||||
|
||||
for (const int i : requests.index_range()) {
|
||||
const AttributeRequest &request = requests[i];
|
||||
if (!pbvh_attr_supported(request)) {
|
||||
continue;
|
||||
}
|
||||
vbos.append_as(request);
|
||||
batch.vbos.append(i);
|
||||
}
|
||||
|
||||
GPUVertBufRaw access;
|
||||
GPU_vertbuf_attr_get_raw_data(vbo.vert_buf, 0, &access);
|
||||
batch.is_coarse = do_coarse_grids;
|
||||
return batch.build_key(vbos);
|
||||
}
|
||||
|
||||
if (const CustomRequest *request_type = std::get_if<CustomRequest>(&vbo.request)) {
|
||||
switch (*request_type) {
|
||||
case CustomRequest::Position: {
|
||||
int PBVHBatches::ensure_vbo(const AttributeRequest &request, const PBVH_GPU_Args &args)
|
||||
{
|
||||
for (const int i : vbos.index_range()) {
|
||||
if (this->vbos[i].request == request) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return this->create_vbo(request, args);
|
||||
}
|
||||
|
||||
static PBVHBatch &ensure_batch(PBVHBatches &batches,
|
||||
const Span<AttributeRequest> requests,
|
||||
const PBVH_GPU_Args &args,
|
||||
const bool do_coarse_grids)
|
||||
{
|
||||
std::string key = build_key(requests, do_coarse_grids);
|
||||
if (PBVHBatch *batch = batches.batches.lookup_ptr(key)) {
|
||||
return *batch;
|
||||
}
|
||||
return batches.batches.lookup_or_add(std::move(key),
|
||||
create_batch(batches, requests, args, do_coarse_grids));
|
||||
}
|
||||
|
||||
static void fill_vbo_normal_faces(const PBVH_GPU_Args &args, gpu::VertBuf &vert_buf)
|
||||
{
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
|
||||
|
||||
short4 *data = static_cast<short4 *>(GPU_vertbuf_get_data(vert_buf));
|
||||
|
||||
short4 face_no;
|
||||
int last_face = -1;
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
const int face_i = args.tri_faces[tri_i];
|
||||
if (!args.hide_poly.is_empty() && args.hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
if (!sharp_faces.is_empty() && sharp_faces[face_i]) {
|
||||
if (face_i != last_face) {
|
||||
face_no = normal_float_to_short(args.face_normals[face_i]);
|
||||
last_face = face_i;
|
||||
}
|
||||
std::fill_n(data, 3, face_no);
|
||||
data += 3;
|
||||
}
|
||||
else {
|
||||
for (const int i : IndexRange(3)) {
|
||||
const int vert = args.corner_verts[args.corner_tris[tri_i][i]];
|
||||
*data = normal_float_to_short(args.vert_normals[vert]);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_vbo_grids_intern(
|
||||
PBVHVbo &vbo,
|
||||
const PBVH_GPU_Args &args,
|
||||
FunctionRef<void(FunctionRef<void(int x, int y, int grid_index, CCGElem *elems[4], int i)>
|
||||
func)> foreach_grids)
|
||||
{
|
||||
uint vert_per_grid = square_i(args.ccg_key.grid_size - 1) * 4;
|
||||
uint vert_count = args.grid_indices.size() * vert_per_grid;
|
||||
|
||||
int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf);
|
||||
void *existing_data = GPU_vertbuf_get_data(*vbo.vert_buf);
|
||||
|
||||
if (existing_data == nullptr || existing_num != vert_count) {
|
||||
/* Allocate buffer if not allocated yet or size changed. */
|
||||
GPU_vertbuf_data_alloc(*vbo.vert_buf, vert_count);
|
||||
}
|
||||
|
||||
GPUVertBufRaw access;
|
||||
GPU_vertbuf_attr_get_raw_data(vbo.vert_buf, 0, &access);
|
||||
|
||||
if (const CustomRequest *request_type = std::get_if<CustomRequest>(&vbo.request)) {
|
||||
switch (*request_type) {
|
||||
case CustomRequest::Position: {
|
||||
foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) {
|
||||
*static_cast<float3 *>(GPU_vertbuf_raw_step(&access)) = CCG_elem_co(args.ccg_key,
|
||||
elems[i]);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Normal: {
|
||||
const Span<int> grid_to_face_map = args.subdiv_ccg->grid_to_face_map;
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face",
|
||||
bke::AttrDomain::Face);
|
||||
|
||||
foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) {
|
||||
float3 no(0.0f, 0.0f, 0.0f);
|
||||
|
||||
const bool smooth = !(!sharp_faces.is_empty() &&
|
||||
sharp_faces[grid_to_face_map[grid_index]]);
|
||||
|
||||
if (smooth) {
|
||||
no = CCG_elem_no(args.ccg_key, elems[0]);
|
||||
}
|
||||
else {
|
||||
normal_quad_v3(no,
|
||||
CCG_elem_co(args.ccg_key, elems[3]),
|
||||
CCG_elem_co(args.ccg_key, elems[2]),
|
||||
CCG_elem_co(args.ccg_key, elems[1]),
|
||||
CCG_elem_co(args.ccg_key, elems[0]));
|
||||
}
|
||||
|
||||
short sno[3];
|
||||
|
||||
normal_float_to_short_v3(sno, no);
|
||||
|
||||
*static_cast<short3 *>(GPU_vertbuf_raw_step(&access)) = sno;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Mask: {
|
||||
if (args.ccg_key.has_mask) {
|
||||
foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) {
|
||||
*static_cast<float3 *>(GPU_vertbuf_raw_step(&access)) = CCG_elem_co(args.ccg_key,
|
||||
elems[i]);
|
||||
*static_cast<float *>(GPU_vertbuf_raw_step(&access)) = CCG_elem_mask(args.ccg_key,
|
||||
elems[i]);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Normal: {
|
||||
const Span<int> grid_to_face_map = args.subdiv_ccg->grid_to_face_map;
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face",
|
||||
bke::AttrDomain::Face);
|
||||
|
||||
foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) {
|
||||
float3 no(0.0f, 0.0f, 0.0f);
|
||||
|
||||
const bool smooth = !(!sharp_faces.is_empty() &&
|
||||
sharp_faces[grid_to_face_map[grid_index]]);
|
||||
|
||||
if (smooth) {
|
||||
no = CCG_elem_no(args.ccg_key, elems[0]);
|
||||
}
|
||||
else {
|
||||
normal_quad_v3(no,
|
||||
CCG_elem_co(args.ccg_key, elems[3]),
|
||||
CCG_elem_co(args.ccg_key, elems[2]),
|
||||
CCG_elem_co(args.ccg_key, elems[1]),
|
||||
CCG_elem_co(args.ccg_key, elems[0]));
|
||||
}
|
||||
|
||||
short sno[3];
|
||||
|
||||
normal_float_to_short_v3(sno, no);
|
||||
|
||||
*static_cast<short3 *>(GPU_vertbuf_raw_step(&access)) = sno;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Mask: {
|
||||
if (args.ccg_key.has_mask) {
|
||||
foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) {
|
||||
*static_cast<float *>(GPU_vertbuf_raw_step(&access)) = CCG_elem_mask(args.ccg_key,
|
||||
elems[i]);
|
||||
});
|
||||
}
|
||||
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 CustomRequest::FaceSet: {
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
if (const VArray<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
|
||||
bke::AttrDomain::Face))
|
||||
{
|
||||
const VArraySpan<int> face_sets_span(face_sets);
|
||||
foreach_grids(
|
||||
[&](int /*x*/, int /*y*/, int grid_index, CCGElem * /*elems*/[4], int /*i*/) {
|
||||
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
|
||||
|
||||
const int face_index = BKE_subdiv_ccg_grid_to_face_index(*args.subdiv_ccg,
|
||||
grid_index);
|
||||
const int fset = face_sets_span[face_index];
|
||||
|
||||
/* Skip for the default color Face Set to render it white. */
|
||||
if (fset != args.face_sets_color_default) {
|
||||
BKE_paint_face_set_overlay_color_get(
|
||||
fset, args.face_sets_color_seed, face_set_color);
|
||||
}
|
||||
|
||||
*static_cast<uchar4 *>(GPU_vertbuf_raw_step(&access)) = face_set_color;
|
||||
});
|
||||
}
|
||||
else {
|
||||
const uchar white[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
|
||||
foreach_grids(
|
||||
[&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) {
|
||||
*static_cast<uchar4 *>(GPU_vertbuf_raw_step(&access)) = white;
|
||||
});
|
||||
}
|
||||
break;
|
||||
else {
|
||||
MutableSpan(static_cast<float *>(GPU_vertbuf_get_data(*vbo.vert_buf)),
|
||||
GPU_vertbuf_get_vertex_len(vbo.vert_buf))
|
||||
.fill(0.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const eCustomDataType type = std::get<GenericRequest>(vbo.request).type;
|
||||
bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
using Converter = AttributeConverter<T>;
|
||||
using VBOType = typename Converter::VBOType;
|
||||
if constexpr (!std::is_void_v<VBOType>) {
|
||||
std::fill_n(static_cast<VBOType *>(GPU_vertbuf_get_data(*vbo.vert_buf)),
|
||||
GPU_vertbuf_get_vertex_len(vbo.vert_buf),
|
||||
Converter::convert(fallback_value_for_fill<T>()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
case CustomRequest::FaceSet: {
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
if (const VArray<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
|
||||
bke::AttrDomain::Face))
|
||||
{
|
||||
const VArraySpan<int> face_sets_span(face_sets);
|
||||
foreach_grids(
|
||||
[&](int /*x*/, int /*y*/, int grid_index, CCGElem * /*elems*/[4], int /*i*/) {
|
||||
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
|
||||
|
||||
void fill_vbo_grids(PBVHVbo &vbo, const PBVH_GPU_Args &args)
|
||||
{
|
||||
int gridsize = args.ccg_key.grid_size;
|
||||
|
||||
uint totgrid = args.grid_indices.size();
|
||||
|
||||
auto foreach_solid =
|
||||
[&](FunctionRef<void(int x, int y, int grid_index, CCGElem *elems[4], int i)> func) {
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
const int grid_index = args.grid_indices[i];
|
||||
|
||||
CCGElem *grid = args.grids[grid_index];
|
||||
|
||||
for (int y = 0; y < gridsize - 1; y++) {
|
||||
for (int x = 0; x < gridsize - 1; x++) {
|
||||
CCGElem *elems[4] = {
|
||||
CCG_grid_elem(args.ccg_key, grid, x, y),
|
||||
CCG_grid_elem(args.ccg_key, grid, x + 1, y),
|
||||
CCG_grid_elem(args.ccg_key, grid, x + 1, y + 1),
|
||||
CCG_grid_elem(args.ccg_key, grid, x, y + 1),
|
||||
};
|
||||
|
||||
func(x, y, grid_index, elems, 0);
|
||||
func(x + 1, y, grid_index, elems, 1);
|
||||
func(x + 1, y + 1, grid_index, elems, 2);
|
||||
func(x, y + 1, grid_index, elems, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto foreach_indexed =
|
||||
[&](FunctionRef<void(int x, int y, int grid_index, CCGElem *elems[4], int i)> func) {
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
const int grid_index = args.grid_indices[i];
|
||||
|
||||
CCGElem *grid = args.grids[grid_index];
|
||||
|
||||
for (int y = 0; y < gridsize; y++) {
|
||||
for (int x = 0; x < gridsize; x++) {
|
||||
CCGElem *elems[4] = {
|
||||
CCG_grid_elem(args.ccg_key, grid, x, y),
|
||||
CCG_grid_elem(args.ccg_key, grid, min_ii(x + 1, gridsize - 1), y),
|
||||
CCG_grid_elem(args.ccg_key,
|
||||
grid,
|
||||
min_ii(x + 1, gridsize - 1),
|
||||
min_ii(y + 1, gridsize - 1)),
|
||||
CCG_grid_elem(args.ccg_key, grid, x, min_ii(y + 1, gridsize - 1)),
|
||||
};
|
||||
|
||||
func(x, y, grid_index, elems, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (needs_tri_index) {
|
||||
fill_vbo_grids_intern(vbo, args, foreach_indexed);
|
||||
}
|
||||
else {
|
||||
fill_vbo_grids_intern(vbo, args, foreach_solid);
|
||||
}
|
||||
}
|
||||
|
||||
void fill_vbo_faces(PBVHVbo &vbo, const PBVH_GPU_Args &args)
|
||||
{
|
||||
const int totvert = this->count_faces(args) * 3;
|
||||
|
||||
int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf);
|
||||
void *existing_data = GPU_vertbuf_get_data(*vbo.vert_buf);
|
||||
|
||||
if (existing_data == nullptr || existing_num != totvert) {
|
||||
/* Allocate buffer if not allocated yet or size changed. */
|
||||
GPU_vertbuf_data_alloc(*vbo.vert_buf, totvert);
|
||||
}
|
||||
|
||||
gpu::VertBuf &vert_buf = *vbo.vert_buf;
|
||||
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
|
||||
if (const CustomRequest *request_type = std::get_if<CustomRequest>(&vbo.request)) {
|
||||
switch (*request_type) {
|
||||
case CustomRequest::Position: {
|
||||
extract_data_vert_faces<float3>(args, args.vert_positions, vert_buf);
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Normal: {
|
||||
fill_vbo_normal_faces(args, vert_buf);
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Mask: {
|
||||
float *data = static_cast<float *>(GPU_vertbuf_get_data(vert_buf));
|
||||
if (const VArray<float> mask = *attributes.lookup<float>(".sculpt_mask",
|
||||
bke::AttrDomain::Point))
|
||||
{
|
||||
const VArraySpan<float> mask_span(mask);
|
||||
const Span<int> corner_verts = args.corner_verts;
|
||||
const Span<int3> corner_tris = args.corner_tris;
|
||||
const Span<int> tri_faces = args.tri_faces;
|
||||
const Span<bool> hide_poly = args.hide_poly;
|
||||
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri_i]]) {
|
||||
continue;
|
||||
}
|
||||
for (int i : IndexRange(3)) {
|
||||
const int vert = corner_verts[corner_tris[tri_i][i]];
|
||||
*data = mask_span[vert];
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
MutableSpan(data, totvert).fill(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CustomRequest::FaceSet: {
|
||||
uchar4 *data = static_cast<uchar4 *>(GPU_vertbuf_get_data(vert_buf));
|
||||
if (const VArray<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
|
||||
bke::AttrDomain::Face))
|
||||
{
|
||||
const VArraySpan<int> face_sets_span(face_sets);
|
||||
int last_face = -1;
|
||||
uchar4 fset_color(UCHAR_MAX);
|
||||
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
if (!args.hide_poly.is_empty() && args.hide_poly[args.tri_faces[tri_i]]) {
|
||||
continue;
|
||||
}
|
||||
const int face_i = args.tri_faces[tri_i];
|
||||
if (last_face != face_i) {
|
||||
last_face = face_i;
|
||||
|
||||
const int fset = face_sets_span[face_i];
|
||||
const int face_index = BKE_subdiv_ccg_grid_to_face_index(*args.subdiv_ccg,
|
||||
grid_index);
|
||||
const int fset = face_sets_span[face_index];
|
||||
|
||||
/* Skip for the default color Face Set to render it white. */
|
||||
if (fset != args.face_sets_color_default) {
|
||||
BKE_paint_face_set_overlay_color_get(
|
||||
fset, args.face_sets_color_seed, fset_color);
|
||||
fset, args.face_sets_color_seed, face_set_color);
|
||||
}
|
||||
else {
|
||||
/* Skip for the default color face set to render it white. */
|
||||
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
|
||||
}
|
||||
}
|
||||
std::fill_n(data, 3, fset_color);
|
||||
data += 3;
|
||||
|
||||
*static_cast<uchar4 *>(GPU_vertbuf_raw_step(&access)) = face_set_color;
|
||||
});
|
||||
}
|
||||
else {
|
||||
const uchar white[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
|
||||
foreach_grids(
|
||||
[&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) {
|
||||
*static_cast<uchar4 *>(GPU_vertbuf_raw_step(&access)) = white;
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const eCustomDataType type = std::get<GenericRequest>(vbo.request).type;
|
||||
bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
using Converter = AttributeConverter<T>;
|
||||
using VBOType = typename Converter::VBOType;
|
||||
if constexpr (!std::is_void_v<VBOType>) {
|
||||
std::fill_n(static_cast<VBOType *>(GPU_vertbuf_get_data(*vbo.vert_buf)),
|
||||
GPU_vertbuf_get_vertex_len(vbo.vert_buf),
|
||||
Converter::convert(fallback_value_for_fill<T>()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_vbo_grids(PBVHVbo &vbo, const PBVH_GPU_Args &args, const bool needs_tri_index)
|
||||
{
|
||||
int gridsize = args.ccg_key.grid_size;
|
||||
|
||||
uint totgrid = args.grid_indices.size();
|
||||
|
||||
auto foreach_solid =
|
||||
[&](FunctionRef<void(int x, int y, int grid_index, CCGElem *elems[4], int i)> func) {
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
const int grid_index = args.grid_indices[i];
|
||||
|
||||
CCGElem *grid = args.grids[grid_index];
|
||||
|
||||
for (int y = 0; y < gridsize - 1; y++) {
|
||||
for (int x = 0; x < gridsize - 1; x++) {
|
||||
CCGElem *elems[4] = {
|
||||
CCG_grid_elem(args.ccg_key, grid, x, y),
|
||||
CCG_grid_elem(args.ccg_key, grid, x + 1, y),
|
||||
CCG_grid_elem(args.ccg_key, grid, x + 1, y + 1),
|
||||
CCG_grid_elem(args.ccg_key, grid, x, y + 1),
|
||||
};
|
||||
|
||||
func(x, y, grid_index, elems, 0);
|
||||
func(x + 1, y, grid_index, elems, 1);
|
||||
func(x + 1, y + 1, grid_index, elems, 2);
|
||||
func(x, y + 1, grid_index, elems, 3);
|
||||
}
|
||||
}
|
||||
else {
|
||||
MutableSpan(data, totvert).fill(uchar4(255));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const GenericRequest &request = std::get<GenericRequest>(vbo.request);
|
||||
const StringRef name = request.name;
|
||||
const bke::AttrDomain domain = request.domain;
|
||||
const eCustomDataType data_type = request.type;
|
||||
const GVArraySpan attribute = *attributes.lookup_or_default(name, domain, data_type);
|
||||
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
|
||||
switch (domain) {
|
||||
case bke::AttrDomain::Point:
|
||||
extract_data_vert_faces<T>(args, attribute.typed<T>(), vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Face:
|
||||
extract_data_face_faces<T>(args, attribute.typed<T>(), vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Corner:
|
||||
extract_data_corner_faces<T>(args, attribute.typed<T>(), vert_buf);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
};
|
||||
|
||||
auto foreach_indexed =
|
||||
[&](FunctionRef<void(int x, int y, int grid_index, CCGElem *elems[4], int i)> func) {
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
const int grid_index = args.grid_indices[i];
|
||||
|
||||
CCGElem *grid = args.grids[grid_index];
|
||||
|
||||
for (int y = 0; y < gridsize; y++) {
|
||||
for (int x = 0; x < gridsize; x++) {
|
||||
CCGElem *elems[4] = {
|
||||
CCG_grid_elem(args.ccg_key, grid, x, y),
|
||||
CCG_grid_elem(args.ccg_key, grid, min_ii(x + 1, gridsize - 1), y),
|
||||
CCG_grid_elem(args.ccg_key,
|
||||
grid,
|
||||
min_ii(x + 1, gridsize - 1),
|
||||
min_ii(y + 1, gridsize - 1)),
|
||||
CCG_grid_elem(args.ccg_key, grid, x, min_ii(y + 1, gridsize - 1)),
|
||||
};
|
||||
|
||||
func(x, y, grid_index, elems, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (needs_tri_index) {
|
||||
fill_vbo_grids_intern(vbo, args, foreach_indexed);
|
||||
}
|
||||
else {
|
||||
fill_vbo_grids_intern(vbo, args, foreach_solid);
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_vbo_faces(PBVHVbo &vbo, const PBVH_GPU_Args &args)
|
||||
{
|
||||
const int totvert = count_faces(args) * 3;
|
||||
|
||||
int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf);
|
||||
void *existing_data = GPU_vertbuf_get_data(*vbo.vert_buf);
|
||||
|
||||
if (existing_data == nullptr || existing_num != totvert) {
|
||||
/* Allocate buffer if not allocated yet or size changed. */
|
||||
GPU_vertbuf_data_alloc(*vbo.vert_buf, totvert);
|
||||
}
|
||||
|
||||
void gpu_flush()
|
||||
{
|
||||
for (PBVHVbo &vbo : vbos) {
|
||||
if (vbo.vert_buf && GPU_vertbuf_get_data(*vbo.vert_buf)) {
|
||||
GPU_vertbuf_use(vbo.vert_buf);
|
||||
gpu::VertBuf &vert_buf = *vbo.vert_buf;
|
||||
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
|
||||
if (const CustomRequest *request_type = std::get_if<CustomRequest>(&vbo.request)) {
|
||||
switch (*request_type) {
|
||||
case CustomRequest::Position: {
|
||||
extract_data_vert_faces<float3>(args, args.vert_positions, vert_buf);
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Normal: {
|
||||
fill_vbo_normal_faces(args, vert_buf);
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Mask: {
|
||||
float *data = static_cast<float *>(GPU_vertbuf_get_data(vert_buf));
|
||||
if (const VArray<float> mask = *attributes.lookup<float>(".sculpt_mask",
|
||||
bke::AttrDomain::Point))
|
||||
{
|
||||
const VArraySpan<float> mask_span(mask);
|
||||
const Span<int> corner_verts = args.corner_verts;
|
||||
const Span<int3> corner_tris = args.corner_tris;
|
||||
const Span<int> tri_faces = args.tri_faces;
|
||||
const Span<bool> hide_poly = args.hide_poly;
|
||||
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri_i]]) {
|
||||
continue;
|
||||
}
|
||||
for (int i : IndexRange(3)) {
|
||||
const int vert = corner_verts[corner_tris[tri_i][i]];
|
||||
*data = mask_span[vert];
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
MutableSpan(data, totvert).fill(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CustomRequest::FaceSet: {
|
||||
uchar4 *data = static_cast<uchar4 *>(GPU_vertbuf_get_data(vert_buf));
|
||||
if (const VArray<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
|
||||
bke::AttrDomain::Face))
|
||||
{
|
||||
const VArraySpan<int> face_sets_span(face_sets);
|
||||
int last_face = -1;
|
||||
uchar4 fset_color(UCHAR_MAX);
|
||||
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
if (!args.hide_poly.is_empty() && args.hide_poly[args.tri_faces[tri_i]]) {
|
||||
continue;
|
||||
}
|
||||
const int face_i = args.tri_faces[tri_i];
|
||||
if (last_face != face_i) {
|
||||
last_face = face_i;
|
||||
|
||||
const int fset = face_sets_span[face_i];
|
||||
|
||||
if (fset != args.face_sets_color_default) {
|
||||
BKE_paint_face_set_overlay_color_get(fset, args.face_sets_color_seed, fset_color);
|
||||
}
|
||||
else {
|
||||
/* Skip for the default color face set to render it white. */
|
||||
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
|
||||
}
|
||||
}
|
||||
std::fill_n(data, 3, fset_color);
|
||||
data += 3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
MutableSpan(data, totvert).fill(uchar4(255));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const GenericRequest &request = std::get<GenericRequest>(vbo.request);
|
||||
const StringRef name = request.name;
|
||||
const bke::AttrDomain domain = request.domain;
|
||||
const eCustomDataType data_type = request.type;
|
||||
const GVArraySpan attribute = *attributes.lookup_or_default(name, domain, data_type);
|
||||
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
|
||||
switch (domain) {
|
||||
case bke::AttrDomain::Point:
|
||||
extract_data_vert_faces<T>(args, attribute.typed<T>(), vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Face:
|
||||
extract_data_face_faces<T>(args, attribute.typed<T>(), vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Corner:
|
||||
extract_data_corner_faces<T>(args, attribute.typed<T>(), vert_buf);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void update(const PBVH_GPU_Args &args)
|
||||
{
|
||||
if (!lines_index) {
|
||||
create_index(args);
|
||||
}
|
||||
for (PBVHVbo &vbo : vbos) {
|
||||
fill_vbo(vbo, args);
|
||||
static void gpu_flush(MutableSpan<PBVHVbo> vbos)
|
||||
{
|
||||
for (PBVHVbo &vbo : vbos) {
|
||||
if (vbo.vert_buf && GPU_vertbuf_get_data(*vbo.vert_buf)) {
|
||||
GPU_vertbuf_use(vbo.vert_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fill_vbo_bmesh(PBVHVbo &vbo, const PBVH_GPU_Args &args)
|
||||
{
|
||||
faces_count = count_faces(args);
|
||||
static void fill_vbo_bmesh(PBVHVbo &vbo, const PBVH_GPU_Args &args)
|
||||
{
|
||||
int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf);
|
||||
void *existing_data = GPU_vertbuf_get_data(*vbo.vert_buf);
|
||||
|
||||
int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf);
|
||||
void *existing_data = GPU_vertbuf_get_data(*vbo.vert_buf);
|
||||
int vert_count = count_faces(args) * 3;
|
||||
|
||||
int vert_count = faces_count * 3;
|
||||
if (existing_data == nullptr || existing_num != vert_count) {
|
||||
/* Allocate buffer if not allocated yet or size changed. */
|
||||
GPU_vertbuf_data_alloc(*vbo.vert_buf, vert_count);
|
||||
}
|
||||
|
||||
if (existing_data == nullptr || existing_num != vert_count) {
|
||||
/* Allocate buffer if not allocated yet or size changed. */
|
||||
GPU_vertbuf_data_alloc(*vbo.vert_buf, vert_count);
|
||||
}
|
||||
|
||||
GPUVertBufRaw access;
|
||||
GPU_vertbuf_attr_get_raw_data(vbo.vert_buf, 0, &access);
|
||||
GPUVertBufRaw access;
|
||||
GPU_vertbuf_attr_get_raw_data(vbo.vert_buf, 0, &access);
|
||||
|
||||
#if 0 /* Enable to fuzz GPU data (to check for over-allocation). */
|
||||
existing_data = GPU_vertbuf_get_data(vbo.vert_buf);
|
||||
@@ -826,557 +832,590 @@ struct PBVHBatches {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (const CustomRequest *request_type = std::get_if<CustomRequest>(&vbo.request)) {
|
||||
switch (*request_type) {
|
||||
case CustomRequest::Position: {
|
||||
float3 *data = static_cast<float3 *>(GPU_vertbuf_get_data(*vbo.vert_buf));
|
||||
if (const CustomRequest *request_type = std::get_if<CustomRequest>(&vbo.request)) {
|
||||
switch (*request_type) {
|
||||
case CustomRequest::Position: {
|
||||
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)) {
|
||||
continue;
|
||||
}
|
||||
const BMLoop *l = f->l_first;
|
||||
*data = l->prev->v->co;
|
||||
data++;
|
||||
*data = l->v->co;
|
||||
data++;
|
||||
*data = l->next->v->co;
|
||||
data++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Normal: {
|
||||
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)) {
|
||||
continue;
|
||||
}
|
||||
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
|
||||
const BMLoop *l = f->l_first;
|
||||
*data = normal_float_to_short(l->prev->v->no);
|
||||
data++;
|
||||
*data = normal_float_to_short(l->v->no);
|
||||
data++;
|
||||
*data = normal_float_to_short(l->next->v->no);
|
||||
data++;
|
||||
}
|
||||
else {
|
||||
std::fill_n(data, 3, normal_float_to_short(f->no));
|
||||
data += 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Mask: {
|
||||
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 = l->prev->v->co;
|
||||
*data = bmesh_cd_vert_get<float>(*l->prev->v, cd_offset);
|
||||
data++;
|
||||
*data = l->v->co;
|
||||
*data = bmesh_cd_vert_get<float>(*l->v, cd_offset);
|
||||
data++;
|
||||
*data = l->next->v->co;
|
||||
*data = bmesh_cd_vert_get<float>(*l->next->v, cd_offset);
|
||||
data++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Normal: {
|
||||
short4 *data = static_cast<short4 *>(GPU_vertbuf_get_data(*vbo.vert_buf));
|
||||
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 CustomRequest::FaceSet: {
|
||||
const int cd_offset = CustomData_get_offset_named(
|
||||
&args.bm->pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
|
||||
uchar4 *data = static_cast<uchar4 *>(GPU_vertbuf_get_data(*vbo.vert_buf));
|
||||
if (cd_offset != -1) {
|
||||
for (const BMFace *f : *args.bm_faces) {
|
||||
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
continue;
|
||||
}
|
||||
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
|
||||
const BMLoop *l = f->l_first;
|
||||
*data = normal_float_to_short(l->prev->v->no);
|
||||
data++;
|
||||
*data = normal_float_to_short(l->v->no);
|
||||
data++;
|
||||
*data = normal_float_to_short(l->next->v->no);
|
||||
data++;
|
||||
|
||||
const int fset = bmesh_cd_face_get<int>(*f, cd_offset);
|
||||
|
||||
uchar4 fset_color;
|
||||
if (fset != args.face_sets_color_default) {
|
||||
BKE_paint_face_set_overlay_color_get(fset, args.face_sets_color_seed, fset_color);
|
||||
}
|
||||
else {
|
||||
std::fill_n(data, 3, normal_float_to_short(f->no));
|
||||
data += 3;
|
||||
/* Skip for the default color face set to render it white. */
|
||||
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
|
||||
}
|
||||
std::fill_n(data, 3, fset_color);
|
||||
data += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CustomRequest::Mask: {
|
||||
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 CustomRequest::FaceSet: {
|
||||
const int cd_offset = CustomData_get_offset_named(
|
||||
&args.bm->pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
|
||||
uchar4 *data = static_cast<uchar4 *>(GPU_vertbuf_get_data(*vbo.vert_buf));
|
||||
if (cd_offset != -1) {
|
||||
for (const BMFace *f : *args.bm_faces) {
|
||||
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int fset = bmesh_cd_face_get<int>(*f, cd_offset);
|
||||
|
||||
uchar4 fset_color;
|
||||
if (fset != args.face_sets_color_default) {
|
||||
BKE_paint_face_set_overlay_color_get(fset, args.face_sets_color_seed, fset_color);
|
||||
}
|
||||
else {
|
||||
/* Skip for the default color face set to render it white. */
|
||||
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
|
||||
}
|
||||
std::fill_n(data, 3, fset_color);
|
||||
data += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
MutableSpan(data, GPU_vertbuf_get_vertex_len(vbo.vert_buf)).fill(uchar4(255));
|
||||
}
|
||||
else {
|
||||
MutableSpan(data, GPU_vertbuf_get_vertex_len(vbo.vert_buf)).fill(uchar4(255));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const GenericRequest &request = std::get<GenericRequest>(vbo.request);
|
||||
const bke::AttrDomain domain = request.domain;
|
||||
const eCustomDataType data_type = request.type;
|
||||
const CustomData &custom_data = *get_cdata(domain, args);
|
||||
const int cd_offset = CustomData_get_offset_named(&custom_data, data_type, request.name);
|
||||
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
|
||||
switch (domain) {
|
||||
case bke::AttrDomain::Point:
|
||||
extract_data_vert_bmesh<T>(args, cd_offset, *vbo.vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Face:
|
||||
extract_data_face_bmesh<T>(args, cd_offset, *vbo.vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Corner:
|
||||
extract_data_corner_bmesh<T>(args, cd_offset, *vbo.vert_buf);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
const GenericRequest &request = std::get<GenericRequest>(vbo.request);
|
||||
const bke::AttrDomain domain = request.domain;
|
||||
const eCustomDataType data_type = request.type;
|
||||
const CustomData &custom_data = *get_cdata(domain, args);
|
||||
const int cd_offset = CustomData_get_offset_named(&custom_data, data_type, request.name);
|
||||
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
|
||||
switch (domain) {
|
||||
case bke::AttrDomain::Point:
|
||||
extract_data_vert_bmesh<T>(args, cd_offset, *vbo.vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Face:
|
||||
extract_data_face_bmesh<T>(args, cd_offset, *vbo.vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Corner:
|
||||
extract_data_corner_bmesh<T>(args, cd_offset, *vbo.vert_buf);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void fill_vbo(PBVHVbo &vbo, const PBVH_GPU_Args &args)
|
||||
{
|
||||
void PBVHBatches::update(const PBVH_GPU_Args &args)
|
||||
{
|
||||
if (!lines_index) {
|
||||
create_index(args);
|
||||
}
|
||||
for (PBVHVbo &vbo : vbos) {
|
||||
switch (args.pbvh_type) {
|
||||
case PBVH_FACES:
|
||||
fill_vbo_faces(vbo, args);
|
||||
break;
|
||||
case PBVH_GRIDS:
|
||||
fill_vbo_grids(vbo, args);
|
||||
fill_vbo_grids(vbo, args, needs_tri_index);
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
fill_vbo_bmesh(vbo, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int create_vbo(const AttributeRequest &request, const PBVH_GPU_Args &args)
|
||||
{
|
||||
|
||||
GPUVertFormat format;
|
||||
GPU_vertformat_clear(&format);
|
||||
if (const CustomRequest *request_type = std::get_if<CustomRequest>(&request)) {
|
||||
switch (*request_type) {
|
||||
case CustomRequest::Position:
|
||||
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
break;
|
||||
case CustomRequest::Normal:
|
||||
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
break;
|
||||
case CustomRequest::Mask:
|
||||
GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
break;
|
||||
case CustomRequest::FaceSet:
|
||||
GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
break;
|
||||
}
|
||||
int PBVHBatches::create_vbo(const AttributeRequest &request, const PBVH_GPU_Args &args)
|
||||
{
|
||||
GPUVertFormat format;
|
||||
GPU_vertformat_clear(&format);
|
||||
if (const CustomRequest *request_type = std::get_if<CustomRequest>(&request)) {
|
||||
switch (*request_type) {
|
||||
case CustomRequest::Position:
|
||||
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
break;
|
||||
case CustomRequest::Normal:
|
||||
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
break;
|
||||
case CustomRequest::Mask:
|
||||
GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
break;
|
||||
case CustomRequest::FaceSet:
|
||||
GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
const GenericRequest &attr = std::get<GenericRequest>(request);
|
||||
const StringRefNull name = attr.name;
|
||||
const bke::AttrDomain domain = attr.domain;
|
||||
const eCustomDataType data_type = attr.type;
|
||||
}
|
||||
else {
|
||||
const GenericRequest &attr = std::get<GenericRequest>(request);
|
||||
const StringRefNull name = attr.name;
|
||||
const bke::AttrDomain domain = attr.domain;
|
||||
const eCustomDataType data_type = attr.type;
|
||||
|
||||
format = draw::init_format_for_attribute(data_type, "data");
|
||||
format = draw::init_format_for_attribute(data_type, "data");
|
||||
|
||||
const CustomData *cdata = get_cdata(domain, args);
|
||||
const CustomData *cdata = get_cdata(domain, args);
|
||||
|
||||
bool is_render, is_active;
|
||||
const char *prefix = "a";
|
||||
bool is_render, is_active;
|
||||
const char *prefix = "a";
|
||||
|
||||
if (CD_TYPE_AS_MASK(data_type) & CD_MASK_COLOR_ALL) {
|
||||
prefix = "c";
|
||||
is_active = StringRef(args.active_color) == name;
|
||||
is_render = StringRef(args.render_color) == name;
|
||||
}
|
||||
if (data_type == CD_PROP_FLOAT2) {
|
||||
prefix = "u";
|
||||
is_active = StringRef(CustomData_get_active_layer_name(cdata, data_type)) == name;
|
||||
is_render = StringRef(CustomData_get_render_layer_name(cdata, data_type)) == name;
|
||||
}
|
||||
|
||||
DRW_cdlayer_attr_aliases_add(&format, prefix, data_type, name.c_str(), is_render, is_active);
|
||||
if (CD_TYPE_AS_MASK(data_type) & CD_MASK_COLOR_ALL) {
|
||||
prefix = "c";
|
||||
is_active = StringRef(args.active_color) == name;
|
||||
is_render = StringRef(args.render_color) == name;
|
||||
}
|
||||
if (data_type == CD_PROP_FLOAT2) {
|
||||
prefix = "u";
|
||||
is_active = StringRef(CustomData_get_active_layer_name(cdata, data_type)) == name;
|
||||
is_render = StringRef(CustomData_get_render_layer_name(cdata, data_type)) == name;
|
||||
}
|
||||
|
||||
vbos.append_as(request);
|
||||
vbos.last().vert_buf = GPU_vertbuf_create_with_format_ex(format, GPU_USAGE_STATIC);
|
||||
fill_vbo(vbos.last(), args);
|
||||
|
||||
return vbos.index_range().last();
|
||||
DRW_cdlayer_attr_aliases_add(&format, prefix, data_type, name.c_str(), is_render, is_active);
|
||||
}
|
||||
|
||||
void update_pre(const PBVH_GPU_Args &args)
|
||||
{
|
||||
if (args.pbvh_type == PBVH_BMESH) {
|
||||
int count = count_faces(args);
|
||||
vbos.append_as(request);
|
||||
vbos.last().vert_buf = GPU_vertbuf_create_with_format_ex(format, GPU_USAGE_STATIC);
|
||||
switch (args.pbvh_type) {
|
||||
case PBVH_FACES:
|
||||
fill_vbo_faces(vbos.last(), args);
|
||||
break;
|
||||
case PBVH_GRIDS:
|
||||
fill_vbo_grids(vbos.last(), args, needs_tri_index);
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
fill_vbo_bmesh(vbos.last(), args);
|
||||
break;
|
||||
}
|
||||
|
||||
if (faces_count != count) {
|
||||
for (PBVHVbo &vbo : vbos) {
|
||||
vbo.clear_data();
|
||||
return vbos.index_range().last();
|
||||
}
|
||||
|
||||
void PBVHBatches::update_pre(const PBVH_GPU_Args &args)
|
||||
{
|
||||
if (args.pbvh_type == PBVH_BMESH) {
|
||||
int count = count_faces(args);
|
||||
|
||||
if (faces_count != count) {
|
||||
for (PBVHVbo &vbo : vbos) {
|
||||
vbo.clear_data();
|
||||
}
|
||||
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index_coarse);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index_coarse);
|
||||
|
||||
faces_count = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gpu::IndexBuf *create_index_faces(const PBVH_GPU_Args &args)
|
||||
{
|
||||
const Span<int2> edges = args.mesh->edges();
|
||||
|
||||
/* Calculate number of edges. */
|
||||
int edge_count = 0;
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
const int face_i = args.tri_faces[tri_i];
|
||||
if (!args.hide_poly.is_empty() && args.hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
|
||||
edges, args.corner_verts, args.corner_edges, args.corner_tris[tri_i]);
|
||||
|
||||
if (real_edges[0] != -1) {
|
||||
edge_count++;
|
||||
}
|
||||
if (real_edges[1] != -1) {
|
||||
edge_count++;
|
||||
}
|
||||
if (real_edges[2] != -1) {
|
||||
edge_count++;
|
||||
}
|
||||
}
|
||||
|
||||
GPUIndexBufBuilder elb_lines;
|
||||
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, edge_count * 2, INT_MAX);
|
||||
|
||||
int vertex_i = 0;
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
const int face_i = args.tri_faces[tri_i];
|
||||
if (!args.hide_poly.is_empty() && args.hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
|
||||
edges, args.corner_verts, args.corner_edges, args.corner_tris[tri_i]);
|
||||
|
||||
if (real_edges[0] != -1) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, vertex_i, vertex_i + 1);
|
||||
}
|
||||
if (real_edges[1] != -1) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, vertex_i + 1, vertex_i + 2);
|
||||
}
|
||||
if (real_edges[2] != -1) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, vertex_i + 2, vertex_i);
|
||||
}
|
||||
|
||||
vertex_i += 3;
|
||||
}
|
||||
|
||||
return GPU_indexbuf_build(&elb_lines);
|
||||
}
|
||||
|
||||
static gpu::IndexBuf *create_index_bmesh(const PBVH_GPU_Args &args, const int visible_faces_num)
|
||||
{
|
||||
GPUIndexBufBuilder elb_lines;
|
||||
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, visible_faces_num * 3 * 2, INT_MAX);
|
||||
|
||||
int v_index = 0;
|
||||
|
||||
for (const BMFace *f : *args.bm_faces) {
|
||||
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v_index, v_index + 1);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index);
|
||||
|
||||
v_index += 3;
|
||||
}
|
||||
|
||||
return GPU_indexbuf_build(&elb_lines);
|
||||
}
|
||||
|
||||
static void create_tris_from_grids(const PBVH_GPU_Args &args,
|
||||
int display_gridsize,
|
||||
GPUIndexBufBuilder &elb,
|
||||
GPUIndexBufBuilder &elb_lines,
|
||||
const BitGroupVector<> &grid_hidden,
|
||||
const int gridsize,
|
||||
const int skip,
|
||||
const int totgrid)
|
||||
{
|
||||
uint offset = 0;
|
||||
const uint grid_vert_len = gridsize * gridsize;
|
||||
for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
|
||||
uint v0, v1, v2, v3;
|
||||
bool grid_visible = false;
|
||||
|
||||
const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
|
||||
grid_hidden[args.grid_indices[i]];
|
||||
|
||||
for (int y = 0; y < gridsize - skip; y += skip) {
|
||||
for (int x = 0; x < gridsize - skip; x += skip) {
|
||||
/* Skip hidden grid face */
|
||||
if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
continue;
|
||||
}
|
||||
/* Indices in a Clockwise QUAD disposition. */
|
||||
v0 = offset + CCG_grid_xy_to_index(gridsize, x, y);
|
||||
v1 = offset + CCG_grid_xy_to_index(gridsize, x + skip, y);
|
||||
v2 = offset + CCG_grid_xy_to_index(gridsize, x + skip, y + skip);
|
||||
v3 = offset + CCG_grid_xy_to_index(gridsize, x, y + skip);
|
||||
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1);
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2);
|
||||
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v1);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v3);
|
||||
|
||||
if (y / skip + 2 == display_gridsize) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v2, v3);
|
||||
}
|
||||
grid_visible = true;
|
||||
}
|
||||
|
||||
if (grid_visible) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void create_quads_from_grids(const PBVH_GPU_Args &args,
|
||||
int display_gridsize,
|
||||
GPUIndexBufBuilder &elb,
|
||||
GPUIndexBufBuilder &elb_lines,
|
||||
const BitGroupVector<> &grid_hidden,
|
||||
const int gridsize,
|
||||
const int skip,
|
||||
const int totgrid)
|
||||
{
|
||||
uint offset = 0;
|
||||
const uint grid_vert_len = square_uint(gridsize - 1) * 4;
|
||||
|
||||
for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
|
||||
bool grid_visible = false;
|
||||
const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
|
||||
grid_hidden[args.grid_indices[i]];
|
||||
|
||||
uint v0, v1, v2, v3;
|
||||
for (int y = 0; y < gridsize - skip; y += skip) {
|
||||
for (int x = 0; x < gridsize - skip; x += skip) {
|
||||
/* Skip hidden grid face */
|
||||
if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index_coarse);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index_coarse);
|
||||
v0 = (y * (gridsize - 1) + x) * 4;
|
||||
|
||||
faces_count = count;
|
||||
if (skip > 1) {
|
||||
v1 = (y * (gridsize - 1) + x + skip - 1) * 4;
|
||||
v2 = ((y + skip - 1) * (gridsize - 1) + x + skip - 1) * 4;
|
||||
v3 = ((y + skip - 1) * (gridsize - 1) + x) * 4;
|
||||
}
|
||||
else {
|
||||
v1 = v2 = v3 = v0;
|
||||
}
|
||||
|
||||
/* VBO data are in a Clockwise QUAD disposition. Note
|
||||
* that vertices might be in different quads if we're
|
||||
* building a coarse index buffer.
|
||||
*/
|
||||
v0 += offset;
|
||||
v1 += offset + 1;
|
||||
v2 += offset + 2;
|
||||
v3 += offset + 3;
|
||||
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1);
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2);
|
||||
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v1);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v3);
|
||||
|
||||
if (y / skip + 2 == display_gridsize) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v2, v3);
|
||||
}
|
||||
grid_visible = true;
|
||||
}
|
||||
|
||||
if (grid_visible) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void create_index_faces(const PBVH_GPU_Args &args)
|
||||
{
|
||||
if (!args.prim_indices.is_empty()) {
|
||||
static int material_index_get(const PBVH_GPU_Args &args)
|
||||
{
|
||||
switch (args.pbvh_type) {
|
||||
case PBVH_FACES: {
|
||||
if (args.prim_indices.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
const VArray material_indices = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Face, 0);
|
||||
material_index = material_indices[args.tri_faces[args.prim_indices.first()]];
|
||||
return material_indices[args.tri_faces[args.prim_indices.first()]];
|
||||
}
|
||||
|
||||
const Span<int2> edges = args.mesh->edges();
|
||||
|
||||
/* Calculate number of edges. */
|
||||
int edge_count = 0;
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
const int face_i = args.tri_faces[tri_i];
|
||||
if (!args.hide_poly.is_empty() && args.hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
|
||||
edges, args.corner_verts, args.corner_edges, args.corner_tris[tri_i]);
|
||||
|
||||
if (real_edges[0] != -1) {
|
||||
edge_count++;
|
||||
}
|
||||
if (real_edges[1] != -1) {
|
||||
edge_count++;
|
||||
}
|
||||
if (real_edges[2] != -1) {
|
||||
edge_count++;
|
||||
case PBVH_GRIDS: {
|
||||
if (args.grid_indices.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
const VArray material_indices = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Face, 0);
|
||||
return material_indices[BKE_subdiv_ccg_grid_to_face_index(*args.subdiv_ccg,
|
||||
args.grid_indices.first())];
|
||||
}
|
||||
case PBVH_BMESH:
|
||||
return 0;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
GPUIndexBufBuilder elb_lines;
|
||||
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, edge_count * 2, INT_MAX);
|
||||
static void create_index_grids(const PBVH_GPU_Args &args,
|
||||
const bool do_coarse,
|
||||
PBVHBatches &batches)
|
||||
{
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
|
||||
|
||||
int vertex_i = 0;
|
||||
for (const int tri_i : args.prim_indices) {
|
||||
const int face_i = args.tri_faces[tri_i];
|
||||
if (!args.hide_poly.is_empty() && args.hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
const BitGroupVector<> &grid_hidden = args.subdiv_ccg->grid_hidden;
|
||||
const Span<int> grid_to_face_map = args.subdiv_ccg->grid_to_face_map;
|
||||
|
||||
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
|
||||
edges, args.corner_verts, args.corner_edges, args.corner_tris[tri_i]);
|
||||
batches.needs_tri_index = true;
|
||||
int gridsize = args.ccg_key.grid_size;
|
||||
int display_gridsize = gridsize;
|
||||
int totgrid = args.grid_indices.size();
|
||||
int skip = 1;
|
||||
|
||||
if (real_edges[0] != -1) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, vertex_i, vertex_i + 1);
|
||||
}
|
||||
if (real_edges[1] != -1) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, vertex_i + 1, vertex_i + 2);
|
||||
}
|
||||
if (real_edges[2] != -1) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, vertex_i + 2, vertex_i);
|
||||
}
|
||||
const int display_level = do_coarse ? batches.coarse_level : args.ccg_key.level;
|
||||
|
||||
vertex_i += 3;
|
||||
}
|
||||
|
||||
lines_index = GPU_indexbuf_build(&elb_lines);
|
||||
if (display_level < args.ccg_key.level) {
|
||||
display_gridsize = (1 << display_level) + 1;
|
||||
skip = 1 << (args.ccg_key.level - display_level - 1);
|
||||
}
|
||||
|
||||
void create_index_bmesh(const PBVH_GPU_Args &args)
|
||||
{
|
||||
GPUIndexBufBuilder elb_lines;
|
||||
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, faces_count * 3 * 2, INT_MAX);
|
||||
|
||||
int v_index = 0;
|
||||
|
||||
for (const BMFace *f : *args.bm_faces) {
|
||||
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v_index, v_index + 1);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index);
|
||||
|
||||
v_index += 3;
|
||||
}
|
||||
|
||||
lines_index = GPU_indexbuf_build(&elb_lines);
|
||||
}
|
||||
|
||||
void create_tris_from_grids(const PBVH_GPU_Args &args,
|
||||
int display_gridsize,
|
||||
GPUIndexBufBuilder &elb,
|
||||
GPUIndexBufBuilder &elb_lines,
|
||||
const BitGroupVector<> &grid_hidden,
|
||||
const int gridsize,
|
||||
const int skip,
|
||||
const int totgrid)
|
||||
{
|
||||
uint offset = 0;
|
||||
const uint grid_vert_len = gridsize * gridsize;
|
||||
for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
|
||||
uint v0, v1, v2, v3;
|
||||
bool grid_visible = false;
|
||||
|
||||
const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
|
||||
grid_hidden[args.grid_indices[i]];
|
||||
|
||||
for (int y = 0; y < gridsize - skip; y += skip) {
|
||||
for (int x = 0; x < gridsize - skip; x += skip) {
|
||||
/* Skip hidden grid face */
|
||||
if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
continue;
|
||||
}
|
||||
/* Indices in a Clockwise QUAD disposition. */
|
||||
v0 = offset + CCG_grid_xy_to_index(gridsize, x, y);
|
||||
v1 = offset + CCG_grid_xy_to_index(gridsize, x + skip, y);
|
||||
v2 = offset + CCG_grid_xy_to_index(gridsize, x + skip, y + skip);
|
||||
v3 = offset + CCG_grid_xy_to_index(gridsize, x, y + skip);
|
||||
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1);
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2);
|
||||
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v1);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v3);
|
||||
|
||||
if (y / skip + 2 == display_gridsize) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v2, v3);
|
||||
}
|
||||
grid_visible = true;
|
||||
}
|
||||
|
||||
if (grid_visible) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
|
||||
}
|
||||
}
|
||||
for (const int grid_index : args.grid_indices) {
|
||||
if (!sharp_faces.is_empty() && sharp_faces[grid_to_face_map[grid_index]]) {
|
||||
batches.needs_tri_index = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void create_quads_from_grids(const PBVH_GPU_Args &args,
|
||||
int display_gridsize,
|
||||
GPUIndexBufBuilder &elb,
|
||||
GPUIndexBufBuilder &elb_lines,
|
||||
const BitGroupVector<> &grid_hidden,
|
||||
const int gridsize,
|
||||
const int skip,
|
||||
const int totgrid)
|
||||
{
|
||||
uint offset = 0;
|
||||
const uint grid_vert_len = square_uint(gridsize - 1) * 4;
|
||||
GPUIndexBufBuilder elb, elb_lines;
|
||||
|
||||
for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
|
||||
bool grid_visible = false;
|
||||
const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
|
||||
grid_hidden[args.grid_indices[i]];
|
||||
const CCGKey *key = &args.ccg_key;
|
||||
|
||||
uint v0, v1, v2, v3;
|
||||
for (int y = 0; y < gridsize - skip; y += skip) {
|
||||
for (int x = 0; x < gridsize - skip; x += skip) {
|
||||
/* Skip hidden grid face */
|
||||
if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
continue;
|
||||
}
|
||||
uint visible_quad_len = bke::pbvh::count_grid_quads(
|
||||
grid_hidden, args.grid_indices, key->grid_size, display_gridsize);
|
||||
|
||||
v0 = (y * (gridsize - 1) + x) * 4;
|
||||
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, 2 * visible_quad_len, INT_MAX);
|
||||
GPU_indexbuf_init(&elb_lines,
|
||||
GPU_PRIM_LINES,
|
||||
2 * totgrid * display_gridsize * (display_gridsize - 1),
|
||||
INT_MAX);
|
||||
|
||||
if (skip > 1) {
|
||||
v1 = (y * (gridsize - 1) + x + skip - 1) * 4;
|
||||
v2 = ((y + skip - 1) * (gridsize - 1) + x + skip - 1) * 4;
|
||||
v3 = ((y + skip - 1) * (gridsize - 1) + x) * 4;
|
||||
}
|
||||
else {
|
||||
v1 = v2 = v3 = v0;
|
||||
}
|
||||
|
||||
/* VBO data are in a Clockwise QUAD disposition. Note
|
||||
* that vertices might be in different quads if we're
|
||||
* building a coarse index buffer.
|
||||
*/
|
||||
v0 += offset;
|
||||
v1 += offset + 1;
|
||||
v2 += offset + 2;
|
||||
v3 += offset + 3;
|
||||
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1);
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2);
|
||||
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v1);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v3);
|
||||
|
||||
if (y / skip + 2 == display_gridsize) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v2, v3);
|
||||
}
|
||||
grid_visible = true;
|
||||
}
|
||||
|
||||
if (grid_visible) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (batches.needs_tri_index) {
|
||||
create_tris_from_grids(
|
||||
args, display_gridsize, elb, elb_lines, grid_hidden, gridsize, skip, totgrid);
|
||||
}
|
||||
else {
|
||||
create_quads_from_grids(
|
||||
args, display_gridsize, elb, elb_lines, grid_hidden, gridsize, skip, totgrid);
|
||||
}
|
||||
|
||||
void create_index_grids(const PBVH_GPU_Args &args, bool do_coarse)
|
||||
{
|
||||
const bke::AttributeAccessor attributes = args.mesh->attributes();
|
||||
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
|
||||
const VArray material_indices = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Face, 0);
|
||||
const BitGroupVector<> &grid_hidden = args.subdiv_ccg->grid_hidden;
|
||||
const Span<int> grid_to_face_map = args.subdiv_ccg->grid_to_face_map;
|
||||
if (do_coarse) {
|
||||
batches.tri_index_coarse = GPU_indexbuf_build(&elb);
|
||||
batches.lines_index_coarse = GPU_indexbuf_build(&elb_lines);
|
||||
batches.tris_count_coarse = visible_quad_len;
|
||||
batches.lines_count_coarse = totgrid * display_gridsize * (display_gridsize - 1);
|
||||
}
|
||||
else {
|
||||
batches.tri_index = GPU_indexbuf_build(&elb);
|
||||
batches.lines_index = GPU_indexbuf_build(&elb_lines);
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.grid_indices.is_empty()) {
|
||||
material_index = material_indices[BKE_subdiv_ccg_grid_to_face_index(
|
||||
*args.subdiv_ccg, args.grid_indices.first())];
|
||||
}
|
||||
|
||||
needs_tri_index = true;
|
||||
int gridsize = args.ccg_key.grid_size;
|
||||
int display_gridsize = gridsize;
|
||||
int totgrid = args.grid_indices.size();
|
||||
int skip = 1;
|
||||
|
||||
const int display_level = do_coarse ? coarse_level : args.ccg_key.level;
|
||||
|
||||
if (display_level < args.ccg_key.level) {
|
||||
display_gridsize = (1 << display_level) + 1;
|
||||
skip = 1 << (args.ccg_key.level - display_level - 1);
|
||||
}
|
||||
|
||||
for (const int grid_index : args.grid_indices) {
|
||||
if (!sharp_faces.is_empty() && sharp_faces[grid_to_face_map[grid_index]]) {
|
||||
needs_tri_index = false;
|
||||
break;
|
||||
void PBVHBatches::create_index(const PBVH_GPU_Args &args)
|
||||
{
|
||||
switch (args.pbvh_type) {
|
||||
case PBVH_FACES:
|
||||
lines_index = create_index_faces(args);
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
lines_index = create_index_bmesh(args, faces_count);
|
||||
break;
|
||||
case PBVH_GRIDS:
|
||||
create_index_grids(args, false, *this);
|
||||
if (args.ccg_key.level > coarse_level) {
|
||||
create_index_grids(args, true, *this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
GPUIndexBufBuilder elb, elb_lines;
|
||||
|
||||
const CCGKey *key = &args.ccg_key;
|
||||
|
||||
uint visible_quad_len = bke::pbvh::count_grid_quads(
|
||||
grid_hidden, args.grid_indices, key->grid_size, display_gridsize);
|
||||
|
||||
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, 2 * visible_quad_len, INT_MAX);
|
||||
GPU_indexbuf_init(&elb_lines,
|
||||
GPU_PRIM_LINES,
|
||||
2 * totgrid * display_gridsize * (display_gridsize - 1),
|
||||
INT_MAX);
|
||||
|
||||
if (needs_tri_index) {
|
||||
create_tris_from_grids(
|
||||
args, display_gridsize, elb, elb_lines, grid_hidden, gridsize, skip, totgrid);
|
||||
for (PBVHBatch &batch : batches.values()) {
|
||||
if (tri_index) {
|
||||
GPU_batch_elembuf_set(batch.tris, tri_index, false);
|
||||
}
|
||||
else {
|
||||
create_quads_from_grids(
|
||||
args, display_gridsize, elb, elb_lines, grid_hidden, gridsize, skip, totgrid);
|
||||
/* Still flag the batch as dirty even if we're using the default index layout. */
|
||||
batch.tris->flag |= GPU_BATCH_DIRTY;
|
||||
}
|
||||
|
||||
if (do_coarse) {
|
||||
tri_index_coarse = GPU_indexbuf_build(&elb);
|
||||
lines_index_coarse = GPU_indexbuf_build(&elb_lines);
|
||||
tris_count_coarse = visible_quad_len;
|
||||
lines_count_coarse = totgrid * display_gridsize * (display_gridsize - 1);
|
||||
}
|
||||
else {
|
||||
tri_index = GPU_indexbuf_build(&elb);
|
||||
lines_index = GPU_indexbuf_build(&elb_lines);
|
||||
}
|
||||
}
|
||||
|
||||
void create_index(const PBVH_GPU_Args &args)
|
||||
{
|
||||
switch (args.pbvh_type) {
|
||||
case PBVH_FACES:
|
||||
create_index_faces(args);
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
create_index_bmesh(args);
|
||||
break;
|
||||
case PBVH_GRIDS:
|
||||
create_index_grids(args, false);
|
||||
|
||||
if (args.ccg_key.level > coarse_level) {
|
||||
create_index_grids(args, true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for (PBVHBatch &batch : batches.values()) {
|
||||
if (tri_index) {
|
||||
GPU_batch_elembuf_set(batch.tris, tri_index, false);
|
||||
}
|
||||
else {
|
||||
/* Still flag the batch as dirty even if we're using the default index layout. */
|
||||
batch.tris->flag |= GPU_BATCH_DIRTY;
|
||||
}
|
||||
|
||||
if (lines_index) {
|
||||
GPU_batch_elembuf_set(batch.lines, lines_index, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PBVHBatch create_batch(const Span<AttributeRequest> requests,
|
||||
const PBVH_GPU_Args &args,
|
||||
bool do_coarse_grids)
|
||||
{
|
||||
if (!lines_index) {
|
||||
create_index(args);
|
||||
}
|
||||
|
||||
PBVHBatch batch;
|
||||
|
||||
batch.tris = GPU_batch_create(GPU_PRIM_TRIS,
|
||||
nullptr,
|
||||
/* can be nullptr if buffer is empty */
|
||||
do_coarse_grids ? tri_index_coarse : tri_index);
|
||||
batch.is_coarse = do_coarse_grids;
|
||||
|
||||
if (lines_index) {
|
||||
batch.lines = GPU_batch_create(
|
||||
GPU_PRIM_LINES, nullptr, do_coarse_grids ? lines_index_coarse : lines_index);
|
||||
GPU_batch_elembuf_set(batch.lines, lines_index, false);
|
||||
}
|
||||
|
||||
for (const AttributeRequest &request : requests) {
|
||||
if (!pbvh_attr_supported(request)) {
|
||||
continue;
|
||||
}
|
||||
const int i = this->ensure_vbo(request, args);
|
||||
batch.vbos.append(i);
|
||||
const PBVHVbo &vbo = this->vbos[i];
|
||||
|
||||
GPU_batch_vertbuf_add(batch.tris, vbo.vert_buf, false);
|
||||
if (batch.lines) {
|
||||
GPU_batch_vertbuf_add(batch.lines, vbo.vert_buf, false);
|
||||
}
|
||||
}
|
||||
|
||||
return batch;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static PBVHBatch create_batch(PBVHBatches &batches,
|
||||
const Span<AttributeRequest> requests,
|
||||
const PBVH_GPU_Args &args,
|
||||
bool do_coarse_grids)
|
||||
{
|
||||
batches.material_index = material_index_get(args);
|
||||
if (!batches.lines_index) {
|
||||
batches.create_index(args);
|
||||
}
|
||||
|
||||
PBVHBatch batch;
|
||||
|
||||
batch.tris = GPU_batch_create(GPU_PRIM_TRIS,
|
||||
nullptr,
|
||||
/* can be nullptr if buffer is empty */
|
||||
do_coarse_grids ? batches.tri_index_coarse : batches.tri_index);
|
||||
batch.is_coarse = do_coarse_grids;
|
||||
|
||||
if (batches.lines_index) {
|
||||
batch.lines = GPU_batch_create(GPU_PRIM_LINES,
|
||||
nullptr,
|
||||
do_coarse_grids ? batches.lines_index_coarse :
|
||||
batches.lines_index);
|
||||
}
|
||||
|
||||
for (const AttributeRequest &request : requests) {
|
||||
if (!pbvh_attr_supported(request)) {
|
||||
continue;
|
||||
}
|
||||
const int i = batches.ensure_vbo(request, args);
|
||||
batch.vbos.append(i);
|
||||
const PBVHVbo &vbo = batches.vbos[i];
|
||||
|
||||
GPU_batch_vertbuf_add(batch.tris, vbo.vert_buf, false);
|
||||
if (batch.lines) {
|
||||
GPU_batch_vertbuf_add(batch.lines, vbo.vert_buf, false);
|
||||
}
|
||||
}
|
||||
|
||||
return batch;
|
||||
}
|
||||
|
||||
void node_update(PBVHBatches *batches, const PBVH_GPU_Args &args)
|
||||
{
|
||||
@@ -1385,7 +1424,7 @@ void node_update(PBVHBatches *batches, const PBVH_GPU_Args &args)
|
||||
|
||||
void node_gpu_flush(PBVHBatches *batches)
|
||||
{
|
||||
batches->gpu_flush();
|
||||
gpu_flush(batches->vbos);
|
||||
}
|
||||
|
||||
PBVHBatches *node_create(const PBVH_GPU_Args &args)
|
||||
@@ -1405,7 +1444,7 @@ gpu::Batch *tris_get(PBVHBatches *batches,
|
||||
bool do_coarse_grids)
|
||||
{
|
||||
do_coarse_grids &= args.pbvh_type == PBVH_GRIDS;
|
||||
PBVHBatch &batch = batches->ensure_batch(attrs, args, do_coarse_grids);
|
||||
PBVHBatch &batch = ensure_batch(*batches, attrs, args, do_coarse_grids);
|
||||
return batch.tris;
|
||||
}
|
||||
|
||||
@@ -1415,7 +1454,7 @@ gpu::Batch *lines_get(PBVHBatches *batches,
|
||||
bool do_coarse_grids)
|
||||
{
|
||||
do_coarse_grids &= args.pbvh_type == PBVH_GRIDS;
|
||||
PBVHBatch &batch = batches->ensure_batch(attrs, args, do_coarse_grids);
|
||||
PBVHBatch &batch = ensure_batch(*batches, attrs, args, do_coarse_grids);
|
||||
return batch.lines;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user