Cleanup: Use FunctionRef for PBVH batch drawing
Also use const arguments, move a null check from the callback to the PBVH function, and reorganice the PBVH code to be in a consistent place in the file and to simplify the logic.
This commit is contained in:
@@ -294,15 +294,14 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
|
||||
void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
|
||||
void BKE_pbvh_get_frustum_planes(const PBVH *pbvh, PBVHFrustumPlanes *planes);
|
||||
|
||||
void BKE_pbvh_draw_cb(const Mesh &mesh,
|
||||
PBVH *pbvh,
|
||||
bool update_only_visible,
|
||||
PBVHFrustumPlanes *update_frustum,
|
||||
PBVHFrustumPlanes *draw_frustum,
|
||||
void (*draw_fn)(void *user_data,
|
||||
blender::draw::pbvh::PBVHBatches *batches,
|
||||
const blender::draw::pbvh::PBVH_GPU_Args &args),
|
||||
void *user_data);
|
||||
void BKE_pbvh_draw_cb(
|
||||
const Mesh &mesh,
|
||||
PBVH *pbvh,
|
||||
bool update_only_visible,
|
||||
const PBVHFrustumPlanes &update_frustum,
|
||||
const PBVHFrustumPlanes &draw_frustum,
|
||||
blender::FunctionRef<void(blender::draw::pbvh::PBVHBatches *batches,
|
||||
const blender::draw::pbvh::PBVH_GPU_Args &args)> draw_fn);
|
||||
|
||||
/* PBVH Access */
|
||||
|
||||
|
||||
@@ -1294,139 +1294,6 @@ bool BKE_pbvh_get_color_layer(Mesh *me, CustomDataLayer **r_layer, eAttrDomain *
|
||||
return *r_layer != nullptr;
|
||||
}
|
||||
|
||||
static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Mesh &mesh,
|
||||
PBVH &pbvh,
|
||||
const PBVHNode &node)
|
||||
{
|
||||
blender::draw::pbvh::PBVH_GPU_Args args{};
|
||||
|
||||
args.pbvh_type = pbvh.header.type;
|
||||
|
||||
args.face_sets_color_default = mesh.face_sets_color_default;
|
||||
args.face_sets_color_seed = mesh.face_sets_color_seed;
|
||||
|
||||
args.active_color = mesh.active_color_attribute;
|
||||
args.render_color = mesh.default_color_attribute;
|
||||
|
||||
switch (pbvh.header.type) {
|
||||
case PBVH_FACES:
|
||||
args.vert_data = &mesh.vert_data;
|
||||
args.loop_data = &mesh.loop_data;
|
||||
args.face_data = &mesh.face_data;
|
||||
args.me = pbvh.mesh;
|
||||
args.vert_positions = pbvh.vert_positions;
|
||||
args.corner_verts = mesh.corner_verts();
|
||||
args.corner_edges = mesh.corner_edges();
|
||||
args.mlooptri = pbvh.looptri;
|
||||
args.vert_normals = pbvh.vert_normals;
|
||||
args.face_normals = pbvh.face_normals;
|
||||
/* Retrieve data from the original mesh. Ideally that would be passed to this function to
|
||||
* make it clearer when each is used. */
|
||||
args.hide_poly = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&pbvh.mesh->face_data, CD_PROP_BOOL, ".hide_poly"));
|
||||
|
||||
args.prim_indices = node.prim_indices;
|
||||
args.looptri_faces = mesh.looptri_faces();
|
||||
break;
|
||||
case PBVH_GRIDS:
|
||||
args.vert_data = &pbvh.mesh->vert_data;
|
||||
args.loop_data = &pbvh.mesh->loop_data;
|
||||
args.face_data = &pbvh.mesh->face_data;
|
||||
args.ccg_key = pbvh.gridkey;
|
||||
args.me = pbvh.mesh;
|
||||
args.grid_indices = node.prim_indices;
|
||||
args.subdiv_ccg = pbvh.subdiv_ccg;
|
||||
args.grids = pbvh.subdiv_ccg->grids;
|
||||
args.vert_normals = pbvh.vert_normals;
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
args.bm = pbvh.header.bm;
|
||||
args.vert_data = &args.bm->vdata;
|
||||
args.loop_data = &args.bm->ldata;
|
||||
args.face_data = &args.bm->pdata;
|
||||
args.bm_faces = &node.bm_faces;
|
||||
args.cd_mask_layer = CustomData_get_offset_named(
|
||||
&pbvh.header.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
static void node_update_draw_buffers(const Mesh &mesh, PBVH &pbvh, PBVHNode &node)
|
||||
{
|
||||
/* Create and update draw buffers. The functions called here must not
|
||||
* do any OpenGL calls. Flags are not cleared immediately, that happens
|
||||
* after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */
|
||||
if (node.flag & PBVH_RebuildDrawBuffers) {
|
||||
const blender::draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, node);
|
||||
node.draw_batches = blender::draw::pbvh::node_create(args);
|
||||
}
|
||||
|
||||
if (node.flag & PBVH_UpdateDrawBuffers) {
|
||||
node.debug_draw_gen++;
|
||||
|
||||
if (node.draw_batches) {
|
||||
const blender::draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, node);
|
||||
blender::draw::pbvh::node_update(node.draw_batches, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pbvh_free_draw_buffers(PBVH & /*pbvh*/, PBVHNode *node)
|
||||
{
|
||||
if (node->draw_batches) {
|
||||
blender::draw::pbvh::node_free(node->draw_batches);
|
||||
node->draw_batches = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void pbvh_update_draw_buffers(const Mesh &mesh,
|
||||
PBVH &pbvh,
|
||||
Span<PBVHNode *> nodes,
|
||||
int update_flag)
|
||||
{
|
||||
using namespace blender;
|
||||
if (pbvh.header.type == PBVH_BMESH && !pbvh.header.bm) {
|
||||
/* BMesh hasn't been created yet */
|
||||
return;
|
||||
}
|
||||
|
||||
if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh.header.type, PBVH_GRIDS, PBVH_BMESH)) {
|
||||
/* Free buffers uses OpenGL, so not in parallel. */
|
||||
for (PBVHNode *node : nodes) {
|
||||
if (node->flag & PBVH_RebuildDrawBuffers) {
|
||||
pbvh_free_draw_buffers(pbvh, node);
|
||||
}
|
||||
else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_batches) {
|
||||
const draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, *node);
|
||||
draw::pbvh::update_pre(node->draw_batches, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parallel creation and update of draw buffers. */
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
node_update_draw_buffers(mesh, pbvh, *node);
|
||||
}
|
||||
});
|
||||
|
||||
/* Flush buffers uses OpenGL, so not in parallel. */
|
||||
for (PBVHNode *node : nodes) {
|
||||
if (node->flag & PBVH_UpdateDrawBuffers) {
|
||||
|
||||
if (node->draw_batches) {
|
||||
draw::pbvh::node_gpu_flush(node->draw_batches);
|
||||
}
|
||||
}
|
||||
|
||||
node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
|
||||
}
|
||||
}
|
||||
|
||||
static int pbvh_flush_bb(PBVH *pbvh, PBVHNode *node, int flag)
|
||||
{
|
||||
int update = 0;
|
||||
@@ -2796,74 +2663,186 @@ void BKE_pbvh_update_normals(PBVH *pbvh, SubdivCCG *subdiv_ccg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PBVH drawing, updating draw buffers as needed and culling any nodes outside
|
||||
* the specified frustum.
|
||||
*/
|
||||
struct PBVHDrawSearchData {
|
||||
PBVHFrustumPlanes *frustum;
|
||||
int accum_update_flag;
|
||||
};
|
||||
|
||||
static bool pbvh_draw_search(PBVHNode *node, PBVHDrawSearchData *data)
|
||||
static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Mesh &mesh,
|
||||
PBVH &pbvh,
|
||||
const PBVHNode &node)
|
||||
{
|
||||
if (data->frustum && !BKE_pbvh_node_frustum_contain_AABB(node, data->frustum)) {
|
||||
return false;
|
||||
blender::draw::pbvh::PBVH_GPU_Args args{};
|
||||
|
||||
args.pbvh_type = pbvh.header.type;
|
||||
|
||||
args.face_sets_color_default = mesh.face_sets_color_default;
|
||||
args.face_sets_color_seed = mesh.face_sets_color_seed;
|
||||
|
||||
args.active_color = mesh.active_color_attribute;
|
||||
args.render_color = mesh.default_color_attribute;
|
||||
|
||||
switch (pbvh.header.type) {
|
||||
case PBVH_FACES:
|
||||
args.vert_data = &mesh.vert_data;
|
||||
args.loop_data = &mesh.loop_data;
|
||||
args.face_data = &mesh.face_data;
|
||||
args.me = pbvh.mesh;
|
||||
args.vert_positions = pbvh.vert_positions;
|
||||
args.corner_verts = mesh.corner_verts();
|
||||
args.corner_edges = mesh.corner_edges();
|
||||
args.mlooptri = pbvh.looptri;
|
||||
args.vert_normals = pbvh.vert_normals;
|
||||
args.face_normals = pbvh.face_normals;
|
||||
/* Retrieve data from the original mesh. Ideally that would be passed to this function to
|
||||
* make it clearer when each is used. */
|
||||
args.hide_poly = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&pbvh.mesh->face_data, CD_PROP_BOOL, ".hide_poly"));
|
||||
|
||||
args.prim_indices = node.prim_indices;
|
||||
args.looptri_faces = mesh.looptri_faces();
|
||||
break;
|
||||
case PBVH_GRIDS:
|
||||
args.vert_data = &pbvh.mesh->vert_data;
|
||||
args.loop_data = &pbvh.mesh->loop_data;
|
||||
args.face_data = &pbvh.mesh->face_data;
|
||||
args.ccg_key = pbvh.gridkey;
|
||||
args.me = pbvh.mesh;
|
||||
args.grid_indices = node.prim_indices;
|
||||
args.subdiv_ccg = pbvh.subdiv_ccg;
|
||||
args.grids = pbvh.subdiv_ccg->grids;
|
||||
args.vert_normals = pbvh.vert_normals;
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
args.bm = pbvh.header.bm;
|
||||
args.vert_data = &args.bm->vdata;
|
||||
args.loop_data = &args.bm->ldata;
|
||||
args.face_data = &args.bm->pdata;
|
||||
args.bm_faces = &node.bm_faces;
|
||||
args.cd_mask_layer = CustomData_get_offset_named(
|
||||
&pbvh.header.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
data->accum_update_flag |= node->flag;
|
||||
return true;
|
||||
return args;
|
||||
}
|
||||
|
||||
void BKE_pbvh_draw_cb(const Mesh &mesh,
|
||||
PBVH *pbvh,
|
||||
bool update_only_visible,
|
||||
PBVHFrustumPlanes *update_frustum,
|
||||
PBVHFrustumPlanes *draw_frustum,
|
||||
void (*draw_fn)(void *user_data,
|
||||
blender::draw::pbvh::PBVHBatches *batches,
|
||||
const blender::draw::pbvh::PBVH_GPU_Args &args),
|
||||
void *user_data)
|
||||
static void node_update_draw_buffers(const Mesh &mesh, PBVH &pbvh, PBVHNode &node)
|
||||
{
|
||||
/* Create and update draw buffers. The functions called here must not
|
||||
* do any OpenGL calls. Flags are not cleared immediately, that happens
|
||||
* after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */
|
||||
if (node.flag & PBVH_RebuildDrawBuffers) {
|
||||
const blender::draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, node);
|
||||
node.draw_batches = blender::draw::pbvh::node_create(args);
|
||||
}
|
||||
|
||||
if (node.flag & PBVH_UpdateDrawBuffers) {
|
||||
node.debug_draw_gen++;
|
||||
|
||||
if (node.draw_batches) {
|
||||
const blender::draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, node);
|
||||
blender::draw::pbvh::node_update(node.draw_batches, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pbvh_free_draw_buffers(PBVH & /*pbvh*/, PBVHNode *node)
|
||||
{
|
||||
if (node->draw_batches) {
|
||||
blender::draw::pbvh::node_free(node->draw_batches);
|
||||
node->draw_batches = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void pbvh_update_draw_buffers(const Mesh &mesh,
|
||||
PBVH &pbvh,
|
||||
Span<PBVHNode *> nodes,
|
||||
int update_flag)
|
||||
{
|
||||
using namespace blender;
|
||||
if (pbvh.header.type == PBVH_BMESH && !pbvh.header.bm) {
|
||||
/* BMesh hasn't been created yet */
|
||||
return;
|
||||
}
|
||||
|
||||
if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh.header.type, PBVH_GRIDS, PBVH_BMESH)) {
|
||||
/* Free buffers uses OpenGL, so not in parallel. */
|
||||
for (PBVHNode *node : nodes) {
|
||||
if (node->flag & PBVH_RebuildDrawBuffers) {
|
||||
pbvh_free_draw_buffers(pbvh, node);
|
||||
}
|
||||
else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_batches) {
|
||||
const draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, pbvh, *node);
|
||||
draw::pbvh::update_pre(node->draw_batches, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parallel creation and update of draw buffers. */
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
node_update_draw_buffers(mesh, pbvh, *node);
|
||||
}
|
||||
});
|
||||
|
||||
/* Flush buffers uses OpenGL, so not in parallel. */
|
||||
for (PBVHNode *node : nodes) {
|
||||
if (node->flag & PBVH_UpdateDrawBuffers) {
|
||||
|
||||
if (node->draw_batches) {
|
||||
draw::pbvh::node_gpu_flush(node->draw_batches);
|
||||
}
|
||||
}
|
||||
|
||||
node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_pbvh_draw_cb(
|
||||
const Mesh &mesh,
|
||||
PBVH *pbvh,
|
||||
bool update_only_visible,
|
||||
const PBVHFrustumPlanes &update_frustum,
|
||||
const PBVHFrustumPlanes &draw_frustum,
|
||||
const blender::FunctionRef<void(blender::draw::pbvh::PBVHBatches *batches,
|
||||
const blender::draw::pbvh::PBVH_GPU_Args &args)> draw_fn)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke::pbvh;
|
||||
Vector<PBVHNode *> nodes;
|
||||
int update_flag = 0;
|
||||
|
||||
pbvh->draw_cache_invalid = false;
|
||||
|
||||
/* Search for nodes that need updates. */
|
||||
if (update_only_visible) {
|
||||
/* Get visible nodes with draw updates. */
|
||||
PBVHDrawSearchData data{};
|
||||
data.frustum = update_frustum;
|
||||
data.accum_update_flag = 0;
|
||||
nodes = search_gather(pbvh, [&](PBVHNode &node) { return pbvh_draw_search(&node, &data); });
|
||||
update_flag = data.accum_update_flag;
|
||||
int update_flag = 0;
|
||||
Vector<PBVHNode *> nodes = search_gather(pbvh, [&](PBVHNode &node) {
|
||||
if (!BKE_pbvh_node_frustum_contain_AABB(&node, &update_frustum)) {
|
||||
return false;
|
||||
}
|
||||
update_flag |= node.flag;
|
||||
return true;
|
||||
});
|
||||
if (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers)) {
|
||||
pbvh_update_draw_buffers(mesh, *pbvh, nodes, update_flag);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Get all nodes with draw updates, also those outside the view. */
|
||||
const int search_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
|
||||
nodes = search_gather(pbvh, [&](PBVHNode &node) { return update_search(&node, search_flag); });
|
||||
update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
|
||||
}
|
||||
|
||||
/* Update draw buffers. */
|
||||
if (!nodes.is_empty() && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) {
|
||||
pbvh_update_draw_buffers(mesh, *pbvh, nodes, update_flag);
|
||||
Vector<PBVHNode *> nodes = search_gather(pbvh, [&](PBVHNode &node) {
|
||||
return update_search(&node, PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
|
||||
});
|
||||
pbvh_update_draw_buffers(mesh, *pbvh, nodes, PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
|
||||
}
|
||||
|
||||
/* Draw visible nodes. */
|
||||
PBVHDrawSearchData draw_data{};
|
||||
draw_data.frustum = draw_frustum;
|
||||
draw_data.accum_update_flag = 0;
|
||||
nodes = search_gather(pbvh, [&](PBVHNode &node) { return pbvh_draw_search(&node, &draw_data); });
|
||||
Vector<PBVHNode *> nodes = search_gather(pbvh, [&](PBVHNode &node) {
|
||||
return BKE_pbvh_node_frustum_contain_AABB(&node, &draw_frustum);
|
||||
});
|
||||
|
||||
for (PBVHNode *node : nodes) {
|
||||
if (!(node->flag & PBVH_FullyHidden)) {
|
||||
const draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, *pbvh, *node);
|
||||
draw_fn(user_data, node->draw_batches, args);
|
||||
if (node->flag & PBVH_FullyHidden) {
|
||||
continue;
|
||||
}
|
||||
if (!node->draw_batches) {
|
||||
continue;
|
||||
}
|
||||
const draw::pbvh::PBVH_GPU_Args args = pbvh_draw_args_init(mesh, *pbvh, *node);
|
||||
draw_fn(node->draw_batches, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1234,10 +1234,6 @@ static void sculpt_draw_cb(DRWSculptCallbackData *scd,
|
||||
const blender::draw::pbvh::PBVH_GPU_Args &pbvh_draw_args)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
if (!batches) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUBatch *geom;
|
||||
|
||||
if (!scd->use_wire) {
|
||||
@@ -1369,15 +1365,14 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
|
||||
Mesh *mesh = static_cast<Mesh *>(scd->ob->data);
|
||||
BKE_pbvh_update_normals(pbvh, mesh->runtime->subdiv_ccg.get());
|
||||
|
||||
BKE_pbvh_draw_cb(*mesh,
|
||||
pbvh,
|
||||
update_only_visible,
|
||||
&update_frustum,
|
||||
&draw_frustum,
|
||||
(void (*)(void *,
|
||||
blender::draw::pbvh::PBVHBatches *,
|
||||
const blender::draw::pbvh::PBVH_GPU_Args &))sculpt_draw_cb,
|
||||
scd);
|
||||
BKE_pbvh_draw_cb(
|
||||
*mesh,
|
||||
pbvh,
|
||||
update_only_visible,
|
||||
update_frustum,
|
||||
draw_frustum,
|
||||
[&](blender::draw::pbvh::PBVHBatches *batches,
|
||||
const blender::draw::pbvh::PBVH_GPU_Args &args) { sculpt_draw_cb(scd, batches, args); });
|
||||
|
||||
if (SCULPT_DEBUG_BUFFERS) {
|
||||
int debug_node_nr = 0;
|
||||
|
||||
@@ -37,40 +37,8 @@ float3 SculptBatch::debug_color()
|
||||
return colors[debug_index % 9];
|
||||
}
|
||||
|
||||
struct SculptCallbackData {
|
||||
bool use_wire;
|
||||
bool fast_mode;
|
||||
|
||||
Span<pbvh::AttributeRequest> attrs;
|
||||
|
||||
Vector<SculptBatch> batches;
|
||||
};
|
||||
|
||||
static void sculpt_draw_cb(SculptCallbackData *data,
|
||||
pbvh::PBVHBatches *batches,
|
||||
const pbvh::PBVH_GPU_Args &pbvh_draw_args)
|
||||
{
|
||||
if (!batches) {
|
||||
return;
|
||||
}
|
||||
|
||||
SculptBatch batch = {};
|
||||
|
||||
if (data->use_wire) {
|
||||
batch.batch = pbvh::lines_get(batches, data->attrs, pbvh_draw_args, data->fast_mode);
|
||||
}
|
||||
else {
|
||||
batch.batch = pbvh::tris_get(batches, data->attrs, pbvh_draw_args, data->fast_mode);
|
||||
}
|
||||
|
||||
batch.material_slot = pbvh::material_index_get(batches);
|
||||
batch.debug_index = data->batches.size();
|
||||
|
||||
data->batches.append(batch);
|
||||
}
|
||||
|
||||
static Vector<SculptBatch> sculpt_batches_get_ex(const Object *ob,
|
||||
bool use_wire,
|
||||
const bool use_wire,
|
||||
const Span<pbvh::AttributeRequest> attrs)
|
||||
{
|
||||
/* PBVH should always exist for non-empty meshes, created by depsgraph eval. */
|
||||
@@ -131,21 +99,25 @@ static Vector<SculptBatch> sculpt_batches_get_ex(const Object *ob,
|
||||
const Mesh *mesh = static_cast<const Mesh *>(ob->data);
|
||||
BKE_pbvh_update_normals(pbvh, mesh->runtime->subdiv_ccg.get());
|
||||
|
||||
SculptCallbackData data;
|
||||
data.use_wire = use_wire;
|
||||
data.fast_mode = fast_mode;
|
||||
data.attrs = attrs;
|
||||
|
||||
BKE_pbvh_draw_cb(
|
||||
*mesh,
|
||||
pbvh,
|
||||
update_only_visible,
|
||||
&update_frustum,
|
||||
&draw_frustum,
|
||||
(void (*)(void *, pbvh::PBVHBatches *, const pbvh::PBVH_GPU_Args &))sculpt_draw_cb,
|
||||
&data);
|
||||
|
||||
return data.batches;
|
||||
Vector<SculptBatch> result_batches;
|
||||
BKE_pbvh_draw_cb(*mesh,
|
||||
pbvh,
|
||||
update_only_visible,
|
||||
update_frustum,
|
||||
draw_frustum,
|
||||
[&](pbvh::PBVHBatches *batches, const pbvh::PBVH_GPU_Args &args) {
|
||||
SculptBatch batch{};
|
||||
if (use_wire) {
|
||||
batch.batch = pbvh::lines_get(batches, attrs, args, fast_mode);
|
||||
}
|
||||
else {
|
||||
batch.batch = pbvh::tris_get(batches, attrs, args, fast_mode);
|
||||
}
|
||||
batch.material_slot = pbvh::material_index_get(batches);
|
||||
batch.debug_index = result_batches.size();
|
||||
result_batches.append(batch);
|
||||
});
|
||||
return result_batches;
|
||||
}
|
||||
|
||||
Vector<SculptBatch> sculpt_batches_get(const Object *ob, SculptBatchFeature features)
|
||||
|
||||
Reference in New Issue
Block a user