Sculpt: Split BVH nodes structs by geometry type

In order to make per-BVH-node overhead smaller and also to improve
type safety and code clarity, split the `pbvh::Node` struct into four classes:
a base class, and a class for each sculpt geometry type.

The size of a mesh BVH node changes from 408 to 176 bytes. For multires
the nodes are smaller at 96 bytes. This gives us leeway to make nodes smaller
to benefit more from spacial locality, etc. It also just reduces memory usage.

Using a `std::variant` makes the change quite simple actually. For the few
places that actually need to process the node types separately given their
different types, we use `std::visit`. Elsewhere we use `IndexMask` to retrieve
selections of nodes from the vector instead, though most code will be
refactored to that pattern separately. The new function `search_nodes`
is the equivalent of the existing `gather_nodes` that returns an `IndexMask`
instead of a vector of node pointers.

Part of #118145.

Pull Request: https://projects.blender.org/blender/blender/pulls/126873
This commit is contained in:
Hans Goudey
2024-08-28 15:18:21 +02:00
committed by Hans Goudey
parent 84bab7f300
commit 52bf292349
15 changed files with 681 additions and 473 deletions

View File

@@ -11,6 +11,7 @@
#include <optional>
#include <string>
#include <variant>
#include "BLI_array.hh"
#include "BLI_bit_group_vector.hh"
@@ -85,16 +86,24 @@ class Node {
* 'nodes' array. */
int children_offset_ = 0;
/* List of primitives for this node. Semantics depends on
* blender::bke::pbvh::Tree type:
*
* - Type::Mesh: Indices into the #blender::bke::pbvh::Tree::corner_tris array.
* - Type::Grids: Multires grid indices.
* - Type::BMesh: Unused. See Node.bm_faces.
*
* NOTE: This is a pointer inside of blender::bke::pbvh::Tree.prim_indices; it
* is not allocated separately per node.
/* Indicates whether this node is a leaf or not; also used for
* marking various updates that need to be applied. */
PBVHNodeFlags flag_ = PBVH_UpdateBB | PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers |
PBVH_UpdateRedraw;
/* Used for ray-casting: how close the bounding-box is to the ray point. */
float tmin_ = 0.0f;
/* Used to flash colors of updated node bounding boxes in
* debug draw mode (when G.debug_value / bpy.app.debug_value is 889).
*/
int debug_draw_gen_ = 0;
pixels::NodeData *pixels_ = nullptr;
};
struct MeshNode : public Node {
/** Indices into the #Mesh::corner_tris() array. Refers to a subset of Tree::prim_indices_. */
Span<int> prim_indices_;
/* Array of indices into the mesh's vertex array. Contains the
@@ -114,15 +123,13 @@ class Node {
* they appear in another node's vert_indices array, they will
* be above that node's 'uniq_verts' value.
*
* Used for leaf nodes in a mesh-based blender::bke::pbvh::Tree (not multires.)
* Used for leaf nodes.
*/
Array<int, 0> vert_indices_;
/** The number of vertices in #vert_indices not shared with (owned by) another node. */
int unique_verts_num_ = 0;
/* Array of indices into the Mesh's corner array.
* Type::Mesh only.
*/
/** Array of indices into the Mesh's corner array. */
Array<int, 0> corner_indices_;
/* An array mapping face corners into the vert_indices
@@ -131,20 +138,17 @@ class Node {
* array, in the same order as the corners in the original
* triangle.
*
* Used for leaf nodes in a mesh-based blender::bke::pbvh::Tree (not multires.)
* Used for leaf nodes.
*/
Array<int3, 0> face_vert_indices_;
};
/* Indicates whether this node is a leaf or not; also used for
* marking various updates that need to be applied. */
PBVHNodeFlags flag_ = PBVH_UpdateBB | PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers |
PBVH_UpdateRedraw;
/* Used for ray-casting: how close the bounding-box is to the ray point. */
float tmin_ = 0.0f;
/* Dyntopo */
struct GridsNode : public Node {
/** Multires grid indices for this node. Refers to a subset of Tree::prim_indices_. */
Span<int> prim_indices_;
};
struct BMeshNode : public Node {
/* Set of pointers to the BMFaces used by this node.
* NOTE: Type::BMesh only. Faces are always triangles
* (dynamic topology forcibly triangulates the mesh).
@@ -158,13 +162,6 @@ class Node {
int (*bm_ortri_)[3] = nullptr;
BMVert **bm_orvert_ = nullptr;
int bm_tot_ortri_ = 0;
pixels::NodeData *pixels_ = nullptr;
/* Used to flash colors of updated node bounding boxes in
* debug draw mode (when G.debug_value / bpy.app.debug_value is 889).
*/
int debug_draw_gen_ = 0;
};
/**
@@ -176,7 +173,7 @@ class Tree {
Type type_;
public:
Vector<Node> nodes_;
std::variant<Vector<MeshNode>, Vector<GridsNode>, Vector<BMeshNode>> nodes_;
/* Memory backing for Node.prim_indices. */
Array<int> prim_indices_;
@@ -187,9 +184,12 @@ class Tree {
pixels::PBVHData *pixels_ = nullptr;
public:
Tree(const Type type) : type_(type) {}
Tree(Type type);
~Tree();
template<typename NodeT> Span<NodeT> nodes() const;
template<typename NodeT> MutableSpan<NodeT> nodes();
Type type() const
{
return this->type_;
@@ -267,7 +267,7 @@ bool raycast_node(Tree &pbvh,
int *active_face_grid_index,
float *face_normal);
bool bmesh_node_raycast_detail(Node &node,
bool bmesh_node_raycast_detail(BMeshNode &node,
const float ray_start[3],
IsectRayPrecalc *isect_precalc,
float *depth,
@@ -389,18 +389,18 @@ void BKE_pbvh_mark_rebuild_pixels(blender::bke::pbvh::Tree &pbvh);
namespace blender::bke::pbvh {
Span<int> node_grid_indices(const Node &node);
Span<int> node_grid_indices(const GridsNode &node);
Span<int> node_verts(const Node &node);
Span<int> node_unique_verts(const Node &node);
Span<int> node_corners(const Node &node);
Span<int> node_verts(const MeshNode &node);
Span<int> node_unique_verts(const MeshNode &node);
Span<int> node_corners(const MeshNode &node);
/**
* Gather the indices of all faces (not triangles) used by the node.
* For convenience, pass a reference to the data in the result.
*/
Span<int> node_face_indices_calc_mesh(Span<int> corner_tri_faces,
const Node &node,
const MeshNode &node,
Vector<int> &faces);
/**
@@ -408,7 +408,7 @@ Span<int> node_face_indices_calc_mesh(Span<int> corner_tri_faces,
* For convenience, pass a reference to the data in the result.
*/
Span<int> node_face_indices_calc_grids(const SubdivCCG &subdiv_ccg,
const Node &node,
const GridsNode &node,
Vector<int> &faces);
Bounds<float3> node_bounds(const Node &node);
@@ -431,9 +431,11 @@ bool BKE_pbvh_node_frustum_contain_AABB(const blender::bke::pbvh::Node *node,
bool BKE_pbvh_node_frustum_exclude_AABB(const blender::bke::pbvh::Node *node,
const PBVHFrustumPlanes *frustum);
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::Node *node);
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_other_verts(blender::bke::pbvh::Node *node);
const blender::Set<BMFace *, 0> &BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::Node *node);
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_unique_verts(
blender::bke::pbvh::BMeshNode *node);
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_other_verts(
blender::bke::pbvh::BMeshNode *node);
const blender::Set<BMFace *, 0> &BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::BMeshNode *node);
/**
* In order to perform operations on the original node coordinates
@@ -443,7 +445,7 @@ const blender::Set<BMFace *, 0> &BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::N
*/
void BKE_pbvh_bmesh_node_save_orig(BMesh *bm,
BMLog *log,
blender::bke::pbvh::Node *node,
blender::bke::pbvh::BMeshNode *node,
bool use_original);
void BKE_pbvh_bmesh_after_stroke(BMesh &bm, blender::bke::pbvh::Tree &pbvh);
@@ -477,14 +479,15 @@ void update_normals_from_eval(Object &object_eval, Tree &pbvh);
blender::Bounds<blender::float3> BKE_pbvh_redraw_BB(blender::bke::pbvh::Tree &pbvh);
namespace blender::bke::pbvh {
IndexMask nodes_to_face_selection_grids(const SubdivCCG &subdiv_ccg,
Span<const Node *> nodes,
Span<GridsNode> nodes,
const IndexMask &nodes_mask,
IndexMaskMemory &memory);
}
void BKE_pbvh_vert_coords_apply(blender::bke::pbvh::Tree &pbvh,
blender::Span<blender::float3> vert_positions);
void BKE_pbvh_node_get_bm_orco_data(blender::bke::pbvh::Node *node,
void BKE_pbvh_node_get_bm_orco_data(blender::bke::pbvh::BMeshNode *node,
int (**r_orco_tris)[3],
int *r_orco_tris_num,
float (**r_orco_coords)[3],
@@ -526,20 +529,56 @@ namespace blender::bke::pbvh {
/** Return pointers to all the leaf nodes in the BVH tree. */
Vector<Node *> all_leaf_nodes(Tree &pbvh);
/** Create a selection of nodes that match the filter function. */
IndexMask search_nodes(const Tree &pbvh,
IndexMaskMemory &memory,
FunctionRef<bool(const Node &)> filter_fn);
Vector<Node *> search_gather(Tree &pbvh,
FunctionRef<bool(Node &)> scb,
PBVHNodeFlags leaf_flag = PBVH_Leaf);
void node_update_mask_mesh(Span<float> mask, Node &node);
void node_update_mask_grids(const CCGKey &key, Span<CCGElem *> grids, Node &node);
void node_update_mask_bmesh(int mask_offset, Node &node);
void node_update_mask_mesh(Span<float> mask, MeshNode &node);
void node_update_mask_grids(const CCGKey &key, Span<CCGElem *> grids, GridsNode &node);
void node_update_mask_bmesh(int mask_offset, BMeshNode &node);
void node_update_visibility_mesh(Span<bool> hide_vert, Node &node);
void node_update_visibility_grids(const BitGroupVector<> &grid_hidden, Node &node);
void node_update_visibility_bmesh(Node &node);
void node_update_visibility_mesh(Span<bool> hide_vert, MeshNode &node);
void node_update_visibility_grids(const BitGroupVector<> &grid_hidden, GridsNode &node);
void node_update_visibility_bmesh(BMeshNode &node);
void update_node_bounds_mesh(Span<float3> positions, Node &node);
void update_node_bounds_grids(const CCGKey &key, Span<CCGElem *> grids, Node &node);
void update_node_bounds_bmesh(Node &node);
void update_node_bounds_mesh(Span<float3> positions, MeshNode &node);
void update_node_bounds_grids(const CCGKey &key, Span<CCGElem *> grids, GridsNode &node);
void update_node_bounds_bmesh(BMeshNode &node);
} // namespace blender::bke::pbvh
/* TODO: Temporary inline definitions with generic #Node type signature. To be removed as
* refactoring changes code to use explicit node types. */
namespace blender::bke::pbvh {
inline Span<int> node_grid_indices(const Node &node)
{
return node_grid_indices(static_cast<const GridsNode &>(node));
}
inline Span<int> node_verts(const Node &node)
{
return node_verts(static_cast<const MeshNode &>(node));
}
inline Span<int> node_unique_verts(const Node &node)
{
return node_unique_verts(static_cast<const MeshNode &>(node));
}
} // namespace blender::bke::pbvh
inline const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_unique_verts(
blender::bke::pbvh::Node *node)
{
return BKE_pbvh_bmesh_node_unique_verts(static_cast<blender::bke::pbvh::BMeshNode *>(node));
}
inline const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_other_verts(
blender::bke::pbvh::Node *node)
{
return BKE_pbvh_bmesh_node_other_verts(static_cast<blender::bke::pbvh::BMeshNode *>(node));
}
inline const blender::Set<BMFace *, 0> &BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::Node *node)
{
return BKE_pbvh_bmesh_node_faces(static_cast<blender::bke::pbvh::BMeshNode *>(node));
}

View File

@@ -170,7 +170,7 @@ static int map_insert_vert(Map<int, int> &map,
static void build_mesh_leaf_node(const Span<int> corner_verts,
const Span<int3> corner_tris,
MutableSpan<bool> vert_bitmap,
Node &node)
MeshNode &node)
{
node.unique_verts_num_ = 0;
int shared_verts = 0;
@@ -251,7 +251,7 @@ static void build_nodes_recursive_mesh(const Span<int> corner_verts,
MutableSpan<int> prim_scratch,
const int depth,
MutableSpan<int> prim_indices,
Vector<Node> &nodes)
Vector<MeshNode> &nodes)
{
int end;
@@ -261,7 +261,7 @@ static void build_nodes_recursive_mesh(const Span<int> corner_verts,
if (!leaf_needs_material_split(
prim_indices, tri_faces, material_indices, sharp_faces, prim_offset, prims_num))
{
Node &node = nodes[node_index];
MeshNode &node = nodes[node_index];
node.flag_ |= PBVH_Leaf;
node.prim_indices_ = prim_indices.as_span().slice(prim_offset, prims_num);
build_mesh_leaf_node(corner_verts, corner_tris, vert_bitmap, node);
@@ -387,7 +387,8 @@ std::unique_ptr<Tree> build_mesh(Mesh *mesh)
pbvh->prim_indices_.reinitialize(corner_tris.size());
array_utils::fill_index_range<int>(pbvh->prim_indices_);
pbvh->nodes_.resize(1);
Vector<MeshNode> &nodes = std::get<Vector<MeshNode>>(pbvh->nodes_);
nodes.resize(1);
build_nodes_recursive_mesh(corner_verts,
corner_tris,
tri_faces,
@@ -403,13 +404,13 @@ std::unique_ptr<Tree> build_mesh(Mesh *mesh)
Array<int>(pbvh->prim_indices_.size()),
0,
pbvh->prim_indices_,
pbvh->nodes_);
nodes);
update_bounds_mesh(vert_positions, *pbvh);
store_bounds_orig(*pbvh);
if (!hide_vert.is_empty()) {
MutableSpan<Node> nodes = pbvh->nodes_;
MutableSpan<MeshNode> nodes = nodes;
threading::parallel_for(nodes.index_range(), 8, [&](const IndexRange range) {
for (const int i : range) {
const Span<int> verts = node_verts(nodes[i]);
@@ -435,7 +436,7 @@ static void build_nodes_recursive_grids(const Span<int> grid_to_face_map,
MutableSpan<int> prim_scratch,
const int depth,
MutableSpan<int> prim_indices,
Vector<Node> &nodes)
Vector<GridsNode> &nodes)
{
int end;
@@ -445,7 +446,7 @@ static void build_nodes_recursive_grids(const Span<int> grid_to_face_map,
if (!leaf_needs_material_split(
prim_indices, grid_to_face_map, material_indices, sharp_faces, prim_offset, prims_num))
{
Node &node = nodes[node_index];
GridsNode &node = nodes[node_index];
node.flag_ |= PBVH_Leaf;
node.prim_indices_ = prim_indices.as_span().slice(prim_offset, prims_num);
return;
@@ -571,7 +572,8 @@ std::unique_ptr<Tree> build_grids(Mesh *mesh, SubdivCCG *subdiv_ccg)
pbvh->prim_indices_.reinitialize(elems.size());
array_utils::fill_index_range<int>(pbvh->prim_indices_);
pbvh->nodes_.resize(1);
Vector<GridsNode> &nodes = std::get<Vector<GridsNode>>(pbvh->nodes_);
nodes.resize(1);
build_nodes_recursive_grids(subdiv_ccg->grid_to_face_map,
material_index,
sharp_face,
@@ -584,14 +586,14 @@ std::unique_ptr<Tree> build_grids(Mesh *mesh, SubdivCCG *subdiv_ccg)
Array<int>(pbvh->prim_indices_.size()),
0,
pbvh->prim_indices_,
pbvh->nodes_);
nodes);
update_bounds_grids(key, elems, *pbvh);
store_bounds_orig(*pbvh);
const BitGroupVector<> &grid_hidden = subdiv_ccg->grid_hidden;
if (!grid_hidden.is_empty()) {
MutableSpan<Node> nodes = pbvh->nodes_;
MutableSpan<GridsNode> nodes = nodes;
threading::parallel_for(nodes.index_range(), 8, [&](const IndexRange range) {
for (const int i : range) {
const Span<int> grids = node_grid_indices(nodes[i]);
@@ -608,23 +610,78 @@ std::unique_ptr<Tree> build_grids(Mesh *mesh, SubdivCCG *subdiv_ccg)
return pbvh;
}
Tree::Tree(const Type type) : type_(type)
{
switch (type) {
case bke::pbvh::Type::Mesh:
nodes_ = Vector<MeshNode>();
break;
case bke::pbvh::Type::Grids:
nodes_ = Vector<GridsNode>();
break;
case bke::pbvh::Type::BMesh:
nodes_ = Vector<BMeshNode>();
break;
}
}
template<> Span<MeshNode> Tree::nodes() const
{
return std::get<Vector<MeshNode>>(this->nodes_);
}
template<> Span<GridsNode> Tree::nodes() const
{
return std::get<Vector<GridsNode>>(this->nodes_);
}
template<> Span<BMeshNode> Tree::nodes() const
{
return std::get<Vector<BMeshNode>>(this->nodes_);
}
template<> MutableSpan<MeshNode> Tree::nodes()
{
return std::get<Vector<MeshNode>>(this->nodes_);
}
template<> MutableSpan<GridsNode> Tree::nodes()
{
return std::get<Vector<GridsNode>>(this->nodes_);
}
template<> MutableSpan<BMeshNode> Tree::nodes()
{
return std::get<Vector<BMeshNode>>(this->nodes_);
}
Tree::~Tree()
{
for (Node &node : this->nodes_) {
if (node.flag_ & PBVH_Leaf) {
if (node.draw_batches_) {
blender::draw::pbvh::node_free(node.draw_batches_);
}
}
std::visit(
[](auto &nodes) {
for (Node &node : nodes) {
if (node.flag_ & PBVH_Leaf) {
if (node.draw_batches_) {
blender::draw::pbvh::node_free(node.draw_batches_);
}
}
if (node.flag_ & (PBVH_Leaf | PBVH_TexLeaf)) {
node_pixels_free(&node);
}
}
if (node.flag_ & (PBVH_Leaf | PBVH_TexLeaf)) {
node_pixels_free(&node);
}
}
},
this->nodes_);
pixels_free(this);
}
static bool tree_is_empty(const Tree &pbvh)
{
return std::visit([](const auto &nodes) { return nodes.is_empty(); }, pbvh.nodes_);
}
static Node &first_node(Tree &pbvh)
{
BLI_assert(!tree_is_empty(pbvh));
return std::visit([](auto &nodes) -> Node & { return nodes.first(); }, pbvh.nodes_);
}
void free(std::unique_ptr<Tree> &pbvh)
{
pbvh.reset();
@@ -646,7 +703,7 @@ static void pbvh_iter_begin(PBVHIter *iter, Tree &pbvh, FunctionRef<bool(Node &)
{
iter->pbvh = &pbvh;
iter->scb = scb;
iter->stack.push({&pbvh.nodes_.first(), false});
iter->stack.push({&first_node(pbvh), false});
}
static Node *pbvh_iter_next(PBVHIter *iter, PBVHNodeFlags leaf_flag)
@@ -683,8 +740,12 @@ static Node *pbvh_iter_next(PBVHIter *iter, PBVHNodeFlags leaf_flag)
iter->stack.push({node, true});
/* push two child nodes on the stack */
iter->stack.push({&iter->pbvh->nodes_[node->children_offset_ + 1], false});
iter->stack.push({&iter->pbvh->nodes_[node->children_offset_], false});
std::visit(
[&](auto &nodes) {
iter->stack.push({&nodes[node->children_offset_ + 1], false});
iter->stack.push({&nodes[node->children_offset_], false});
},
iter->pbvh->nodes_);
}
return nullptr;
@@ -711,8 +772,12 @@ static Node *pbvh_iter_next_occluded(PBVHIter *iter)
return node;
}
iter->stack.push({&iter->pbvh->nodes_[node->children_offset_ + 1], false});
iter->stack.push({&iter->pbvh->nodes_[node->children_offset_], false});
std::visit(
[&](auto &nodes) {
iter->stack.push({&nodes[node->children_offset_ + 1], false});
iter->stack.push({&nodes[node->children_offset_], false});
},
iter->pbvh->nodes_);
}
return nullptr;
@@ -788,7 +853,7 @@ static void search_callback_occluded(Tree &pbvh,
const FunctionRef<bool(Node &)> scb,
const FunctionRef<void(Node &node, float *tmin)> hit_fn)
{
if (pbvh.nodes_.is_empty()) {
if (tree_is_empty(pbvh)) {
return;
}
PBVHIter iter;
@@ -822,10 +887,10 @@ static void search_callback_occluded(Tree &pbvh,
}
}
static bool update_search(Node *node, const int flag)
static bool update_search(const Node &node, const int flag)
{
if (node->flag_ & PBVH_Leaf) {
return (node->flag_ & flag) != 0;
if (node.flag_ & PBVH_Leaf) {
return (node.flag_ & flag) != 0;
}
return true;
@@ -930,19 +995,20 @@ static void calc_node_face_normals(const Span<float3> positions,
const OffsetIndices<int> faces,
const Span<int> corner_verts,
const Span<int> corner_tri_faces,
const Span<const Node *> nodes,
const Span<MeshNode> nodes,
const IndexMask &nodes_to_update,
MutableSpan<float3> face_normals)
{
threading::EnumerableThreadSpecific<Vector<int>> all_index_data;
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
threading::parallel_for(nodes_to_update.index_range(), 1, [&](const IndexRange range) {
Vector<int> &node_faces = all_index_data.local();
for (const Node *node : nodes.slice(range)) {
nodes_to_update.slice(range).foreach_index([&](const int i) {
normals_calc_faces(positions,
faces,
corner_verts,
node_face_indices_calc_mesh(corner_tri_faces, *node, node_faces),
node_face_indices_calc_mesh(corner_tri_faces, nodes[i], node_faces),
face_normals);
}
});
});
}
@@ -972,18 +1038,20 @@ static void calc_boundary_vert_normals(const GroupedSpan<int> vert_to_face_map,
static void calc_node_vert_normals(const GroupedSpan<int> vert_to_face_map,
const Span<float3> face_normals,
const Span<Node *> nodes,
const Span<MeshNode> nodes,
const IndexMask &nodes_to_update,
MutableSpan<float3> vert_normals)
{
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (const Node *node : nodes.slice(range)) {
normals_calc_verts_simple(
vert_to_face_map, face_normals, node_unique_verts(*node), vert_normals);
}
nodes_to_update.foreach_index(GrainSize(1), [&](const int i) {
normals_calc_verts_simple(
vert_to_face_map, face_normals, node_unique_verts(nodes[i]), vert_normals);
});
}
static void update_normals_mesh(Object &object_orig, Object &object_eval, Span<Node *> nodes)
static void update_normals_mesh(Object &object_orig,
Object &object_eval,
const Span<MeshNode> nodes,
const IndexMask &nodes_to_update)
{
/* Position changes are tracked on a per-node level, so all the vertex and face normals for every
* affected node are recalculated. However, the additional complexity comes from the fact that
@@ -1010,11 +1078,12 @@ static void update_normals_mesh(Object &object_orig, Object &object_eval, Span<N
object_eval);
VectorSet<int> boundary_faces;
for (const Node *node : nodes) {
for (const int vert : node->vert_indices_.as_span().drop_front(node->unique_verts_num_)) {
nodes_to_update.foreach_index([&](const int i) {
const MeshNode &node = nodes[i];
for (const int vert : node.vert_indices_.as_span().drop_front(node.unique_verts_num_)) {
boundary_faces.add_multiple(vert_to_face_map[vert]);
}
}
});
VectorSet<int> boundary_verts;
@@ -1028,7 +1097,8 @@ static void update_normals_mesh(Object &object_orig, Object &object_eval, Span<N
}
else {
face_normals_cache.update([&](Vector<float3> &r_data) {
calc_node_face_normals(positions, faces, corner_verts, tri_faces, nodes, r_data);
calc_node_face_normals(
positions, faces, corner_verts, tri_faces, nodes, nodes_to_update, r_data);
calc_boundary_face_normals(positions, faces, corner_verts, boundary_faces, r_data);
});
}
@@ -1051,45 +1121,38 @@ static void update_normals_mesh(Object &object_orig, Object &object_eval, Span<N
}
else {
vert_normals_cache.update([&](Vector<float3> &r_data) {
calc_node_vert_normals(vert_to_face_map, face_normals, nodes, r_data);
calc_node_vert_normals(vert_to_face_map, face_normals, nodes, nodes_to_update, r_data);
calc_boundary_vert_normals(vert_to_face_map, face_normals, boundary_verts, r_data);
});
}
for (Node *node : nodes) {
node->flag_ &= ~PBVH_UpdateNormals;
}
}
static void update_normals(Object &object_orig, Object &object_eval, Tree &pbvh)
{
Vector<Node *> nodes = search_gather(
pbvh, [&](Node &node) { return update_search(&node, PBVH_UpdateNormals); });
IndexMaskMemory memory;
const IndexMask nodes_to_update = search_nodes(
pbvh, memory, [&](const Node &node) { return update_search(node, PBVH_UpdateNormals); });
switch (pbvh.type()) {
case Type::Mesh: {
update_normals_mesh(object_orig, object_eval, nodes);
update_normals_mesh(object_orig, object_eval, pbvh.nodes<MeshNode>(), nodes_to_update);
MutableSpan<MeshNode> nodes = pbvh.nodes<MeshNode>();
nodes_to_update.foreach_index([&](const int i) { nodes[i].flag_ &= ~PBVH_UpdateNormals; });
break;
}
case Type::Grids: {
if (nodes.is_empty()) {
return;
}
SculptSession &ss = *object_orig.sculpt;
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
MutableSpan<GridsNode> nodes = pbvh.nodes<GridsNode>();
IndexMaskMemory memory;
const IndexMask faces_to_update = nodes_to_face_selection_grids(subdiv_ccg, nodes, memory);
const IndexMask faces_to_update = nodes_to_face_selection_grids(
subdiv_ccg, nodes, nodes_to_update, memory);
BKE_subdiv_ccg_update_normals(subdiv_ccg, faces_to_update);
for (Node *node : nodes) {
node->flag_ &= ~PBVH_UpdateNormals;
}
nodes_to_update.foreach_index([&](const int i) { nodes[i].flag_ &= ~PBVH_UpdateNormals; });
break;
}
case Type::BMesh: {
if (nodes.is_empty()) {
return;
}
bmesh_normals_update(nodes);
bmesh_normals_update(pbvh, nodes_to_update);
break;
}
}
@@ -1112,7 +1175,7 @@ void update_normals_from_eval(Object &object_eval, Tree &pbvh)
update_normals(object_orig, object_eval, pbvh);
}
void update_node_bounds_mesh(const Span<float3> positions, Node &node)
void update_node_bounds_mesh(const Span<float3> positions, MeshNode &node)
{
Bounds<float3> bounds = negative_bounds();
for (const int vert : node_verts(node)) {
@@ -1121,7 +1184,7 @@ void update_node_bounds_mesh(const Span<float3> positions, Node &node)
node.bounds_ = bounds;
}
void update_node_bounds_grids(const CCGKey &key, const Span<CCGElem *> grids, Node &node)
void update_node_bounds_grids(const CCGKey &key, const Span<CCGElem *> grids, GridsNode &node)
{
Bounds<float3> bounds = negative_bounds();
for (const int grid : node.prim_indices_) {
@@ -1132,7 +1195,7 @@ void update_node_bounds_grids(const CCGKey &key, const Span<CCGElem *> grids, No
node.bounds_ = bounds;
}
void update_node_bounds_bmesh(Node &node)
void update_node_bounds_bmesh(BMeshNode &node)
{
Bounds<float3> bounds = negative_bounds();
for (const BMVert *vert : node.bm_unique_verts_) {
@@ -1149,9 +1212,10 @@ struct BoundsMergeInfo {
bool update;
};
static BoundsMergeInfo merge_child_bounds(MutableSpan<Node> nodes, const int node_index)
template<typename NodeT>
static BoundsMergeInfo merge_child_bounds(MutableSpan<NodeT> nodes, const int node_index)
{
Node &node = nodes[node_index];
NodeT &node = nodes[node_index];
if (node.flag_ & PBVH_Leaf) {
const bool update = node.flag_ & PBVH_UpdateBB;
node.flag_ &= ~PBVH_UpdateBB;
@@ -1170,18 +1234,22 @@ static BoundsMergeInfo merge_child_bounds(MutableSpan<Node> nodes, const int nod
static void flush_bounds_to_parents(Tree &pbvh)
{
pbvh.nodes_.first().bounds_ = merge_child_bounds(pbvh.nodes_, 0).bounds;
std::visit(
[](auto &nodes) {
nodes.first().bounds_ = merge_child_bounds(nodes.as_mutable_span(), 0).bounds;
},
pbvh.nodes_);
}
void update_bounds_mesh(const Span<float3> vert_positions, Tree &pbvh)
{
Vector<Node *> nodes = search_gather(
pbvh, [&](Node &node) { return update_search(&node, PBVH_UpdateBB); });
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (Node *node : nodes.as_span().slice(range)) {
update_node_bounds_mesh(vert_positions, *node);
}
});
IndexMaskMemory memory;
const IndexMask nodes_to_update = search_nodes(
pbvh, memory, [&](const Node &node) { return update_search(node, PBVH_UpdateBB); });
MutableSpan<MeshNode> nodes = pbvh.nodes<MeshNode>();
nodes_to_update.foreach_index(
[&](const int i) { update_node_bounds_mesh(vert_positions, nodes[i]); });
if (!nodes.is_empty()) {
flush_bounds_to_parents(pbvh);
}
@@ -1189,13 +1257,13 @@ void update_bounds_mesh(const Span<float3> vert_positions, Tree &pbvh)
void update_bounds_grids(const CCGKey &key, const Span<CCGElem *> elems, Tree &pbvh)
{
Vector<Node *> nodes = search_gather(
pbvh, [&](Node &node) { return update_search(&node, PBVH_UpdateBB); });
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (Node *node : nodes.as_span().slice(range)) {
update_node_bounds_grids(key, elems, *node);
}
});
IndexMaskMemory memory;
const IndexMask nodes_to_update = search_nodes(
pbvh, memory, [&](const Node &node) { return update_search(node, PBVH_UpdateBB); });
MutableSpan<GridsNode> nodes = pbvh.nodes<GridsNode>();
nodes_to_update.foreach_index(
[&](const int i) { update_node_bounds_grids(key, elems, nodes[i]); });
if (!nodes.is_empty()) {
flush_bounds_to_parents(pbvh);
}
@@ -1203,13 +1271,12 @@ void update_bounds_grids(const CCGKey &key, const Span<CCGElem *> elems, Tree &p
void update_bounds_bmesh(const BMesh & /*bm*/, Tree &pbvh)
{
Vector<Node *> nodes = search_gather(
pbvh, [&](Node &node) { return update_search(&node, PBVH_UpdateBB); });
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (Node *node : nodes.as_span().slice(range)) {
update_node_bounds_bmesh(*node);
}
});
IndexMaskMemory memory;
const IndexMask nodes_to_update = search_nodes(
pbvh, memory, [&](const Node &node) { return update_search(node, PBVH_UpdateBB); });
MutableSpan<BMeshNode> nodes = pbvh.nodes<BMeshNode>();
nodes_to_update.foreach_index([&](const int i) { update_node_bounds_bmesh(nodes[i]); });
if (!nodes.is_empty()) {
flush_bounds_to_parents(pbvh);
}
@@ -1241,15 +1308,18 @@ void update_bounds(const Depsgraph &depsgraph, const Object &object, Tree &pbvh)
void store_bounds_orig(Tree &pbvh)
{
MutableSpan<Node> nodes = pbvh.nodes_;
threading::parallel_for(nodes.index_range(), 256, [&](const IndexRange range) {
for (const int i : range) {
nodes[i].bounds_orig_ = nodes[i].bounds_;
}
});
std::visit(
[](auto &nodes) {
threading::parallel_for(nodes.index_range(), 256, [&](const IndexRange range) {
for (const int i : range) {
nodes[i].bounds_orig_ = nodes[i].bounds_;
}
});
},
pbvh.nodes_);
}
void node_update_mask_mesh(const Span<float> mask, Node &node)
void node_update_mask_mesh(const Span<float> mask, MeshNode &node)
{
const Span<int> verts = node_verts(node);
const bool fully_masked = std::all_of(
@@ -1261,27 +1331,26 @@ void node_update_mask_mesh(const Span<float> mask, Node &node)
node.flag_ &= ~PBVH_UpdateMask;
}
static void update_mask_mesh(const Mesh &mesh, const Span<Node *> nodes)
static void update_mask_mesh(const Mesh &mesh,
const MutableSpan<MeshNode> nodes,
const IndexMask &nodes_to_update)
{
const AttributeAccessor attributes = mesh.attributes();
const VArraySpan<float> mask = *attributes.lookup<float>(".sculpt_mask", AttrDomain::Point);
if (mask.is_empty()) {
for (Node *node : nodes) {
node->flag_ &= ~PBVH_FullyMasked;
node->flag_ |= PBVH_FullyUnmasked;
node->flag_ &= ~PBVH_UpdateMask;
}
nodes_to_update.foreach_index([&](const int i) {
nodes[i].flag_ &= ~PBVH_FullyMasked;
nodes[i].flag_ |= PBVH_FullyUnmasked;
nodes[i].flag_ &= ~PBVH_UpdateMask;
});
return;
}
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (Node *node : nodes.slice(range)) {
node_update_mask_mesh(mask, *node);
}
});
nodes_to_update.foreach_index(GrainSize(1),
[&](const int i) { node_update_mask_mesh(mask, nodes[i]); });
}
void node_update_mask_grids(const CCGKey &key, const Span<CCGElem *> grids, Node &node)
void node_update_mask_grids(const CCGKey &key, const Span<CCGElem *> grids, GridsNode &node)
{
BLI_assert(key.has_mask);
bool fully_masked = true;
@@ -1299,26 +1368,25 @@ void node_update_mask_grids(const CCGKey &key, const Span<CCGElem *> grids, Node
node.flag_ &= ~PBVH_UpdateMask;
}
static void update_mask_grids(const SubdivCCG &subdiv_ccg, const Span<Node *> nodes)
static void update_mask_grids(const SubdivCCG &subdiv_ccg,
const MutableSpan<GridsNode> nodes,
const IndexMask &nodes_to_update)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
if (!key.has_mask) {
for (Node *node : nodes) {
node->flag_ &= ~PBVH_FullyMasked;
node->flag_ |= PBVH_FullyUnmasked;
node->flag_ &= ~PBVH_UpdateMask;
}
nodes_to_update.foreach_index([&](const int i) {
nodes[i].flag_ &= ~PBVH_FullyMasked;
nodes[i].flag_ |= PBVH_FullyUnmasked;
nodes[i].flag_ &= ~PBVH_UpdateMask;
});
return;
}
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (Node *node : nodes.slice(range)) {
node_update_mask_grids(key, subdiv_ccg.grids, *node);
}
});
nodes_to_update.foreach_index(
GrainSize(1), [&](const int i) { node_update_mask_grids(key, subdiv_ccg.grids, nodes[i]); });
}
void node_update_mask_bmesh(const int mask_offset, Node &node)
void node_update_mask_bmesh(const int mask_offset, BMeshNode &node)
{
BLI_assert(mask_offset != -1);
bool fully_masked = true;
@@ -1336,52 +1404,52 @@ void node_update_mask_bmesh(const int mask_offset, Node &node)
node.flag_ &= ~PBVH_UpdateMask;
}
static void update_mask_bmesh(const BMesh &bm, const Span<Node *> nodes)
static void update_mask_bmesh(const BMesh &bm,
const MutableSpan<BMeshNode> nodes,
const IndexMask &nodes_to_update)
{
const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
if (offset == -1) {
for (Node *node : nodes) {
node->flag_ &= ~PBVH_FullyMasked;
node->flag_ |= PBVH_FullyUnmasked;
node->flag_ &= ~PBVH_UpdateMask;
}
nodes_to_update.foreach_index([&](const int i) {
nodes[i].flag_ &= ~PBVH_FullyMasked;
nodes[i].flag_ |= PBVH_FullyUnmasked;
nodes[i].flag_ &= ~PBVH_UpdateMask;
});
return;
}
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (Node *node : nodes.slice(range)) {
node_update_mask_bmesh(offset, *node);
}
});
nodes_to_update.foreach_index(GrainSize(1),
[&](const int i) { node_update_mask_bmesh(offset, nodes[i]); });
}
void update_mask(const Object &object, Tree &pbvh)
{
Vector<Node *> nodes = search_gather(
pbvh, [&](Node &node) { return update_search(&node, PBVH_UpdateMask); });
IndexMaskMemory memory;
const IndexMask nodes_to_update = search_nodes(
pbvh, memory, [&](const Node &node) { return update_search(node, PBVH_UpdateMask); });
switch (pbvh.type()) {
case Type::Mesh: {
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
update_mask_mesh(mesh, nodes);
update_mask_mesh(mesh, pbvh.nodes<MeshNode>(), nodes_to_update);
break;
}
case Type::Grids: {
const SculptSession &ss = *object.sculpt;
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
update_mask_grids(subdiv_ccg, nodes);
update_mask_grids(subdiv_ccg, pbvh.nodes<GridsNode>(), nodes_to_update);
break;
}
case Type::BMesh: {
const SculptSession &ss = *object.sculpt;
const BMesh &bm = *ss.bm;
update_mask_bmesh(bm, nodes);
update_mask_bmesh(bm, pbvh.nodes<BMeshNode>(), nodes_to_update);
break;
}
}
}
void node_update_visibility_mesh(const Span<bool> hide_vert, Node &node)
void node_update_visibility_mesh(const Span<bool> hide_vert, MeshNode &node)
{
BLI_assert(!hide_vert.is_empty());
const Span<int> verts = node_verts(node);
@@ -1391,26 +1459,25 @@ void node_update_visibility_mesh(const Span<bool> hide_vert, Node &node)
node.flag_ &= ~PBVH_UpdateVisibility;
}
static void update_visibility_faces(const Mesh &mesh, const Span<Node *> nodes)
static void update_visibility_faces(const Mesh &mesh,
const MutableSpan<MeshNode> nodes,
const IndexMask &nodes_to_update)
{
const AttributeAccessor attributes = mesh.attributes();
const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert", AttrDomain::Point);
if (hide_vert.is_empty()) {
for (Node *node : nodes) {
node->flag_ &= ~PBVH_FullyHidden;
node->flag_ &= ~PBVH_UpdateVisibility;
}
nodes_to_update.foreach_index([&](const int i) {
nodes[i].flag_ &= ~PBVH_FullyHidden;
nodes[i].flag_ &= ~PBVH_UpdateVisibility;
});
return;
}
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (Node *node : nodes.slice(range)) {
node_update_visibility_mesh(hide_vert, *node);
}
});
nodes_to_update.foreach_index(
GrainSize(1), [&](const int i) { node_update_visibility_mesh(hide_vert, nodes[i]); });
}
void node_update_visibility_grids(const BitGroupVector<> &grid_hidden, Node &node)
void node_update_visibility_grids(const BitGroupVector<> &grid_hidden, GridsNode &node)
{
BLI_assert(!grid_hidden.is_empty());
const bool fully_hidden = std::none_of(
@@ -1421,25 +1488,24 @@ void node_update_visibility_grids(const BitGroupVector<> &grid_hidden, Node &nod
node.flag_ &= ~PBVH_UpdateVisibility;
}
static void update_visibility_grids(const SubdivCCG &subdiv_ccg, const Span<Node *> nodes)
static void update_visibility_grids(const SubdivCCG &subdiv_ccg,
const MutableSpan<GridsNode> nodes,
const IndexMask &nodes_to_update)
{
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
if (grid_hidden.is_empty()) {
for (Node *node : nodes) {
node->flag_ &= ~PBVH_FullyHidden;
node->flag_ &= ~PBVH_UpdateVisibility;
}
nodes_to_update.foreach_index([&](const int i) {
nodes[i].flag_ &= ~PBVH_FullyHidden;
nodes[i].flag_ &= ~PBVH_UpdateVisibility;
});
return;
}
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (Node *node : nodes.slice(range)) {
node_update_visibility_grids(grid_hidden, *node);
}
});
nodes_to_update.foreach_index(
GrainSize(1), [&](const int i) { node_update_visibility_grids(grid_hidden, nodes[i]); });
}
void node_update_visibility_bmesh(Node &node)
void node_update_visibility_bmesh(BMeshNode &node)
{
const bool unique_hidden = std::all_of(
node.bm_unique_verts_.begin(), node.bm_unique_verts_.end(), [&](const BMVert *vert) {
@@ -1453,33 +1519,32 @@ void node_update_visibility_bmesh(Node &node)
node.flag_ &= ~PBVH_UpdateVisibility;
}
static void update_visibility_bmesh(const Span<Node *> nodes)
static void update_visibility_bmesh(const MutableSpan<BMeshNode> nodes,
const IndexMask &nodes_to_update)
{
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (Node *node : nodes.slice(range)) {
node_update_visibility_bmesh(*node);
}
});
nodes_to_update.foreach_index(GrainSize(1),
[&](const int i) { node_update_visibility_bmesh(nodes[i]); });
}
void update_visibility(const Object &object, Tree &pbvh)
{
Vector<Node *> nodes = search_gather(
pbvh, [&](Node &node) { return update_search(&node, PBVH_UpdateVisibility); });
IndexMaskMemory memory;
const IndexMask nodes_to_update = search_nodes(
pbvh, memory, [&](const Node &node) { return update_search(node, PBVH_UpdateVisibility); });
switch (pbvh.type()) {
case Type::Mesh: {
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
update_visibility_faces(mesh, nodes);
update_visibility_faces(mesh, pbvh.nodes<MeshNode>(), nodes_to_update);
break;
}
case Type::Grids: {
const SculptSession &ss = *object.sculpt;
update_visibility_grids(*ss.subdiv_ccg, nodes);
update_visibility_grids(*ss.subdiv_ccg, pbvh.nodes<GridsNode>(), nodes_to_update);
break;
}
case Type::BMesh: {
update_visibility_bmesh(nodes);
update_visibility_bmesh(pbvh.nodes<BMeshNode>(), nodes_to_update);
break;
}
}
@@ -1525,7 +1590,7 @@ blender::Bounds<blender::float3> BKE_pbvh_redraw_BB(blender::bke::pbvh::Tree &pb
{
using namespace blender;
using namespace blender::bke::pbvh;
if (pbvh.nodes_.is_empty()) {
if (tree_is_empty(pbvh)) {
return {};
}
Bounds<float3> bounds = negative_bounds();
@@ -1545,7 +1610,8 @@ blender::Bounds<blender::float3> BKE_pbvh_redraw_BB(blender::bke::pbvh::Tree &pb
namespace blender::bke::pbvh {
IndexMask nodes_to_face_selection_grids(const SubdivCCG &subdiv_ccg,
const Span<const Node *> nodes,
const Span<GridsNode> nodes,
const IndexMask &nodes_mask,
IndexMaskMemory &memory)
{
const Span<int> grid_to_face_map = subdiv_ccg.grid_to_face_map;
@@ -1553,11 +1619,9 @@ IndexMask nodes_to_face_selection_grids(const SubdivCCG &subdiv_ccg,
* worse with large selections since the loop would be single-threaded. A boolean array has an
* overhead regardless of selection size, but that is small. */
Array<bool> faces_to_update(subdiv_ccg.faces.size(), false);
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (const Node *node : nodes.slice(range)) {
for (const int grid : node->prim_indices_) {
faces_to_update[grid_to_face_map[grid]] = true;
}
nodes_mask.foreach_index(GrainSize(1), [&](const int i) {
for (const int grid : node_grid_indices(nodes[i])) {
faces_to_update[grid_to_face_map[grid]] = true;
}
});
return IndexMask::from_bools(faces_to_update, memory);
@@ -1565,10 +1629,14 @@ IndexMask nodes_to_face_selection_grids(const SubdivCCG &subdiv_ccg,
Bounds<float3> bounds_get(const Tree &pbvh)
{
if (pbvh.nodes_.is_empty()) {
return float3(0);
}
return pbvh.nodes_.first().bounds_;
return std::visit(
[](auto &nodes) -> Bounds<float3> {
if (nodes.is_empty()) {
return float3(0);
}
return nodes.first().bounds_;
},
pbvh.nodes_);
}
} // namespace blender::bke::pbvh
@@ -1614,11 +1682,15 @@ void BKE_pbvh_node_mark_update_face_sets(blender::bke::pbvh::Node &node)
void BKE_pbvh_mark_rebuild_pixels(blender::bke::pbvh::Tree &pbvh)
{
for (blender::bke::pbvh::Node &node : pbvh.nodes_) {
if (node.flag_ & PBVH_Leaf) {
node.flag_ |= PBVH_RebuildPixels;
}
}
std::visit(
[](auto &nodes) {
for (blender::bke::pbvh::Node &node : nodes) {
if (node.flag_ & PBVH_Leaf) {
node.flag_ |= PBVH_RebuildPixels;
}
}
},
pbvh.nodes_);
}
void BKE_pbvh_node_mark_update_visibility(blender::bke::pbvh::Node &node)
@@ -1695,23 +1767,23 @@ bool BKE_pbvh_node_fully_unmasked_get(const blender::bke::pbvh::Node &node)
namespace blender::bke::pbvh {
Span<int> node_corners(const Node &node)
Span<int> node_corners(const MeshNode &node)
{
return node.corner_indices_;
}
Span<int> node_verts(const Node &node)
Span<int> node_verts(const MeshNode &node)
{
return node.vert_indices_;
}
Span<int> node_unique_verts(const Node &node)
Span<int> node_unique_verts(const MeshNode &node)
{
return node.vert_indices_.as_span().take_front(node.unique_verts_num_);
}
Span<int> node_face_indices_calc_mesh(const Span<int> corner_tri_faces,
const Node &node,
const MeshNode &node,
Vector<int> &faces)
{
faces.clear();
@@ -1727,7 +1799,7 @@ Span<int> node_face_indices_calc_mesh(const Span<int> corner_tri_faces,
}
Span<int> node_face_indices_calc_grids(const SubdivCCG &subdiv_ccg,
const Node &node,
const GridsNode &node,
Vector<int> &faces)
{
faces.clear();
@@ -1743,7 +1815,7 @@ Span<int> node_face_indices_calc_grids(const SubdivCCG &subdiv_ccg,
return faces.as_span();
}
Span<int> node_grid_indices(const Node &node)
Span<int> node_grid_indices(const GridsNode &node)
{
return node.prim_indices_;
}
@@ -1765,7 +1837,7 @@ blender::Bounds<blender::float3> BKE_pbvh_node_get_original_BB(
return node->bounds_orig_;
}
void BKE_pbvh_node_get_bm_orco_data(blender::bke::pbvh::Node *node,
void BKE_pbvh_node_get_bm_orco_data(blender::bke::pbvh::BMeshNode *node,
int (**r_orco_tris)[3],
int *r_orco_tris_num,
float (**r_orco_coords)[3],
@@ -1928,7 +2000,7 @@ bool ray_face_nearest_tri(const float ray_start[3],
return false;
}
static bool pbvh_faces_node_raycast(const Node &node,
static bool pbvh_faces_node_raycast(const MeshNode &node,
const float (*origco)[3],
const Span<float3> vert_positions,
const Span<int> corner_verts,
@@ -2000,7 +2072,7 @@ static bool pbvh_faces_node_raycast(const Node &node,
}
static bool pbvh_grids_node_raycast(const SubdivCCG &subdiv_ccg,
Node &node,
GridsNode &node,
const float (*origco)[3],
const float ray_start[3],
const float ray_normal[3],
@@ -2119,7 +2191,7 @@ bool raycast_node(Tree &pbvh,
switch (pbvh.type()) {
case Type::Mesh:
hit |= pbvh_faces_node_raycast(node,
hit |= pbvh_faces_node_raycast(static_cast<MeshNode &>(node),
origco,
vert_positions,
corner_verts,
@@ -2136,7 +2208,7 @@ bool raycast_node(Tree &pbvh,
break;
case Type::Grids:
hit |= pbvh_grids_node_raycast(*subdiv_ccg,
node,
static_cast<GridsNode &>(node),
origco,
ray_start,
ray_normal,
@@ -2147,7 +2219,7 @@ bool raycast_node(Tree &pbvh,
face_normal);
break;
case Type::BMesh:
hit = bmesh_node_raycast(node,
hit = bmesh_node_raycast(static_cast<BMeshNode &>(node),
ray_start,
ray_normal,
isect_precalc,
@@ -2164,7 +2236,7 @@ bool raycast_node(Tree &pbvh,
void clip_ray_ortho(
Tree &pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
{
if (pbvh.nodes_.is_empty()) {
if (tree_is_empty(pbvh)) {
return;
}
float rootmin_start, rootmin_end;
@@ -2176,10 +2248,10 @@ void clip_ray_ortho(
const float offset_vec[3] = {1e-3f, 1e-3f, 1e-3f};
if (original) {
bb_root = BKE_pbvh_node_get_original_BB(&pbvh.nodes_.first());
bb_root = BKE_pbvh_node_get_original_BB(&first_node(pbvh));
}
else {
bb_root = node_bounds(pbvh.nodes_.first());
bb_root = node_bounds(first_node(pbvh));
}
/* Calc rough clipping to avoid overflow later. See #109555. */
@@ -2288,7 +2360,7 @@ void find_nearest_to_ray(Tree &pbvh,
fn);
}
static bool pbvh_faces_node_nearest_to_ray(const Node &node,
static bool pbvh_faces_node_nearest_to_ray(const MeshNode &node,
const float (*origco)[3],
const Span<float3> vert_positions,
const Span<int> corner_verts,
@@ -2337,7 +2409,7 @@ static bool pbvh_faces_node_nearest_to_ray(const Node &node,
}
static bool pbvh_grids_node_nearest_to_ray(const SubdivCCG &subdiv_ccg,
Node &node,
GridsNode &node,
const float (*origco)[3],
const float ray_start[3],
const float ray_normal[3],
@@ -2420,7 +2492,7 @@ bool find_nearest_to_ray_node(Tree &pbvh,
switch (pbvh.type()) {
case Type::Mesh:
hit |= pbvh_faces_node_nearest_to_ray(node,
hit |= pbvh_faces_node_nearest_to_ray(static_cast<MeshNode &>(node),
origco,
vert_positions,
corner_verts,
@@ -2433,11 +2505,17 @@ bool find_nearest_to_ray_node(Tree &pbvh,
dist_sq);
break;
case Type::Grids:
hit |= pbvh_grids_node_nearest_to_ray(
*subdiv_ccg, node, origco, ray_start, ray_normal, depth, dist_sq);
hit |= pbvh_grids_node_nearest_to_ray(*subdiv_ccg,
static_cast<GridsNode &>(node),
origco,
ray_start,
ray_normal,
depth,
dist_sq);
break;
case Type::BMesh:
hit = bmesh_node_nearest_to_ray(node, ray_start, ray_normal, depth, dist_sq, use_origco);
hit = bmesh_node_nearest_to_ray(
static_cast<BMeshNode &>(node), ray_start, ray_normal, depth, dist_sq, use_origco);
break;
}
@@ -2535,7 +2613,7 @@ static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Object &obje
args.hide_poly = *mesh_orig.attributes().lookup<bool>(".hide_poly",
blender::bke::AttrDomain::Face);
args.prim_indices = node.prim_indices_;
args.prim_indices = static_cast<const blender::bke::pbvh::MeshNode &>(node).prim_indices_;
args.tri_faces = mesh_eval.corner_tri_faces();
break;
case blender::bke::pbvh::Type::Grids: {
@@ -2545,7 +2623,7 @@ static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Object &obje
args.face_data = &mesh_orig.face_data;
args.ccg_key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
args.mesh = &mesh_orig;
args.grid_indices = node.prim_indices_;
args.grid_indices = static_cast<const blender::bke::pbvh::GridsNode &>(node).prim_indices_;
args.subdiv_ccg = &const_cast<SubdivCCG &>(subdiv_ccg);
args.grids = subdiv_ccg.grids;
break;
@@ -2556,7 +2634,7 @@ static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Object &obje
args.vert_data = &args.bm->vdata;
args.corner_data = &args.bm->ldata;
args.face_data = &args.bm->pdata;
args.bm_faces = &node.bm_faces_;
args.bm_faces = &static_cast<const blender::bke::pbvh::BMeshNode &>(node).bm_faces_;
args.cd_mask_layer = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
break;
@@ -2674,7 +2752,7 @@ void draw_cb(const Object &object_eval,
else {
/* Get all nodes with draw updates, also those outside the view. */
Vector<Node *> nodes = search_gather(pbvh, [&](Node &node) {
return update_search(&node, PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
return update_search(node, PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
});
pbvh_update_draw_buffers(
object_orig, object_eval, pbvh, nodes, PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
@@ -2709,27 +2787,31 @@ void BKE_pbvh_draw_debug_cb(blender::bke::pbvh::Tree &pbvh,
{
PBVHNodeFlags flag = PBVH_Leaf;
for (blender::bke::pbvh::Node &node : pbvh.nodes_) {
if (node.flag_ & PBVH_TexLeaf) {
flag = PBVH_TexLeaf;
break;
}
}
std::visit(
[&](auto &nodes) {
for (blender::bke::pbvh::Node &node : nodes) {
if (node.flag_ & PBVH_TexLeaf) {
flag = PBVH_TexLeaf;
break;
}
}
for (blender::bke::pbvh::Node &node : pbvh.nodes_) {
if (!(node.flag_ & flag)) {
continue;
}
for (blender::bke::pbvh::Node &node : nodes) {
if (!(node.flag_ & flag)) {
continue;
}
draw_fn(&node, user_data, node.bounds_.min, node.bounds_.max, node.flag_);
}
draw_fn(&node, user_data, node.bounds_.min, node.bounds_.max, node.flag_);
}
},
pbvh.nodes_);
}
void BKE_pbvh_vert_coords_apply(blender::bke::pbvh::Tree &pbvh,
const blender::Span<blender::float3> vert_positions)
{
using namespace blender::bke::pbvh;
for (Node &node : pbvh.nodes_) {
for (MeshNode &node : pbvh.nodes<MeshNode>()) {
BKE_pbvh_node_mark_positions_update(node);
}
update_bounds_mesh(vert_positions, pbvh);
@@ -2848,7 +2930,7 @@ void BKE_pbvh_ensure_node_face_corners(blender::bke::pbvh::Tree &pbvh,
int totloop = 0;
/* Check if nodes already have loop indices. */
for (blender::bke::pbvh::Node &node : pbvh.nodes_) {
for (blender::bke::pbvh::MeshNode &node : pbvh.nodes<blender::bke::pbvh::MeshNode>()) {
if (!(node.flag_ & PBVH_Leaf)) {
continue;
}
@@ -2864,7 +2946,7 @@ void BKE_pbvh_ensure_node_face_corners(blender::bke::pbvh::Tree &pbvh,
/* Create loop indices from node loop triangles. */
Vector<int> corner_indices;
for (blender::bke::pbvh::Node &node : pbvh.nodes_) {
for (blender::bke::pbvh::MeshNode &node : pbvh.nodes<blender::bke::pbvh::MeshNode>()) {
if (!(node.flag_ & PBVH_Leaf)) {
continue;
}
@@ -2978,20 +3060,24 @@ namespace blender::bke::pbvh {
Vector<Node *> all_leaf_nodes(Tree &pbvh)
{
Vector<Node *> leaf_nodes;
leaf_nodes.reserve(pbvh.nodes_.size());
for (Node &node : pbvh.nodes_) {
if (node.flag_ & PBVH_Leaf) {
leaf_nodes.append(&node);
}
}
return leaf_nodes;
return std::visit(
[&](auto &nodes) {
leaf_nodes.reserve(nodes.size());
for (Node &node : nodes) {
if (node.flag_ & PBVH_Leaf) {
leaf_nodes.append(&node);
}
}
return leaf_nodes;
},
pbvh.nodes_);
}
Vector<Node *> search_gather(Tree &pbvh,
const FunctionRef<bool(Node &)> scb,
PBVHNodeFlags leaf_flag)
{
if (pbvh.nodes_.is_empty()) {
if (tree_is_empty(pbvh)) {
return {};
}
@@ -3010,6 +3096,25 @@ Vector<Node *> search_gather(Tree &pbvh,
return nodes;
}
IndexMask search_nodes(const Tree &pbvh,
IndexMaskMemory &memory,
FunctionRef<bool(const Node &)> filter_fn)
{
Vector<Node *> nodes = search_gather(const_cast<Tree &>(pbvh),
[&](Node &node) { return filter_fn(node); });
Array<int> indices(nodes.size());
std::visit(
[&](const auto &pbvh_nodes) {
using VectorT = std::decay_t<decltype(pbvh_nodes)>;
for (const int i : nodes.index_range()) {
indices[i] = static_cast<typename VectorT::value_type *>(nodes[i]) - pbvh_nodes.data();
}
},
pbvh.nodes_);
std::sort(indices.begin(), indices.end());
return IndexMask::from_indices(indices.as_span(), memory);
}
} // namespace blender::bke::pbvh
PBVHVertRef BKE_pbvh_index_to_vertex(const Object &object, int index)

View File

@@ -205,12 +205,11 @@ static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v)
/****************************** Building ******************************/
/** Update node data after splitting. */
static void pbvh_bmesh_node_finalize(Tree &pbvh,
static void pbvh_bmesh_node_finalize(BMeshNode *n,
const int node_index,
const int cd_vert_node_offset,
const int cd_face_node_offset)
{
Node *n = &pbvh.nodes_[node_index];
bool has_visible = false;
n->bounds_ = negative_bounds();
@@ -256,17 +255,17 @@ static void pbvh_bmesh_node_finalize(Tree &pbvh,
}
/** Recursively split the node if it exceeds the leaf_limit. */
static void pbvh_bmesh_node_split(Tree &pbvh,
static void pbvh_bmesh_node_split(Vector<BMeshNode> &nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
const Span<Bounds<float3>> face_bounds,
int node_index)
{
Node *n = &pbvh.nodes_[node_index];
BMeshNode *n = &nodes[node_index];
if (n->bm_faces_.size() <= leaf_limit) {
/* Node limit not exceeded. */
pbvh_bmesh_node_finalize(pbvh, node_index, cd_vert_node_offset, cd_face_node_offset);
pbvh_bmesh_node_finalize(n, node_index, cd_vert_node_offset, cd_face_node_offset);
return;
}
@@ -283,15 +282,15 @@ static void pbvh_bmesh_node_split(Tree &pbvh,
const float mid = math::midpoint(cb.max[axis], cb.min[axis]);
/* Add two new child nodes. */
const int children = pbvh.nodes_.size();
const int children = nodes.size();
n->children_offset_ = children;
pbvh.nodes_.resize(pbvh.nodes_.size() + 2);
nodes.resize(nodes.size() + 2);
/* Array reallocated, update current node pointer. */
n = &pbvh.nodes_[node_index];
n = &nodes[node_index];
/* Initialize children */
Node *c1 = &pbvh.nodes_[children], *c2 = &pbvh.nodes_[children + 1];
BMeshNode *c1 = &nodes[children], *c2 = &nodes[children + 1];
c1->flag_ |= PBVH_Leaf;
c2->flag_ |= PBVH_Leaf;
c1->bm_faces_.reserve(n->bm_faces_.size() / 2);
@@ -346,26 +345,27 @@ static void pbvh_bmesh_node_split(Tree &pbvh,
n->flag_ &= ~PBVH_Leaf;
/* Recurse. */
pbvh_bmesh_node_split(pbvh, cd_vert_node_offset, cd_face_node_offset, face_bounds, children);
pbvh_bmesh_node_split(pbvh, cd_vert_node_offset, cd_face_node_offset, face_bounds, children + 1);
pbvh_bmesh_node_split(nodes, cd_vert_node_offset, cd_face_node_offset, face_bounds, children);
pbvh_bmesh_node_split(
nodes, cd_vert_node_offset, cd_face_node_offset, face_bounds, children + 1);
/* Array maybe reallocated, update current node pointer */
n = &pbvh.nodes_[node_index];
n = &nodes[node_index];
/* Update bounding box. */
n->bounds_ = bounds::merge(pbvh.nodes_[n->children_offset_].bounds_,
pbvh.nodes_[n->children_offset_ + 1].bounds_);
n->bounds_ = bounds::merge(nodes[n->children_offset_].bounds_,
nodes[n->children_offset_ + 1].bounds_);
n->bounds_orig_ = n->bounds_;
}
/** Recursively split the node if it exceeds the leaf_limit. */
static bool pbvh_bmesh_node_limit_ensure(BMesh &bm,
Tree &pbvh,
Vector<BMeshNode> &nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
int node_index)
{
Node &node = pbvh.nodes_[node_index];
BMeshNode &node = nodes[node_index];
const int faces_num = node.bm_faces_.size();
if (faces_num <= leaf_limit) {
/* Node limit not exceeded */
@@ -393,7 +393,7 @@ static bool pbvh_bmesh_node_limit_ensure(BMesh &bm,
/* Likely this is already dirty. */
bm.elem_index_dirty |= BM_FACE;
pbvh_bmesh_node_split(pbvh, cd_vert_node_offset, cd_face_node_offset, face_bounds, node_index);
pbvh_bmesh_node_split(nodes, cd_vert_node_offset, cd_face_node_offset, face_bounds, node_index);
return true;
}
@@ -414,22 +414,22 @@ BLI_INLINE int pbvh_bmesh_node_index_from_face(const int cd_face_node_offset, co
return node_index;
}
BLI_INLINE Node *pbvh_bmesh_node_from_vert(Tree &pbvh,
const int cd_vert_node_offset,
const BMVert *key)
BLI_INLINE BMeshNode *pbvh_bmesh_node_from_vert(MutableSpan<BMeshNode> nodes,
const int cd_vert_node_offset,
const BMVert *key)
{
return &pbvh.nodes_[pbvh_bmesh_node_index_from_vert(cd_vert_node_offset, key)];
return &nodes[pbvh_bmesh_node_index_from_vert(cd_vert_node_offset, key)];
}
BLI_INLINE Node *pbvh_bmesh_node_from_face(Tree &pbvh,
const int cd_face_node_offset,
const BMFace *key)
BLI_INLINE BMeshNode *pbvh_bmesh_node_from_face(MutableSpan<BMeshNode> nodes,
const int cd_face_node_offset,
const BMFace *key)
{
return &pbvh.nodes_[pbvh_bmesh_node_index_from_face(cd_face_node_offset, key)];
return &nodes[pbvh_bmesh_node_index_from_face(cd_face_node_offset, key)];
}
static BMVert *pbvh_bmesh_vert_create(BMesh &bm,
Tree &pbvh,
MutableSpan<BMeshNode> nodes,
BMLog &bm_log,
const BMVert *v1,
const BMVert *v2,
@@ -439,9 +439,9 @@ static BMVert *pbvh_bmesh_vert_create(BMesh &bm,
const int cd_vert_node_offset,
const int cd_vert_mask_offset)
{
Node *node = &pbvh.nodes_[node_index];
BMeshNode *node = &nodes[node_index];
BLI_assert((pbvh.nodes_.size() == 1 || node_index) && node_index <= pbvh.nodes_.size());
BLI_assert((nodes.size() == 1 || node_index) && node_index <= nodes.size());
/* Avoid initializing custom-data because its quite involved. */
BMVert *v = BM_vert_create(&bm, co, nullptr, BM_CREATE_NOP);
@@ -466,7 +466,7 @@ static BMVert *pbvh_bmesh_vert_create(BMesh &bm,
* \note Callers are responsible for checking if the face exists before adding.
*/
static BMFace *pbvh_bmesh_face_create(BMesh &bm,
Tree &pbvh,
MutableSpan<BMeshNode> nodes,
const int cd_face_node_offset,
BMLog &bm_log,
int node_index,
@@ -474,7 +474,7 @@ static BMFace *pbvh_bmesh_face_create(BMesh &bm,
const Span<BMEdge *> e_tri,
const BMFace *f_example)
{
Node *node = &pbvh.nodes_[node_index];
BMeshNode *node = &nodes[node_index];
/* Ensure we never add existing face. */
BLI_assert(!BM_face_exists(v_tri.data(), 3));
@@ -494,17 +494,20 @@ static BMFace *pbvh_bmesh_face_create(BMesh &bm,
return f;
}
#define pbvh_bmesh_node_vert_use_count_is_equal(pbvh, cd_face_node_offset, node, v, n) \
(pbvh_bmesh_node_vert_use_count_at_most(pbvh, cd_face_node_offset, node, v, (n) + 1) == n)
#define pbvh_bmesh_node_vert_use_count_is_equal(nodes, cd_face_node_offset, node, v, n) \
(pbvh_bmesh_node_vert_use_count_at_most(nodes, cd_face_node_offset, node, v, (n) + 1) == n)
static int pbvh_bmesh_node_vert_use_count_at_most(
Tree &pbvh, const int cd_face_node_offset, Node *node, BMVert *v, const int count_max)
static int pbvh_bmesh_node_vert_use_count_at_most(MutableSpan<BMeshNode> nodes,
const int cd_face_node_offset,
BMeshNode *node,
BMVert *v,
const int count_max)
{
int count = 0;
BMFace *f;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
Node *f_node = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, f);
BMeshNode *f_node = pbvh_bmesh_node_from_face(nodes, cd_face_node_offset, f);
if (f_node == node) {
count++;
if (count == count_max) {
@@ -518,16 +521,16 @@ static int pbvh_bmesh_node_vert_use_count_at_most(
}
/** Return a node that uses vertex `v` other than its current owner. */
static Node *pbvh_bmesh_vert_other_node_find(Tree &pbvh,
const int cd_vert_node_offset,
const int cd_face_node_offset,
BMVert *v)
static BMeshNode *pbvh_bmesh_vert_other_node_find(MutableSpan<BMeshNode> nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
BMVert *v)
{
Node *current_node = pbvh_bmesh_node_from_vert(pbvh, cd_vert_node_offset, v);
BMeshNode *current_node = pbvh_bmesh_node_from_vert(nodes, cd_vert_node_offset, v);
BMFace *f;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
Node *f_node = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, f);
BMeshNode *f_node = pbvh_bmesh_node_from_face(nodes, cd_face_node_offset, f);
if (f_node != current_node) {
return f_node;
@@ -538,12 +541,12 @@ static Node *pbvh_bmesh_vert_other_node_find(Tree &pbvh,
return nullptr;
}
static void pbvh_bmesh_vert_ownership_transfer(Tree &pbvh,
static void pbvh_bmesh_vert_ownership_transfer(MutableSpan<BMeshNode> nodes,
const int cd_vert_node_offset,
Node *new_owner,
BMeshNode *new_owner,
BMVert *v)
{
Node *current_owner = pbvh_bmesh_node_from_vert(pbvh, cd_vert_node_offset, v);
BMeshNode *current_owner = pbvh_bmesh_node_from_vert(nodes, cd_vert_node_offset, v);
current_owner->flag_ |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
BLI_assert(current_owner != new_owner);
@@ -552,7 +555,7 @@ static void pbvh_bmesh_vert_ownership_transfer(Tree &pbvh,
current_owner->bm_unique_verts_.remove(v);
/* Set new ownership */
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, new_owner - pbvh.nodes_.data());
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, new_owner - nodes.data());
new_owner->bm_unique_verts_.add(v);
new_owner->bm_other_verts_.remove(v);
BLI_assert(!new_owner->bm_other_verts_.contains(v));
@@ -560,7 +563,7 @@ static void pbvh_bmesh_vert_ownership_transfer(Tree &pbvh,
new_owner->flag_ |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
}
static void pbvh_bmesh_vert_remove(Tree &pbvh,
static void pbvh_bmesh_vert_remove(MutableSpan<BMeshNode> nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
BMVert *v)
@@ -568,7 +571,7 @@ static void pbvh_bmesh_vert_remove(Tree &pbvh,
/* Never match for first time. */
int f_node_index_prev = DYNTOPO_NODE_NONE;
Node *v_node = pbvh_bmesh_node_from_vert(pbvh, cd_vert_node_offset, v);
BMeshNode *v_node = pbvh_bmesh_node_from_vert(nodes, cd_vert_node_offset, v);
v_node->bm_unique_verts_.remove(v);
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
@@ -581,7 +584,7 @@ static void pbvh_bmesh_vert_remove(Tree &pbvh,
if (f_node_index_prev != f_node_index) {
f_node_index_prev = f_node_index;
Node *f_node = &pbvh.nodes_[f_node_index];
BMeshNode *f_node = &nodes[f_node_index];
f_node->flag_ |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
/* Remove current ownership. */
@@ -594,30 +597,30 @@ static void pbvh_bmesh_vert_remove(Tree &pbvh,
BM_FACES_OF_VERT_ITER_END;
}
static void pbvh_bmesh_face_remove(Tree &pbvh,
static void pbvh_bmesh_face_remove(MutableSpan<BMeshNode> nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
BMLog &bm_log,
BMFace *f)
{
Node *f_node = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, f);
BMeshNode *f_node = pbvh_bmesh_node_from_face(nodes, cd_face_node_offset, f);
/* Check if any of this face's vertices need to be removed from the node. */
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter = l_first;
do {
BMVert *v = l_iter->v;
if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, cd_face_node_offset, f_node, v, 1)) {
if (pbvh_bmesh_node_vert_use_count_is_equal(nodes, cd_face_node_offset, f_node, v, 1)) {
if (f_node->bm_unique_verts_.contains(v)) {
/* Find a different node that uses 'v'. */
Node *new_node;
BMeshNode *new_node;
new_node = pbvh_bmesh_vert_other_node_find(
pbvh, cd_vert_node_offset, cd_face_node_offset, v);
nodes, cd_vert_node_offset, cd_face_node_offset, v);
BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
if (new_node) {
pbvh_bmesh_vert_ownership_transfer(pbvh, cd_vert_node_offset, new_node, v);
pbvh_bmesh_vert_ownership_transfer(nodes, cd_vert_node_offset, new_node, v);
}
}
else {
@@ -651,7 +654,7 @@ static Array<BMLoop *> pbvh_bmesh_edge_loops(BMEdge *e)
return loops;
}
static void pbvh_bmesh_node_drop_orig(Node *node)
static void pbvh_bmesh_node_drop_orig(BMeshNode *node)
{
MEM_SAFE_FREE(node->bm_orco_);
MEM_SAFE_FREE(node->bm_ortri_);
@@ -1016,7 +1019,7 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
*/
static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
const float max_edge_len,
Tree &pbvh,
MutableSpan<BMeshNode> nodes,
const float center[3],
const float view_normal[3],
float radius,
@@ -1051,7 +1054,7 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
pbvh_bmesh_edge_tag_verify(pbvh);
#endif
for (Node &node : pbvh.nodes_) {
for (BMeshNode &node : nodes) {
/* Check leaf nodes marked for topology update. */
if ((node.flag_ & PBVH_Leaf) && (node.flag_ & PBVH_UpdateTopology) &&
!(node.flag_ & PBVH_FullyHidden))
@@ -1075,7 +1078,7 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
*/
static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
const float min_edge_len,
Tree &pbvh,
MutableSpan<BMeshNode> nodes,
const float center[3],
const float view_normal[3],
float radius,
@@ -1106,7 +1109,7 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
}
for (Node &node : pbvh.nodes_) {
for (BMeshNode &node : nodes) {
/* Check leaf nodes marked for topology update */
if ((node.flag_ & PBVH_Leaf) && (node.flag_ & PBVH_UpdateTopology) &&
!(node.flag_ & PBVH_FullyHidden))
@@ -1147,7 +1150,7 @@ static void merge_edge_data(BMesh &bm, BMEdge &dst, const BMEdge &src)
static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
BMesh &bm,
Tree &pbvh,
MutableSpan<BMeshNode> nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
BMLog &bm_log,
@@ -1165,7 +1168,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
BMVert *v_new = pbvh_bmesh_vert_create(bm,
pbvh,
nodes,
bm_log,
e->v1,
e->v2,
@@ -1192,7 +1195,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
BMVert *v2 = l_adj->next->v;
if (ni != node_index && i == 0) {
pbvh_bmesh_vert_ownership_transfer(pbvh, cd_vert_node_offset, &pbvh.nodes_[ni], v_new);
pbvh_bmesh_vert_ownership_transfer(nodes, cd_vert_node_offset, &nodes[ni], v_new);
}
/* The 2 new faces created and assigned to `f_new` have their
@@ -1226,7 +1229,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
copy_edge_data(bm, *first_edges[0], *e);
BMFace *f_new_first = pbvh_bmesh_face_create(
bm, pbvh, cd_face_node_offset, bm_log, ni, first_tri, first_edges, f_adj);
bm, nodes, cd_face_node_offset, bm_log, ni, first_tri, first_edges, f_adj);
long_edge_queue_face_add(eq_ctx, f_new_first);
/* Create second face (v_new, v2, v_opp). */
@@ -1239,16 +1242,16 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
copy_edge_data(bm, *second_edges[0], *e);
BMFace *f_new_second = pbvh_bmesh_face_create(
bm, pbvh, cd_face_node_offset, bm_log, ni, second_tri, second_edges, f_adj);
bm, nodes, cd_face_node_offset, bm_log, ni, second_tri, second_edges, f_adj);
long_edge_queue_face_add(eq_ctx, f_new_second);
/* Delete original */
pbvh_bmesh_face_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log, f_adj);
pbvh_bmesh_face_remove(nodes, cd_vert_node_offset, cd_face_node_offset, bm_log, f_adj);
BM_face_kill(&bm, f_adj);
/* Ensure new vertex is in the node */
if (!pbvh.nodes_[ni].bm_unique_verts_.contains(v_new)) {
pbvh.nodes_[ni].bm_other_verts_.add(v_new);
if (!nodes[ni].bm_unique_verts_.contains(v_new)) {
nodes[ni].bm_other_verts_.add(v_new);
}
if (BM_vert_edge_count_is_over(v_opp, 8)) {
@@ -1265,7 +1268,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
BMesh &bm,
Tree &pbvh,
MutableSpan<BMeshNode> nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
BMLog &bm_log)
@@ -1305,7 +1308,7 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
any_subdivided = true;
pbvh_bmesh_split_edge(eq_ctx, bm, pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log, e);
pbvh_bmesh_split_edge(eq_ctx, bm, nodes, cd_vert_node_offset, cd_face_node_offset, bm_log, e);
}
#ifdef USE_EDGEQUEUE_TAG_VERIFY
@@ -1563,7 +1566,7 @@ static void merge_face_edge_data(BMesh &bm,
}
static void pbvh_bmesh_collapse_edge(BMesh &bm,
Tree &pbvh,
MutableSpan<BMeshNode> nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
BMLog &bm_log,
@@ -1606,7 +1609,7 @@ static void pbvh_bmesh_collapse_edge(BMesh &bm,
}
/* Remove the merge vertex from the Tree. */
pbvh_bmesh_vert_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, v_del);
pbvh_bmesh_vert_remove(nodes, cd_vert_node_offset, cd_face_node_offset, v_del);
/* For all remaining faces of v_del, create a new face that is the
* same except it uses v_conn instead of v_del */
@@ -1645,7 +1648,7 @@ static void pbvh_bmesh_collapse_edge(BMesh &bm,
while ((l_adj = e->l)) {
BMFace *f_adj = l_adj->f;
pbvh_bmesh_face_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log, f_adj);
pbvh_bmesh_face_remove(nodes, cd_vert_node_offset, cd_face_node_offset, bm_log, f_adj);
BM_face_kill(&bm, f_adj);
}
@@ -1664,11 +1667,11 @@ static void pbvh_bmesh_collapse_edge(BMesh &bm,
const std::array<BMVert *, 3> v_tri{v_conn, l->next->v, l->prev->v};
BLI_assert(!BM_face_exists(v_tri.data(), 3));
Node *n = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, f);
int ni = n - pbvh.nodes_.data();
BMeshNode *n = pbvh_bmesh_node_from_face(nodes, cd_face_node_offset, f);
int ni = n - nodes.data();
const std::array<BMEdge *, 3> e_tri = bm_edges_from_tri(bm, v_tri);
BMFace *new_face = pbvh_bmesh_face_create(
bm, pbvh, cd_face_node_offset, bm_log, ni, v_tri, e_tri, f);
bm, nodes, cd_face_node_offset, bm_log, ni, v_tri, e_tri, f);
merge_face_edge_data(bm, f, new_face, v_del, l, v_conn);
@@ -1694,7 +1697,7 @@ static void pbvh_bmesh_collapse_edge(BMesh &bm,
try_merge_flap_edge_data_before_dissolve(bm, *f_del);
/* Remove the face */
pbvh_bmesh_face_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log, f_del);
pbvh_bmesh_face_remove(nodes, cd_vert_node_offset, cd_face_node_offset, bm_log, f_del);
BM_face_kill(&bm, f_del);
/* Check if any of the face's edges are now unused by any
@@ -1709,7 +1712,7 @@ static void pbvh_bmesh_collapse_edge(BMesh &bm,
* remove them from the Tree */
for (const int j : IndexRange(3)) {
if ((v_tri[j] != v_del) && (v_tri[j]->e == nullptr)) {
pbvh_bmesh_vert_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, v_tri[j]);
pbvh_bmesh_vert_remove(nodes, cd_vert_node_offset, cd_face_node_offset, v_tri[j]);
BM_log_vert_removed(&bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
@@ -1738,7 +1741,7 @@ static void pbvh_bmesh_collapse_edge(BMesh &bm,
/* Update bounding boxes attached to the connected vertex.
* Note that we can often get-away without this but causes #48779. */
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
Node *f_node = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, l->f);
Node *f_node = pbvh_bmesh_node_from_face(nodes, cd_face_node_offset, l->f);
f_node->flag_ |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
}
BM_LOOPS_OF_VERT_ITER_END;
@@ -1755,7 +1758,7 @@ static void pbvh_bmesh_collapse_edge(BMesh &bm,
static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
const float min_edge_len,
BMesh &bm,
Tree &pbvh,
MutableSpan<BMeshNode> nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
BMLog &bm_log)
@@ -1806,7 +1809,7 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
any_collapsed = true;
pbvh_bmesh_collapse_edge(bm,
pbvh,
nodes,
cd_vert_node_offset,
cd_face_node_offset,
bm_log,
@@ -1826,7 +1829,7 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
/************************* Called from pbvh.cc *************************/
bool bmesh_node_raycast(Node &node,
bool bmesh_node_raycast(BMeshNode &node,
const float ray_start[3],
const float ray_normal[3],
IsectRayPrecalc *isect_precalc,
@@ -1907,7 +1910,7 @@ bool bmesh_node_raycast(Node &node,
return hit;
}
bool bmesh_node_raycast_detail(Node &node,
bool bmesh_node_raycast_detail(BMeshNode &node,
const float ray_start[3],
IsectRayPrecalc *isect_precalc,
float *depth,
@@ -1950,7 +1953,7 @@ bool bmesh_node_raycast_detail(Node &node,
return hit;
}
bool bmesh_node_nearest_to_ray(Node &node,
bool bmesh_node_nearest_to_ray(BMeshNode &node,
const float ray_start[3],
const float ray_normal[3],
float *depth,
@@ -1987,22 +1990,24 @@ bool bmesh_node_nearest_to_ray(Node &node,
return hit;
}
void bmesh_normals_update(Span<Node *> nodes)
void bmesh_normals_update(Tree &pbvh, const IndexMask &nodes_to_update)
{
for (Node *node : nodes) {
if (node->flag_ & PBVH_UpdateNormals) {
for (BMFace *face : node->bm_faces_) {
const MutableSpan<BMeshNode> nodes = pbvh.nodes<BMeshNode>();
nodes_to_update.foreach_index([&](const int i) {
BMeshNode &node = nodes[i];
if (node.flag_ & PBVH_UpdateNormals) {
for (BMFace *face : node.bm_faces_) {
BM_face_normal_update(face);
}
for (BMVert *vert : node->bm_unique_verts_) {
for (BMVert *vert : node.bm_unique_verts_) {
BM_vert_normal_update(vert);
}
for (BMVert *vert : node->bm_other_verts_) {
for (BMVert *vert : node.bm_other_verts_) {
BM_vert_normal_update(vert);
}
node->flag_ &= ~PBVH_UpdateNormals;
node.flag_ &= ~PBVH_UpdateNormals;
}
}
});
}
struct FastNodeBuildInfo {
@@ -2017,8 +2022,7 @@ struct FastNodeBuildInfo {
* This function is multi-thread-able since each invocation applies
* to a sub part of the arrays.
*/
static void pbvh_bmesh_node_limit_ensure_fast(Tree *pbvh,
const MutableSpan<BMFace *> nodeinfo,
static void pbvh_bmesh_node_limit_ensure_fast(const MutableSpan<BMFace *> nodeinfo,
const Span<Bounds<float3>> face_bounds,
FastNodeBuildInfo *node,
MemArena *arena)
@@ -2114,11 +2118,11 @@ static void pbvh_bmesh_node_limit_ensure_fast(Tree *pbvh,
child2->start = node->start + num_child1;
child1->child1 = child1->child2 = child2->child1 = child2->child2 = nullptr;
pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, face_bounds, child1, arena);
pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, face_bounds, child2, arena);
pbvh_bmesh_node_limit_ensure_fast(nodeinfo, face_bounds, child1, arena);
pbvh_bmesh_node_limit_ensure_fast(nodeinfo, face_bounds, child2, arena);
}
static void pbvh_bmesh_create_nodes_fast_recursive(Tree *pbvh,
static void pbvh_bmesh_create_nodes_fast_recursive(Vector<BMeshNode> &nodes,
const int cd_vert_node_offset,
const int cd_face_node_offset,
const Span<BMFace *> nodeinfo,
@@ -2126,21 +2130,21 @@ static void pbvh_bmesh_create_nodes_fast_recursive(Tree *pbvh,
FastNodeBuildInfo *node,
int node_index)
{
Node *n = &pbvh->nodes_[node_index];
BMeshNode *n = &nodes[node_index];
/* Two cases, node does not have children or does have children. */
if (node->child1) {
int children_offset_ = pbvh->nodes_.size();
int children_offset_ = nodes.size();
n->children_offset_ = children_offset_;
pbvh->nodes_.resize(pbvh->nodes_.size() + 2);
pbvh_bmesh_create_nodes_fast_recursive(pbvh,
nodes.resize(nodes.size() + 2);
pbvh_bmesh_create_nodes_fast_recursive(nodes,
cd_vert_node_offset,
cd_face_node_offset,
nodeinfo,
face_bounds,
node->child1,
children_offset_);
pbvh_bmesh_create_nodes_fast_recursive(pbvh,
pbvh_bmesh_create_nodes_fast_recursive(nodes,
cd_vert_node_offset,
cd_face_node_offset,
nodeinfo,
@@ -2233,21 +2237,21 @@ std::unique_ptr<Tree> build_bmesh(BMesh *bm)
rootnode.totface = bm->totface;
/* Start recursion, assign faces to nodes accordingly. */
pbvh_bmesh_node_limit_ensure_fast(pbvh.get(), nodeinfo, face_bounds, &rootnode, arena);
pbvh_bmesh_node_limit_ensure_fast(nodeinfo, face_bounds, &rootnode, arena);
/* We now have all faces assigned to a node,
* next we need to assign those to the gsets of the nodes. */
/* Start with all faces in the root node. */
/* Take root node and visit and populate children recursively. */
pbvh->nodes_.resize(1);
Vector<BMeshNode> &nodes = std::get<Vector<BMeshNode>>(pbvh->nodes_);
nodes.resize(1);
pbvh_bmesh_create_nodes_fast_recursive(
pbvh.get(), cd_vert_node_offset, cd_face_node_offset, nodeinfo, face_bounds, &rootnode, 0);
nodes, cd_vert_node_offset, cd_face_node_offset, nodeinfo, face_bounds, &rootnode, 0);
update_bounds_bmesh(*bm, *pbvh);
store_bounds_orig(*pbvh);
MutableSpan<Node> nodes = pbvh->nodes_;
threading::parallel_for(nodes.index_range(), 8, [&](const IndexRange range) {
for (const int i : range) {
const Set<BMFace *, 0> &faces = BKE_pbvh_bmesh_node_faces(&nodes[i]);
@@ -2289,6 +2293,8 @@ bool bmesh_update_topology(BMesh &bm,
BLI_assert(len_squared_v3(view_normal) != 0.0f);
}
MutableSpan<BMeshNode> nodes = pbvh.nodes<BMeshNode>();
if (mode & PBVH_Collapse) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *) * 2, 0, 128, BLI_MEMPOOL_NOP);
@@ -2302,9 +2308,9 @@ bool bmesh_update_topology(BMesh &bm,
};
short_edge_queue_create(
&eq_ctx, min_edge_len, pbvh, center, view_normal, radius, use_frontface, use_projected);
&eq_ctx, min_edge_len, nodes, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_collapse_short_edges(
&eq_ctx, min_edge_len, bm, pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log);
&eq_ctx, min_edge_len, bm, nodes, cd_vert_node_offset, cd_face_node_offset, bm_log);
BLI_heapsimple_free(q.heap, nullptr);
BLI_mempool_destroy(queue_pool);
}
@@ -2322,22 +2328,22 @@ bool bmesh_update_topology(BMesh &bm,
};
long_edge_queue_create(
&eq_ctx, max_edge_len, pbvh, center, view_normal, radius, use_frontface, use_projected);
&eq_ctx, max_edge_len, nodes, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_subdivide_long_edges(
&eq_ctx, bm, pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log);
&eq_ctx, bm, nodes, cd_vert_node_offset, cd_face_node_offset, bm_log);
BLI_heapsimple_free(q.heap, nullptr);
BLI_mempool_destroy(queue_pool);
}
/* Unmark nodes. */
for (Node &node : pbvh.nodes_) {
for (Node &node : nodes) {
if (node.flag_ & PBVH_Leaf && node.flag_ & PBVH_UpdateTopology) {
node.flag_ &= ~PBVH_UpdateTopology;
}
}
/* Go over all changed nodes and check if anything needs to be updated. */
for (Node &node : pbvh.nodes_) {
for (BMeshNode &node : nodes) {
if (node.flag_ & PBVH_Leaf && node.flag_ & PBVH_TopologyUpdated) {
node.flag_ &= ~PBVH_TopologyUpdated;
@@ -2362,7 +2368,7 @@ bool bmesh_update_topology(BMesh &bm,
* BMesh vertex. Attempts to retrieve the value from the BMLog, falls back to the vertex's current
* coordinates if it is either not found in the log or not requested. */
static void BKE_pbvh_bmesh_node_copy_original_co(
BMLog *log, blender::bke::pbvh::Node *node, BMVert *v, int i, bool use_original)
BMLog *log, blender::bke::pbvh::BMeshNode *node, BMVert *v, int i, bool use_original)
{
if (!use_original) {
copy_v3_v3(node->bm_orco_[i], v->co);
@@ -2383,7 +2389,7 @@ static void BKE_pbvh_bmesh_node_copy_original_co(
void BKE_pbvh_bmesh_node_save_orig(BMesh *bm,
BMLog *log,
blender::bke::pbvh::Node *node,
blender::bke::pbvh::BMeshNode *node,
bool use_original)
{
/* Skip if original coords/triangles are already saved. */
@@ -2429,19 +2435,22 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm,
void BKE_pbvh_bmesh_after_stroke(BMesh &bm, blender::bke::pbvh::Tree &pbvh)
{
using namespace blender;
const int cd_vert_node_offset = CustomData_get_offset_named(
&bm.vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex");
const int cd_face_node_offset = CustomData_get_offset_named(
&bm.pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face");
const int totnode = pbvh.nodes_.size();
for (int i = 0; i < totnode; i++) {
blender::bke::pbvh::Node *n = &pbvh.nodes_[i];
Vector<bke::pbvh::BMeshNode> &nodes = std::get<Vector<bke::pbvh::BMeshNode>>(pbvh.nodes_);
const IndexRange orig_range = nodes.index_range();
for (const int i : orig_range) {
bke::pbvh::BMeshNode *n = &nodes[i];
if (n->flag_ & PBVH_Leaf) {
/* Free orco/ortri data. */
pbvh_bmesh_node_drop_orig(n);
/* Recursively split nodes that have gotten too many elements. */
pbvh_bmesh_node_limit_ensure(bm, pbvh, cd_vert_node_offset, cd_face_node_offset, i);
pbvh_bmesh_node_limit_ensure(bm, nodes, cd_vert_node_offset, cd_face_node_offset, i);
}
}
}
@@ -2451,17 +2460,19 @@ void BKE_pbvh_node_mark_topology_update(blender::bke::pbvh::Node &node)
node.flag_ |= PBVH_UpdateTopology;
}
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::Node *node)
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_unique_verts(
blender::bke::pbvh::BMeshNode *node)
{
return node->bm_unique_verts_;
}
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_other_verts(blender::bke::pbvh::Node *node)
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_other_verts(
blender::bke::pbvh::BMeshNode *node)
{
return node->bm_other_verts_;
}
const blender::Set<BMFace *, 0> &BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::Node *node)
const blender::Set<BMFace *, 0> &BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::BMeshNode *node)
{
return node->bm_faces_;
}

View File

@@ -46,7 +46,7 @@ bool ray_face_nearest_tri(const float ray_start[3],
/* pbvh_bmesh.cc */
bool bmesh_node_raycast(blender::bke::pbvh::Node &node,
bool bmesh_node_raycast(blender::bke::pbvh::BMeshNode &node,
const float ray_start[3],
const float ray_normal[3],
IsectRayPrecalc *isect_precalc,
@@ -54,14 +54,14 @@ bool bmesh_node_raycast(blender::bke::pbvh::Node &node,
bool use_original,
PBVHVertRef *r_active_vertex,
float *r_face_normal);
bool bmesh_node_nearest_to_ray(blender::bke::pbvh::Node &node,
bool bmesh_node_nearest_to_ray(blender::bke::pbvh::BMeshNode &node,
const float ray_start[3],
const float ray_normal[3],
float *depth,
float *dist_sq,
bool use_original);
void bmesh_normals_update(Span<blender::bke::pbvh::Node *> nodes);
void bmesh_normals_update(Tree &pbvh, const IndexMask &nodes_to_update);
/* pbvh_pixels.hh */

View File

@@ -147,7 +147,7 @@ static void do_encode_pixels(const uv_islands::MeshData &mesh_data,
const UVPrimitiveLookup &uv_prim_lookup,
Image &image,
ImageUser &image_user,
Node &node)
MeshNode &node)
{
NodeData *node_data = static_cast<NodeData *>(node.pixels_);
@@ -234,7 +234,7 @@ static bool should_pixels_be_updated(const Node &node)
static int count_nodes_to_update(Tree &pbvh)
{
int result = 0;
for (Node &node : pbvh.nodes_) {
for (Node &node : pbvh.nodes<MeshNode>()) {
if (should_pixels_be_updated(node)) {
result++;
}
@@ -251,7 +251,7 @@ static int count_nodes_to_update(Tree &pbvh)
*
* returns if there were any nodes found (true).
*/
static bool find_nodes_to_update(Tree &pbvh, Vector<Node *> &r_nodes_to_update)
static bool find_nodes_to_update(Tree &pbvh, Vector<MeshNode *> &r_nodes_to_update)
{
int nodes_to_update_len = count_nodes_to_update(pbvh);
if (nodes_to_update_len == 0) {
@@ -270,7 +270,7 @@ static bool find_nodes_to_update(Tree &pbvh, Vector<Node *> &r_nodes_to_update)
r_nodes_to_update.reserve(nodes_to_update_len);
for (Node &node : pbvh.nodes_) {
for (MeshNode &node : pbvh.nodes<MeshNode>()) {
if (!should_pixels_be_updated(node)) {
continue;
}
@@ -300,7 +300,7 @@ static void apply_watertight_check(Tree &pbvh, Image &image, ImageUser &image_us
if (image_buffer == nullptr) {
continue;
}
for (Node &node : pbvh.nodes_) {
for (Node &node : pbvh.nodes<MeshNode>()) {
if ((node.flag_ & PBVH_Leaf) == 0) {
continue;
}
@@ -336,7 +336,7 @@ static bool update_pixels(const Depsgraph &depsgraph,
Image &image,
ImageUser &image_user)
{
Vector<Node *> nodes_to_update;
Vector<MeshNode *> nodes_to_update;
if (!find_nodes_to_update(pbvh, nodes_to_update)) {
return false;
}
@@ -404,7 +404,7 @@ static bool update_pixels(const Depsgraph &depsgraph,
}
/* Add PBVH_TexLeaf flag */
for (Node &node : pbvh.nodes_) {
for (Node &node : pbvh.nodes<MeshNode>()) {
if (node.flag_ & PBVH_Leaf) {
node.flag_ = (PBVHNodeFlags)(int(node.flag_) | int(PBVH_TexLeaf));
}

View File

@@ -173,13 +173,17 @@ class PixelNodesTileData : public Vector<std::reference_wrapper<UDIMTilePixels>>
{
reserve(count_nodes(pbvh, image_tile));
for (blender::bke::pbvh::Node &node : pbvh.nodes_) {
if (should_add_node(node, image_tile)) {
NodeData &node_data = *static_cast<NodeData *>(node.pixels_);
UDIMTilePixels &tile_pixels = *node_data.find_tile_data(image_tile);
append(tile_pixels);
}
}
std::visit(
[&](auto &nodes) {
for (blender::bke::pbvh::Node &node : nodes) {
if (should_add_node(node, image_tile)) {
NodeData &node_data = *static_cast<NodeData *>(node.pixels_);
UDIMTilePixels &tile_pixels = *node_data.find_tile_data(image_tile);
append(tile_pixels);
}
}
},
pbvh.nodes_);
}
private:
@@ -203,11 +207,15 @@ class PixelNodesTileData : public Vector<std::reference_wrapper<UDIMTilePixels>>
const image::ImageTileWrapper &image_tile)
{
int64_t result = 0;
for (blender::bke::pbvh::Node &node : pbvh.nodes_) {
if (should_add_node(node, image_tile)) {
result++;
}
}
std::visit(
[&](auto &nodes) {
for (blender::bke::pbvh::Node &node : nodes) {
if (should_add_node(node, image_tile)) {
result++;
}
}
},
pbvh.nodes_);
return result;
}
};

View File

@@ -185,7 +185,7 @@ static void do_draw_face_sets_brush_mesh(const Depsgraph &depsgraph,
MeshLocalData &tls = all_tls.local();
for (const int i : range) {
const Span<int> face_indices = bke::pbvh::node_face_indices_calc_mesh(
corner_tris, *nodes[i], tls.face_indices);
corner_tris, static_cast<bke::pbvh::MeshNode &>(*nodes[i]), tls.face_indices);
undo::push_node(depsgraph, object, nodes[i], undo::Type::FaceSet);

View File

@@ -232,7 +232,7 @@ static void flush_face_changes_node(Mesh &mesh,
TLS &tls = all_tls.local();
for (bke::pbvh::Node *node : nodes.slice(range)) {
const Span<int> node_faces = bke::pbvh::node_face_indices_calc_mesh(
tri_faces, *node, tls.face_indices);
tri_faces, static_cast<bke::pbvh::MeshNode &>(*node), tls.face_indices);
tls.new_hide.resize(node_faces.size());
gather_data_mesh(hide_poly.span.as_span(), node_faces, tls.new_hide.as_mutable_span());
@@ -245,7 +245,7 @@ static void flush_face_changes_node(Mesh &mesh,
scatter_data_mesh(tls.new_hide.as_span(), node_faces, hide_poly.span);
BKE_pbvh_node_mark_update_visibility(*node);
bke::pbvh::node_update_visibility_mesh(hide_vert, *node);
bke::pbvh::node_update_visibility_mesh(hide_vert, static_cast<bke::pbvh::MeshNode &>(*node));
}
});
hide_poly.finish();
@@ -350,7 +350,8 @@ static void grid_hide_update(Depsgraph &depsgraph,
}
BKE_pbvh_node_mark_update_visibility(*node);
bke::pbvh::node_update_visibility_grids(grid_hidden, *node);
bke::pbvh::node_update_visibility_grids(grid_hidden,
static_cast<bke::pbvh::GridsNode &>(*node));
}
});
@@ -705,7 +706,8 @@ static void invert_visibility_mesh(const Depsgraph &depsgraph,
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
Vector<int> &faces = all_index_data.local();
for (bke::pbvh::Node *node : nodes.slice(range)) {
bke::pbvh::node_face_indices_calc_mesh(tri_faces, *node, faces);
bke::pbvh::node_face_indices_calc_mesh(
tri_faces, static_cast<bke::pbvh::MeshNode &>(*node), faces);
for (const int face : faces) {
hide_poly.span[face] = !hide_poly.span[face];
}
@@ -733,7 +735,8 @@ static void invert_visibility_grids(Depsgraph &depsgraph,
bits::invert(grid_hidden[i]);
}
BKE_pbvh_node_mark_update_visibility(*node);
bke::pbvh::node_update_visibility_grids(grid_hidden, *node);
bke::pbvh::node_update_visibility_grids(grid_hidden,
static_cast<bke::pbvh::GridsNode &>(*node));
}
});
@@ -910,7 +913,7 @@ static void update_node_visibility_from_face_changes(const Span<bke::pbvh::Node
for (bke::pbvh::Node *node : nodes.slice(range)) {
bool any_changed = false;
const Span<int> indices = bke::pbvh::node_face_indices_calc_mesh(
tri_faces, *node, face_indices);
tri_faces, static_cast<bke::pbvh::MeshNode &>(*node), face_indices);
for (const int face_index : indices) {
if (orig_hide_poly[face_index] != new_hide_poly[face_index]) {
any_changed = true;
@@ -920,7 +923,8 @@ static void update_node_visibility_from_face_changes(const Span<bke::pbvh::Node
if (any_changed) {
BKE_pbvh_node_mark_update_visibility(*node);
bke::pbvh::node_update_visibility_mesh(hide_vert, *node);
bke::pbvh::node_update_visibility_mesh(hide_vert,
static_cast<bke::pbvh::MeshNode &>(*node));
}
}
});
@@ -1058,7 +1062,8 @@ static void grow_shrink_visibility_grid(Depsgraph &depsgraph,
bke::pbvh::Node *node = nodes[node_index];
BKE_pbvh_node_mark_update_visibility(*node);
bke::pbvh::node_update_visibility_grids(grid_hidden, *node);
bke::pbvh::node_update_visibility_grids(grid_hidden,
static_cast<bke::pbvh::GridsNode &>(*node));
}
});

View File

@@ -282,7 +282,7 @@ void update_mask_mesh(const Depsgraph &depsgraph,
}
undo::push_node(depsgraph, object, node, undo::Type::Mask);
array_utils::scatter<float>(tls.mask, verts, mask.span);
bke::pbvh::node_update_mask_mesh(mask.span, *node);
bke::pbvh::node_update_mask_mesh(mask.span, static_cast<bke::pbvh::MeshNode &>(*node));
BKE_pbvh_node_mark_redraw(*node);
}
});
@@ -630,7 +630,7 @@ static void invert_mask_grids(Main &bmain,
}
}
BKE_pbvh_node_mark_update_mask(*node);
bke::pbvh::node_update_mask_grids(key, grids, *node);
bke::pbvh::node_update_mask_grids(key, grids, static_cast<bke::pbvh::GridsNode &>(*node));
}
});
@@ -657,7 +657,7 @@ static void invert_mask_bmesh(const Depsgraph &depsgraph,
}
}
BKE_pbvh_node_mark_update_mask(*node);
bke::pbvh::node_update_mask_bmesh(offset, *node);
bke::pbvh::node_update_mask_bmesh(offset, static_cast<bke::pbvh::BMeshNode &>(*node));
}
});
}

View File

@@ -1840,7 +1840,7 @@ static void calc_area_normal_and_center_node_bmesh(const Object &object,
const bool use_area_nos,
const bool use_area_cos,
const bool has_bm_orco,
const bke::pbvh::Node &node,
const bke::pbvh::BMeshNode &node,
SampleLocalData &tls,
AreaNormalCenterData &anctd)
{
@@ -1869,8 +1869,11 @@ static void calc_area_normal_and_center_node_bmesh(const Object &object,
float(*orco_coords)[3];
int(*orco_tris)[3];
int orco_tris_num;
BKE_pbvh_node_get_bm_orco_data(
&const_cast<bke::pbvh::Node &>(node), &orco_tris, &orco_tris_num, &orco_coords, nullptr);
BKE_pbvh_node_get_bm_orco_data(&const_cast<bke::pbvh::BMeshNode &>(node),
&orco_tris,
&orco_tris_num,
&orco_coords,
nullptr);
tls.positions.resize(orco_tris_num);
const MutableSpan<float3> positions = tls.positions;
@@ -1912,7 +1915,7 @@ static void calc_area_normal_and_center_node_bmesh(const Object &object,
}
const Set<BMVert *, 0> &verts = BKE_pbvh_bmesh_node_unique_verts(
&const_cast<bke::pbvh::Node &>(node));
&const_cast<bke::pbvh::BMeshNode &>(node));
if (use_original) {
tls.positions.resize(verts.size());
const MutableSpan<float3> positions = tls.positions;
@@ -2055,7 +2058,14 @@ void calc_area_center(const Depsgraph &depsgraph,
SampleLocalData &tls = all_tls.local();
for (const int i : range) {
calc_area_normal_and_center_node_bmesh(
ob, brush, false, true, has_bm_orco, *nodes[i], tls, anctd);
ob,
brush,
false,
true,
has_bm_orco,
static_cast<const blender::bke::pbvh::BMeshNode &>(*nodes[i]),
tls,
anctd);
}
return anctd;
},
@@ -2152,7 +2162,14 @@ std::optional<float3> calc_area_normal(const Depsgraph &depsgraph,
SampleLocalData &tls = all_tls.local();
for (const int i : range) {
calc_area_normal_and_center_node_bmesh(
ob, brush, true, false, has_bm_orco, *nodes[i], tls, anctd);
ob,
brush,
true,
false,
has_bm_orco,
static_cast<const blender::bke::pbvh::BMeshNode &>(*nodes[i]),
tls,
anctd);
}
return anctd;
},
@@ -2241,7 +2258,14 @@ void calc_area_normal_and_center(const Depsgraph &depsgraph,
SampleLocalData &tls = all_tls.local();
for (const int i : range) {
calc_area_normal_and_center_node_bmesh(
ob, brush, true, true, has_bm_orco, *nodes[i], tls, anctd);
ob,
brush,
true,
true,
has_bm_orco,
static_cast<const blender::bke::pbvh::BMeshNode &>(*nodes[i]),
tls,
anctd);
}
return anctd;
},
@@ -3237,7 +3261,8 @@ static void dynamic_topology_update(const Depsgraph &depsgraph,
BKE_pbvh_node_mark_update(*node);
BKE_pbvh_node_mark_topology_update(*node);
BKE_pbvh_bmesh_node_save_orig(ss.bm, ss.bm_log, node, false);
BKE_pbvh_bmesh_node_save_orig(
ss.bm, ss.bm_log, static_cast<blender::bke::pbvh::BMeshNode *>(node), false);
}
float max_edge_len;

View File

@@ -227,7 +227,7 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2])
mesh.remesh_voxel_size = edge_length / float(neighbors.size());
}
static void sculpt_raycast_detail_cb(bke::pbvh::Node &node,
static void sculpt_raycast_detail_cb(bke::pbvh::BMeshNode &node,
SculptDetailRaycastData &srd,
float *tmin)
{
@@ -262,7 +262,9 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, const int mval[2
bke::pbvh::raycast(
*ob.sculpt->pbvh,
[&](bke::pbvh::Node &node, float *tmin) { sculpt_raycast_detail_cb(node, srd, tmin); },
[&](bke::pbvh::Node &node, float *tmin) {
sculpt_raycast_detail_cb(static_cast<bke::pbvh::BMeshNode &>(node), srd, tmin);
},
ray_start,
ray_normal,
false);

View File

@@ -305,8 +305,10 @@ static void face_sets_update(const Depsgraph &depsgraph,
for (bke::pbvh::Node *node : nodes.slice(range)) {
const Span<int> faces =
pbvh.type() == bke::pbvh::Type::Mesh ?
bke::pbvh::node_face_indices_calc_mesh(tri_faces, *node, tls.face_indices) :
bke::pbvh::node_face_indices_calc_grids(*ss.subdiv_ccg, *node, tls.face_indices);
bke::pbvh::node_face_indices_calc_mesh(
tri_faces, static_cast<bke::pbvh::MeshNode &>(*node), tls.face_indices) :
bke::pbvh::node_face_indices_calc_grids(
*ss.subdiv_ccg, static_cast<bke::pbvh::GridsNode &>(*node), tls.face_indices);
tls.new_face_sets.resize(faces.size());
MutableSpan<int> new_face_sets = tls.new_face_sets;
@@ -352,8 +354,10 @@ static void clear_face_sets(const Depsgraph &depsgraph,
for (bke::pbvh::Node *node : nodes.slice(range)) {
const Span<int> faces =
pbvh.type() == bke::pbvh::Type::Mesh ?
bke::pbvh::node_face_indices_calc_mesh(tri_faces, *node, face_indices) :
bke::pbvh::node_face_indices_calc_grids(*ss.subdiv_ccg, *node, face_indices);
bke::pbvh::node_face_indices_calc_mesh(
tri_faces, static_cast<bke::pbvh::MeshNode &>(*node), face_indices) :
bke::pbvh::node_face_indices_calc_grids(
*ss.subdiv_ccg, static_cast<bke::pbvh::GridsNode &>(*node), face_indices);
if (std::any_of(faces.begin(), faces.end(), [&](const int face) {
return face_sets[face] != default_face_set;
}))
@@ -847,8 +851,10 @@ static void face_hide_update(const Depsgraph &depsgraph,
for (bke::pbvh::Node *node : nodes.slice(range)) {
const Span<int> faces =
pbvh.type() == bke::pbvh::Type::Mesh ?
bke::pbvh::node_face_indices_calc_mesh(tri_faces, *node, tls.face_indices) :
bke::pbvh::node_face_indices_calc_grids(*ss.subdiv_ccg, *node, tls.face_indices);
bke::pbvh::node_face_indices_calc_mesh(
tri_faces, static_cast<bke::pbvh::MeshNode &>(*node), tls.face_indices) :
bke::pbvh::node_face_indices_calc_grids(
*ss.subdiv_ccg, static_cast<bke::pbvh::GridsNode &>(*node), tls.face_indices);
tls.new_hide.resize(faces.size());
MutableSpan<bool> new_hide = tls.new_hide;
@@ -1585,8 +1591,10 @@ static void gesture_apply_mesh(gesture::GestureData &gesture_data,
undo::push_node(depsgraph, *gesture_data.vc.obact, node, undo::Type::FaceSet);
const Span<int> node_faces =
pbvh.type() == bke::pbvh::Type::Mesh ?
bke::pbvh::node_face_indices_calc_mesh(tri_faces, *node, tls.face_indices) :
bke::pbvh::node_face_indices_calc_grids(*ss.subdiv_ccg, *node, tls.face_indices);
bke::pbvh::node_face_indices_calc_mesh(
tri_faces, static_cast<bke::pbvh::MeshNode &>(*node), tls.face_indices) :
bke::pbvh::node_face_indices_calc_grids(
*ss.subdiv_ccg, static_cast<bke::pbvh::GridsNode &>(*node), tls.face_indices);
bool any_updated = false;
for (const int face : node_faces) {

View File

@@ -70,7 +70,7 @@ void write_mask_mesh(const Depsgraph &depsgraph,
for (const int i : range) {
write_fn(mask.span, hide::node_visible_verts(*nodes[i], hide_vert, index_data));
BKE_pbvh_node_mark_redraw(*nodes[i]);
bke::pbvh::node_update_mask_mesh(mask.span, *nodes[i]);
bke::pbvh::node_update_mask_mesh(mask.span, static_cast<bke::pbvh::MeshNode &>(*nodes[i]));
}
});
mask.finish();

View File

@@ -1168,7 +1168,8 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
for (const int i : range) {
bake_mask_mesh(*depsgraph, ob, *automasking, mode, factor, *nodes[i], tls, mask.span);
BKE_pbvh_node_mark_update_mask(*nodes[i]);
bke::pbvh::node_update_mask_mesh(mask.span, *nodes[i]);
bke::pbvh::node_update_mask_mesh(mask.span,
static_cast<bke::pbvh::MeshNode &>(*nodes[i]));
}
});
});

View File

@@ -966,7 +966,7 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
for (bke::pbvh::Node *node : nodes) {
faces_vector.clear();
const Span<int> faces = bke::pbvh::node_face_indices_calc_grids(
subdiv_ccg, *node, faces_vector);
subdiv_ccg, static_cast<bke::pbvh::GridsNode &>(*node), faces_vector);
if (indices_contain_true(modified_faces, faces)) {
BKE_pbvh_node_mark_update_visibility(*node);
}
@@ -978,7 +978,7 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
for (bke::pbvh::Node *node : nodes) {
faces_vector.clear();
const Span<int> faces = bke::pbvh::node_face_indices_calc_mesh(
tri_faces, *node, faces_vector);
tri_faces, static_cast<bke::pbvh::MeshNode &>(*node), faces_vector);
if (indices_contain_true(modified_faces, faces)) {
BKE_pbvh_node_mark_update_visibility(*node);
}
@@ -1041,7 +1041,7 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
for (bke::pbvh::Node *node : nodes) {
faces_vector.clear();
const Span<int> faces = bke::pbvh::node_face_indices_calc_grids(
subdiv_ccg, *node, faces_vector);
subdiv_ccg, static_cast<bke::pbvh::GridsNode &>(*node), faces_vector);
if (indices_contain_true(modified_faces, faces)) {
BKE_pbvh_node_mark_update_face_sets(*node);
}
@@ -1053,7 +1053,7 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
for (bke::pbvh::Node *node : nodes) {
faces_vector.clear();
const Span<int> faces = bke::pbvh::node_face_indices_calc_mesh(
tri_faces, *node, faces_vector);
tri_faces, static_cast<bke::pbvh::MeshNode &>(*node), faces_vector);
if (indices_contain_true(modified_faces, faces)) {
BKE_pbvh_node_mark_update_face_sets(*node);
}
@@ -1280,7 +1280,7 @@ static void store_color(const Object &object, const bke::pbvh::Node &node, Node
faces, corner_verts, vert_to_face_map, colors, color_attribute.domain, verts, unode.col);
if (color_attribute.domain == bke::AttrDomain::Corner) {
unode.corner_indices = bke::pbvh::node_corners(node);
unode.corner_indices = bke::pbvh::node_corners(static_cast<const bke::pbvh::MeshNode &>(node));
unode.loop_col.reinitialize(unode.corner_indices.size());
color::gather_colors(colors, unode.corner_indices, unode.loop_col);
}
@@ -1346,16 +1346,20 @@ static void fill_node_data(const Depsgraph &depsgraph,
const bool need_faces = ELEM(type, Type::FaceSet, Type::HideFace);
if (need_loops) {
unode.corner_indices = bke::pbvh::node_corners(*node);
unode.corner_indices = bke::pbvh::node_corners(
static_cast<const bke::pbvh::MeshNode &>(*node));
}
if (need_faces) {
if (ss.pbvh->type() == bke::pbvh::Type::Mesh) {
bke::pbvh::node_face_indices_calc_mesh(mesh.corner_tri_faces(), *node, unode.face_indices);
bke::pbvh::node_face_indices_calc_mesh(mesh.corner_tri_faces(),
static_cast<const bke::pbvh::MeshNode &>(*node),
unode.face_indices);
}
else {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
bke::pbvh::node_face_indices_calc_grids(subdiv_ccg, *node, unode.face_indices);
bke::pbvh::node_face_indices_calc_grids(
subdiv_ccg, static_cast<const bke::pbvh::GridsNode &>(*node), unode.face_indices);
}
}