Subdiv: Store multires sculpt grid visibility in BitGroupVector #115687
|
@ -224,7 +224,7 @@ bool BKE_paint_always_hide_test(const Object *ob);
|
|||
* Returns non-zero if any of the corners of the grid
|
||||
* face whose inner corner is at (x, y) are hidden, zero otherwise.
|
||||
*/
|
||||
bool paint_is_grid_face_hidden(const unsigned int *grid_hidden, int gridsize, int x, int y);
|
||||
bool paint_is_grid_face_hidden(blender::BoundedBitSpan grid_hidden, int gridsize, int x, int y);
|
||||
/**
|
||||
* Return true if all vertices in the face are visible, false otherwise.
|
||||
*/
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_bit_group_vector.hh"
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_index_mask.hh"
|
||||
|
@ -320,7 +320,7 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *me);
|
|||
/**
|
||||
* Returns the number of visible quads in the nodes' grids.
|
||||
*/
|
||||
int BKE_pbvh_count_grid_quads(blender::Span<const BLI_bitmap *> grid_hidden,
|
||||
int BKE_pbvh_count_grid_quads(const blender::BitGroupVector<> &grid_visibility,
|
||||
const int *grid_indices,
|
||||
int totgrid,
|
||||
int gridsize,
|
||||
|
@ -464,7 +464,8 @@ struct PBVHVertexIter {
|
|||
CCGKey key;
|
||||
CCGElem *const *grids;
|
||||
CCGElem *grid;
|
||||
BLI_bitmap *const *grid_hidden, *gh;
|
||||
const blender::BitGroupVector<> *grid_hidden;
|
||||
std::optional<blender::BoundedBitSpan> gh;
|
||||
const int *grid_indices;
|
||||
int totgrid;
|
||||
int gridsize;
|
||||
|
@ -508,7 +509,12 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
|||
vi.index = vi.vertex.i = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
|
||||
vi.grid = CCG_elem_offset(&vi.key, vi.grids[vi.grid_indices[vi.g]], -1); \
|
||||
if (mode == PBVH_ITER_UNIQUE) { \
|
||||
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
|
||||
if (vi.grid_hidden) { \
|
||||
vi.gh.emplace((*vi.grid_hidden)[vi.grid_indices[vi.g]]); \
|
||||
} \
|
||||
else { \
|
||||
vi.gh.reset(); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
|
@ -527,7 +533,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
|||
vi.vertex.i++; \
|
||||
vi.visible = true; \
|
||||
if (vi.gh) { \
|
||||
if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) { \
|
||||
if ((*vi.gh)[vi.gy * vi.gridsize + vi.gx]) { \
|
||||
continue; \
|
||||
} \
|
||||
} \
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_bit_group_vector.hh"
|
||||
#include "BLI_offset_indices.hh"
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
|
@ -171,7 +171,9 @@ struct SubdivCCG {
|
|||
blender::Array<SubdivCCGAdjacentVertex> adjacent_verts;
|
||||
|
||||
blender::Array<DMFlagMat> grid_flag_mats;
|
||||
blender::Array<BLI_bitmap *> grid_hidden;
|
||||
|
||||
/** Store the visibility of the items in each grid. If empty, everything is visible. */
|
||||
blender::BitGroupVector<> grid_hidden;
|
||||
|
||||
/* TODO(sergey): Consider adding some accessors to a "decoded" geometry,
|
||||
* to make integration with draw manager and such easy.
|
||||
|
@ -315,5 +317,5 @@ SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
|
|||
const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG &subdiv_ccg);
|
||||
const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG &subdiv_ccg);
|
||||
|
||||
void BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG &subdiv_ccg, int grid_index);
|
||||
void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG &subdiv_ccg, int grid_index);
|
||||
blender::BitGroupVector<> &BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG &subdiv_ccg);
|
||||
void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG &subdiv_ccg);
|
||||
|
|
|
@ -1282,13 +1282,14 @@ void BKE_paint_blend_read_data(BlendDataReader *reader, const Scene *scene, Pain
|
|||
BKE_paint_runtime_init(scene->toolsettings, p);
|
||||
}
|
||||
|
||||
bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int y)
|
||||
bool paint_is_grid_face_hidden(const blender::BoundedBitSpan grid_hidden,
|
||||
int gridsize,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
/* Skip face if any of its corners are hidden. */
|
||||
return (BLI_BITMAP_TEST(grid_hidden, y * gridsize + x) ||
|
||||
BLI_BITMAP_TEST(grid_hidden, y * gridsize + x + 1) ||
|
||||
BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x + 1) ||
|
||||
BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x));
|
||||
return grid_hidden[y * gridsize + x] || grid_hidden[y * gridsize + x + 1] ||
|
||||
grid_hidden[(y + 1) * gridsize + x + 1] || grid_hidden[(y + 1) * gridsize + x];
|
||||
}
|
||||
|
||||
bool paint_is_bmesh_face_hidden(const BMFace *f)
|
||||
|
@ -2148,32 +2149,24 @@ void BKE_sculpt_sync_face_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg)
|
|||
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
|
||||
".hide_poly", ATTR_DOMAIN_FACE, false);
|
||||
if (hide_poly.is_single() && !hide_poly.get_internal_single()) {
|
||||
/* Nothing is hidden, so we can just remove all visibility bitmaps. */
|
||||
for (const int i : subdiv_ccg->grid_hidden.index_range()) {
|
||||
BKE_subdiv_ccg_grid_hidden_free(*subdiv_ccg, i);
|
||||
}
|
||||
BKE_subdiv_ccg_grid_hidden_free(*subdiv_ccg);
|
||||
return;
|
||||
}
|
||||
|
||||
const OffsetIndices<int> faces = mesh->faces();
|
||||
|
||||
const VArraySpan<bool> hide_poly_span(hide_poly);
|
||||
CCGKey key;
|
||||
BKE_subdiv_ccg_key_top_level(key, *subdiv_ccg);
|
||||
for (int i = 0; i < mesh->totloop; i++) {
|
||||
const int face_index = BKE_subdiv_ccg_grid_to_face_index(*subdiv_ccg, i);
|
||||
const bool is_hidden = hide_poly_span[face_index];
|
||||
|
||||
/* Avoid creating and modifying the grid_hidden bitmap if the base mesh face is visible and
|
||||
* there is not bitmap for the grid. This is because missing grid_hidden implies grid is fully
|
||||
* visible. */
|
||||
if (is_hidden) {
|
||||
BKE_subdiv_ccg_grid_hidden_ensure(*subdiv_ccg, i);
|
||||
BitGroupVector<> &grid_hidden = BKE_subdiv_ccg_grid_hidden_ensure(*subdiv_ccg);
|
||||
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
const bool face_hidden = hide_poly_span[i];
|
||||
for (const int corner : faces[i]) {
|
||||
grid_hidden[corner].set_all(face_hidden);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_bitmap *gh = subdiv_ccg->grid_hidden[i];
|
||||
if (gh) {
|
||||
BLI_bitmap_set_all(gh, is_hidden, key.grid_area);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "pbvh_intern.hh"
|
||||
|
||||
using blender::BitGroupVector;
|
||||
using blender::float3;
|
||||
using blender::MutableSpan;
|
||||
using blender::Span;
|
||||
|
@ -390,14 +391,16 @@ static void update_vb(PBVH *pbvh, PBVHNode *node, const Span<BBC> prim_bbc, int
|
|||
node->orig_vb = node->vb;
|
||||
}
|
||||
|
||||
int BKE_pbvh_count_grid_quads(const Span<const BLI_bitmap *> grid_hidden,
|
||||
int BKE_pbvh_count_grid_quads(const BitGroupVector<> &grid_hidden,
|
||||
const int *grid_indices,
|
||||
int totgrid,
|
||||
int gridsize,
|
||||
int display_gridsize)
|
||||
{
|
||||
const int gridarea = (gridsize - 1) * (gridsize - 1);
|
||||
int totquad = 0;
|
||||
if (grid_hidden.is_empty()) {
|
||||
return gridarea * totgrid;
|
||||
}
|
||||
|
||||
/* grid hidden layer is present, so have to check each grid for
|
||||
* visibility */
|
||||
|
@ -407,22 +410,17 @@ int BKE_pbvh_count_grid_quads(const Span<const BLI_bitmap *> grid_hidden,
|
|||
|
||||
int skip = depth2 < depth1 ? 1 << (depth1 - depth2 - 1) : 1;
|
||||
|
||||
int totquad = 0;
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
const BLI_bitmap *gh = grid_hidden[grid_indices[i]];
|
||||
|
||||
if (gh) {
|
||||
/* grid hidden are present, have to check each element */
|
||||
for (int y = 0; y < gridsize - skip; y += skip) {
|
||||
for (int x = 0; x < gridsize - skip; x += skip) {
|
||||
if (!paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
totquad++;
|
||||
}
|
||||
const blender::BoundedBitSpan gh = grid_hidden[grid_indices[i]];
|
||||
/* grid hidden are present, have to check each element */
|
||||
for (int y = 0; y < gridsize - skip; y += skip) {
|
||||
for (int x = 0; x < gridsize - skip; x += skip) {
|
||||
if (!paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
totquad++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
totquad += gridarea;
|
||||
}
|
||||
}
|
||||
|
||||
return totquad;
|
||||
|
@ -1466,7 +1464,6 @@ static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Mesh &mesh,
|
|||
args.grid_indices = node.prim_indices;
|
||||
args.subdiv_ccg = pbvh.subdiv_ccg;
|
||||
args.grids = pbvh.subdiv_ccg->grids;
|
||||
args.grid_hidden = pbvh.subdiv_ccg->grid_hidden;
|
||||
args.grid_flag_mats = pbvh.subdiv_ccg->grid_flag_mats;
|
||||
args.vert_normals = pbvh.vert_normals;
|
||||
break;
|
||||
|
@ -1662,20 +1659,24 @@ static void pbvh_faces_node_visibility_update(const Mesh &mesh, const Span<PBVHN
|
|||
static void pbvh_grids_node_visibility_update(PBVH *pbvh, const Span<PBVHNode *> nodes)
|
||||
{
|
||||
using namespace blender;
|
||||
const BitGroupVector<> &grid_hidden = pbvh->subdiv_ccg->grid_hidden;
|
||||
if (grid_hidden.is_empty()) {
|
||||
for (PBVHNode *node : nodes) {
|
||||
BKE_pbvh_node_fully_hidden_set(node, false);
|
||||
node->flag &= ~PBVH_UpdateVisibility;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
|
||||
const Span<const BLI_bitmap *> grid_hidden = pbvh->subdiv_ccg->grid_hidden;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
for (const int grid_index : BKE_pbvh_node_get_grid_indices(*node)) {
|
||||
const BLI_bitmap *gh = grid_hidden[grid_index];
|
||||
if (!gh) {
|
||||
BKE_pbvh_node_fully_hidden_set(node, false);
|
||||
return;
|
||||
}
|
||||
const blender::BoundedBitSpan gh = grid_hidden[grid_index];
|
||||
|
||||
for (int y = 0; y < key.grid_size; y++) {
|
||||
for (int x = 0; x < key.grid_size; x++) {
|
||||
if (!BLI_BITMAP_TEST(gh, y * key.grid_size + x)) {
|
||||
if (!gh[y * key.grid_size + x]) {
|
||||
BKE_pbvh_node_fully_hidden_set(node, false);
|
||||
return;
|
||||
}
|
||||
|
@ -2335,7 +2336,7 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh,
|
|||
bool hit = false;
|
||||
float nearest_vertex_co[3] = {0.0};
|
||||
const CCGKey *gridkey = &pbvh->gridkey;
|
||||
const Span<BLI_bitmap *> grid_hidden = pbvh->subdiv_ccg->grid_hidden;
|
||||
const BitGroupVector<> &grid_hidden = pbvh->subdiv_ccg->grid_hidden;
|
||||
const Span<CCGElem *> grids = pbvh->subdiv_ccg->grids;
|
||||
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
|
@ -2345,13 +2346,11 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh,
|
|||
continue;
|
||||
}
|
||||
|
||||
const BLI_bitmap *gh = grid_hidden[grid_index];
|
||||
|
||||
for (int y = 0; y < gridsize - 1; y++) {
|
||||
for (int x = 0; x < gridsize - 1; x++) {
|
||||
/* check if grid face is hidden */
|
||||
if (gh) {
|
||||
if (paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
if (!grid_hidden.is_empty()) {
|
||||
if (paint_is_grid_face_hidden(grid_hidden[grid_index], gridsize, x, y)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -2665,7 +2664,7 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *pbvh,
|
|||
const int totgrid = node->prim_indices.size();
|
||||
const int gridsize = pbvh->gridkey.grid_size;
|
||||
bool hit = false;
|
||||
const Span<BLI_bitmap *> grid_hidden = pbvh->subdiv_ccg->grid_hidden;
|
||||
const BitGroupVector<> &grid_hidden = pbvh->subdiv_ccg->grid_hidden;
|
||||
const Span<CCGElem *> grids = pbvh->subdiv_ccg->grids;
|
||||
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
|
@ -2674,13 +2673,11 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *pbvh,
|
|||
continue;
|
||||
}
|
||||
|
||||
const BLI_bitmap *gh = grid_hidden[node->prim_indices[i]];
|
||||
|
||||
for (int y = 0; y < gridsize - 1; y++) {
|
||||
for (int x = 0; x < gridsize - 1; x++) {
|
||||
/* check if grid face is hidden */
|
||||
if (gh) {
|
||||
if (paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
if (!grid_hidden.is_empty()) {
|
||||
if (paint_is_grid_face_hidden(grid_hidden[node->prim_indices[i]], gridsize, x, y)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -3078,9 +3075,10 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
|||
vi->bm_vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
}
|
||||
|
||||
vi->gh = nullptr;
|
||||
vi->gh.reset();
|
||||
if (vi->grids && mode == PBVH_ITER_UNIQUE) {
|
||||
vi->grid_hidden = pbvh->subdiv_ccg->grid_hidden.data();
|
||||
vi->grid_hidden = pbvh->subdiv_ccg->grid_hidden.is_empty() ? nullptr :
|
||||
&pbvh->subdiv_ccg->grid_hidden;
|
||||
}
|
||||
|
||||
vi->mask = 0.0f;
|
||||
|
@ -3294,20 +3292,23 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh)
|
|||
}
|
||||
case PBVH_GRIDS: {
|
||||
const OffsetIndices faces = mesh->faces();
|
||||
const Span<BLI_bitmap *> grid_hidden = pbvh->subdiv_ccg->grid_hidden;
|
||||
const BitGroupVector<> &grid_hidden = pbvh->subdiv_ccg->grid_hidden;
|
||||
CCGKey key = pbvh->gridkey;
|
||||
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask hidden_faces = IndexMask::from_predicate(
|
||||
faces.index_range(), GrainSize(1024), memory, [&](const int i) {
|
||||
const IndexRange face = faces[i];
|
||||
return std::any_of(face.begin(), face.end(), [&](const int corner) {
|
||||
if (!grid_hidden[corner]) {
|
||||
return false;
|
||||
}
|
||||
return BLI_BITMAP_TEST_BOOL(grid_hidden[corner], key.grid_area - 1);
|
||||
});
|
||||
});
|
||||
const IndexMask hidden_faces =
|
||||
grid_hidden.is_empty() ?
|
||||
IndexMask::from_predicate(faces.index_range(),
|
||||
GrainSize(1024),
|
||||
memory,
|
||||
[&](const int i) {
|
||||
const IndexRange face = faces[i];
|
||||
return std::any_of(
|
||||
face.begin(), face.end(), [&](const int corner) {
|
||||
return grid_hidden[corner][key.grid_area - 1];
|
||||
});
|
||||
}) :
|
||||
IndexMask();
|
||||
|
||||
MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
if (hidden_faces.is_empty()) {
|
||||
|
|
|
@ -144,10 +144,6 @@ static void subdiv_ccg_alloc_elements(SubdivCCG &subdiv_ccg, Subdiv &subdiv)
|
|||
subdiv_ccg.grids[grid_index] = (CCGElem *)&subdiv_ccg.grids_storage[grid_offset];
|
||||
}
|
||||
subdiv_ccg.grid_flag_mats.reinitialize(num_grids);
|
||||
subdiv_ccg.grid_hidden.reinitialize(num_grids);
|
||||
for (int grid_index = 0; grid_index < num_grids; grid_index++) {
|
||||
subdiv_ccg.grid_hidden[grid_index] = BLI_BITMAP_NEW(grid_area, "ccg grid hidden");
|
||||
}
|
||||
/* TODO(sergey): Allocate memory for loose elements. */
|
||||
subdiv_ccg.faces.reinitialize(num_faces);
|
||||
subdiv_ccg.grid_to_face_map.reinitialize(num_grids);
|
||||
|
@ -563,10 +559,6 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv &subdiv,
|
|||
|
||||
void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
|
||||
{
|
||||
for (const int grid_index : subdiv_ccg->grid_hidden.index_range()) {
|
||||
MEM_SAFE_FREE(subdiv_ccg->grid_hidden[grid_index]);
|
||||
}
|
||||
|
||||
if (subdiv_ccg->subdiv != nullptr) {
|
||||
BKE_subdiv_free(subdiv_ccg->subdiv);
|
||||
}
|
||||
|
@ -1684,20 +1676,18 @@ SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
|
|||
return SUBDIV_CCG_ADJACENT_NONE;
|
||||
}
|
||||
|
||||
void BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG &subdiv_ccg, int grid_index)
|
||||
blender::BitGroupVector<> &BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG &subdiv_ccg)
|
||||
{
|
||||
if (subdiv_ccg.grid_hidden[grid_index] != nullptr) {
|
||||
return;
|
||||
if (subdiv_ccg.grid_hidden.is_empty()) {
|
||||
const int grid_area = subdiv_ccg.grid_size * subdiv_ccg.grid_size;
|
||||
subdiv_ccg.grid_hidden = blender::BitGroupVector<>(subdiv_ccg.grids.size(), grid_area, false);
|
||||
}
|
||||
|
||||
CCGKey key;
|
||||
BKE_subdiv_ccg_key_top_level(key, subdiv_ccg);
|
||||
subdiv_ccg.grid_hidden[grid_index] = BLI_BITMAP_NEW(key.grid_area, __func__);
|
||||
return subdiv_ccg.grid_hidden;
|
||||
}
|
||||
|
||||
void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG &subdiv_ccg, int grid_index)
|
||||
void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG &subdiv_ccg)
|
||||
{
|
||||
MEM_SAFE_FREE(subdiv_ccg.grid_hidden[grid_index]);
|
||||
subdiv_ccg.grid_hidden = {};
|
||||
}
|
||||
|
||||
static void subdiv_ccg_coord_to_ptex_coord(const SubdivCCG &subdiv_ccg,
|
||||
|
|
|
@ -76,6 +76,11 @@ class BitGroupVector {
|
|||
return aligned_group_size_ == 0 ? 0 : data_.size() / aligned_group_size_;
|
||||
}
|
||||
|
||||
bool is_empty() const
|
||||
{
|
||||
return this->size() == 0;
|
||||
}
|
||||
|
||||
/** Number of bits per group. */
|
||||
int64_t group_size() const
|
||||
{
|
||||
|
|
|
@ -363,6 +363,11 @@ class MutableBoundedBitSpan : public MutableBitSpan {
|
|||
return {data_, bit_range_.take_front(n)};
|
||||
}
|
||||
|
||||
BoundedBitSpan as_span() const
|
||||
{
|
||||
return BoundedBitSpan(data_, bit_range_);
|
||||
}
|
||||
|
||||
void copy_from(const BitSpan other);
|
||||
void copy_from(const BoundedBitSpan other);
|
||||
};
|
||||
|
|
|
@ -255,6 +255,16 @@ template<typename BitSpanT> inline bool any_bit_set(const BitSpanT &arg)
|
|||
return has_common_set_bits(arg);
|
||||
}
|
||||
|
||||
template<typename... BitSpanT> inline bool has_common_unset_bits(const BitSpanT &...args)
|
||||
{
|
||||
return any_set_expr([](const auto... x) { return ~(x | ...); }, args...);
|
||||
}
|
||||
|
||||
template<typename BitSpanT> inline bool any_bit_unset(const BitSpanT &arg)
|
||||
{
|
||||
return has_common_unset_bits(arg);
|
||||
}
|
||||
|
||||
template<typename BitSpanT, typename Fn> inline void foreach_1_index(const BitSpanT &data, Fn &&fn)
|
||||
{
|
||||
foreach_1_index_expr([](const BitInt x) { return x; }, fn, data);
|
||||
|
|
|
@ -95,10 +95,10 @@ class BitVector {
|
|||
|
||||
BitVector(NoExceptConstructor, Allocator allocator = {}) noexcept : BitVector(allocator) {}
|
||||
|
||||
BitVector(const BitVector &other) : BitVector(NoExceptConstructor(), other.allocator_)
|
||||
BitVector(const BoundedBitSpan span) : BitVector(NoExceptConstructor())
|
||||
{
|
||||
const int64_t ints_to_copy = other.used_ints_amount();
|
||||
if (other.size_in_bits_ <= BitsInInlineBuffer) {
|
||||
const int64_t ints_to_copy = required_ints_for_bits(span.size());
|
||||
if (span.size() <= BitsInInlineBuffer) {
|
||||
/* The data is copied into the owned inline buffer. */
|
||||
data_ = inline_buffer_;
|
||||
capacity_in_bits_ = BitsInInlineBuffer;
|
||||
|
@ -109,8 +109,13 @@ class BitVector {
|
|||
allocator_.allocate(ints_to_copy * sizeof(BitInt), AllocationAlignment, __func__));
|
||||
capacity_in_bits_ = ints_to_copy * BitsPerInt;
|
||||
}
|
||||
size_in_bits_ = other.size_in_bits_;
|
||||
uninitialized_copy_n(other.data_, ints_to_copy, data_);
|
||||
size_in_bits_ = span.size();
|
||||
uninitialized_copy_n(span.data(), ints_to_copy, data_);
|
||||
}
|
||||
|
||||
BitVector(const BitVector &other) : BitVector(BoundedBitSpan(other))
|
||||
{
|
||||
allocator_ = other.allocator_;
|
||||
}
|
||||
|
||||
BitVector(BitVector &&other) noexcept : BitVector(NoExceptConstructor(), other.allocator_)
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
/* Needed for BKE_ccg.h. */
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_offset_indices.hh"
|
||||
#include "BLI_set.hh"
|
||||
|
@ -80,7 +79,6 @@ struct PBVH_GPU_Args {
|
|||
Span<int> grid_indices;
|
||||
CCGKey ccg_key;
|
||||
Span<CCGElem *> grids;
|
||||
Span<const BLI_bitmap *> grid_hidden;
|
||||
|
||||
Span<int> prim_indices;
|
||||
|
||||
|
|
|
@ -351,7 +351,7 @@ struct PBVHBatches {
|
|||
break;
|
||||
}
|
||||
case PBVH_GRIDS: {
|
||||
count = BKE_pbvh_count_grid_quads(args.grid_hidden,
|
||||
count = BKE_pbvh_count_grid_quads(args.subdiv_ccg->grid_hidden,
|
||||
args.grid_indices.data(),
|
||||
args.grid_indices.size(),
|
||||
args.ccg_key.grid_size,
|
||||
|
@ -1111,6 +1111,7 @@ struct PBVHBatches {
|
|||
|
||||
void create_index_grids(const PBVH_GPU_Args &args, bool do_coarse)
|
||||
{
|
||||
const BitGroupVector<> &grid_hidden = args.subdiv_ccg->grid_hidden;
|
||||
const int *mat_index = static_cast<const int *>(
|
||||
CustomData_get_layer_named(args.face_data, CD_PROP_INT32, "material_index"));
|
||||
|
||||
|
@ -1134,14 +1135,15 @@ struct PBVHBatches {
|
|||
|
||||
for (const int grid_index : args.grid_indices) {
|
||||
bool smooth = !args.grid_flag_mats[grid_index].sharp;
|
||||
const BLI_bitmap *gh = args.grid_hidden[grid_index];
|
||||
|
||||
for (int y = 0; y < gridsize - 1; y += skip) {
|
||||
for (int x = 0; x < gridsize - 1; x += skip) {
|
||||
if (gh && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
/* Skip hidden faces by just setting smooth to true. */
|
||||
smooth = true;
|
||||
goto outer_loop_break;
|
||||
if (!grid_hidden.is_empty()) {
|
||||
const BoundedBitSpan gh = grid_hidden[grid_index];
|
||||
for (int y = 0; y < gridsize - 1; y += skip) {
|
||||
for (int x = 0; x < gridsize - 1; x += skip) {
|
||||
if (paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
/* Skip hidden faces by just setting smooth to true. */
|
||||
smooth = true;
|
||||
goto outer_loop_break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1159,7 +1161,7 @@ struct PBVHBatches {
|
|||
const CCGKey *key = &args.ccg_key;
|
||||
|
||||
uint visible_quad_len = BKE_pbvh_count_grid_quads(
|
||||
args.grid_hidden, args.grid_indices.data(), totgrid, key->grid_size, display_gridsize);
|
||||
grid_hidden, args.grid_indices.data(), totgrid, key->grid_size, display_gridsize);
|
||||
|
||||
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, 2 * visible_quad_len, INT_MAX);
|
||||
GPU_indexbuf_init(&elb_lines,
|
||||
|
@ -1174,12 +1176,13 @@ struct PBVHBatches {
|
|||
uint v0, v1, v2, v3;
|
||||
bool grid_visible = false;
|
||||
|
||||
const BLI_bitmap *gh = args.grid_hidden[args.grid_indices[i]];
|
||||
const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
|
||||
grid_hidden[args.grid_indices[i]];
|
||||
|
||||
for (int j = 0; j < gridsize - skip; j += skip) {
|
||||
for (int k = 0; k < gridsize - skip; k += skip) {
|
||||
/* Skip hidden grid face */
|
||||
if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
|
||||
if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
|
||||
continue;
|
||||
}
|
||||
/* Indices in a Clockwise QUAD disposition. */
|
||||
|
@ -1212,13 +1215,14 @@ struct PBVHBatches {
|
|||
|
||||
for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
|
||||
bool grid_visible = false;
|
||||
const BLI_bitmap *gh = args.grid_hidden[args.grid_indices[i]];
|
||||
const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
|
||||
grid_hidden[args.grid_indices[i]];
|
||||
|
||||
uint v0, v1, v2, v3;
|
||||
for (int j = 0; j < gridsize - skip; j += skip) {
|
||||
for (int k = 0; k < gridsize - skip; k += skip) {
|
||||
/* Skip hidden grid face */
|
||||
if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
|
||||
if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_bit_span_ops.hh"
|
||||
#include "BLI_enumerable_thread_specific.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
|
@ -156,12 +156,12 @@ static void vert_hide_update(Object &object,
|
|||
}
|
||||
|
||||
static void partialvis_update_mesh(Object &object,
|
||||
PBVH &pbvh,
|
||||
const VisAction action,
|
||||
const VisArea area,
|
||||
const float planes[4][4],
|
||||
const Span<PBVHNode *> nodes)
|
||||
{
|
||||
PBVH &pbvh = *object.sculpt->pbvh;
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
if (action == VisAction::Show && !attributes.contains(".hide_vert")) {
|
||||
|
@ -195,7 +195,7 @@ static void partialvis_update_mesh(Object &object,
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case VisArea::Masked:
|
||||
case VisArea::Masked: {
|
||||
const VArraySpan<float> mask = *attributes.lookup<float>(".sculpt_mask", ATTR_DOMAIN_POINT);
|
||||
if (action == VisAction::Show && mask.is_empty()) {
|
||||
vert_show_all(object, nodes);
|
||||
|
@ -210,96 +210,154 @@ static void partialvis_update_mesh(Object &object,
|
|||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BKE_mesh_flush_hidden_from_verts(&mesh);
|
||||
}
|
||||
|
||||
/* Hide or show elements in multires grids with a special GridFlags
|
||||
* customdata layer. */
|
||||
static void partialvis_update_grids(Depsgraph *depsgraph,
|
||||
Object *ob,
|
||||
PBVH *pbvh,
|
||||
static void grids_show_all(Depsgraph &depsgraph, Object &object, const Span<PBVHNode *> nodes)
|
||||
{
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
PBVH &pbvh = *object.sculpt->pbvh;
|
||||
SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
|
||||
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
|
||||
if (!grid_hidden.is_empty()) {
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
const Span<int> grids = BKE_pbvh_node_get_grid_indices(*node);
|
||||
if (std::any_of(grids.begin(), grids.end(), [&](const int i) {
|
||||
return bits::any_bit_set(grid_hidden[i]);
|
||||
}))
|
||||
{
|
||||
SCULPT_undo_push_node(&object, node, SCULPT_UNDO_HIDDEN);
|
||||
BKE_pbvh_node_mark_rebuild_draw(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
for (PBVHNode *node : nodes) {
|
||||
BKE_pbvh_node_fully_hidden_set(node, false);
|
||||
}
|
||||
BKE_subdiv_ccg_grid_hidden_free(subdiv_ccg);
|
||||
BKE_pbvh_sync_visibility_from_verts(&pbvh, &mesh);
|
||||
multires_mark_as_modified(&depsgraph, &object, MULTIRES_HIDDEN_MODIFIED);
|
||||
}
|
||||
|
||||
static void grid_hide_update(Depsgraph &depsgraph,
|
||||
Object &object,
|
||||
const Span<PBVHNode *> nodes,
|
||||
const FunctionRef<void(const int, MutableBoundedBitSpan)> calc_hide)
|
||||
{
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
PBVH &pbvh = *object.sculpt->pbvh;
|
||||
SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
|
||||
BitGroupVector<> &grid_hidden = BKE_subdiv_ccg_grid_hidden_ensure(subdiv_ccg);
|
||||
|
||||
bool any_changed = false;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
bool changed = false;
|
||||
bool any_visible = false;
|
||||
for (const int grid : BKE_pbvh_node_get_grid_indices(*node)) {
|
||||
MutableBoundedBitSpan gh = grid_hidden[grid];
|
||||
const BitVector<1024> old_hide(gh);
|
||||
calc_hide(grid, gh);
|
||||
changed |= !bits::spans_equal(old_hide, gh);
|
||||
any_visible |= bits::any_bit_unset(gh);
|
||||
}
|
||||
if (!changed) {
|
||||
continue;
|
||||
}
|
||||
any_changed = true;
|
||||
|
||||
SCULPT_undo_push_node(&object, node, SCULPT_UNDO_HIDDEN);
|
||||
|
||||
/* Don't tag a visibility update, we handle updating the fully hidden status here. */
|
||||
BKE_pbvh_node_mark_rebuild_draw(node);
|
||||
BKE_pbvh_node_fully_hidden_set(node, !any_visible);
|
||||
}
|
||||
});
|
||||
|
||||
if (any_changed) {
|
||||
multires_mark_as_modified(&depsgraph, &object, MULTIRES_HIDDEN_MODIFIED);
|
||||
BKE_pbvh_sync_visibility_from_verts(&pbvh, &mesh);
|
||||
}
|
||||
}
|
||||
|
||||
static void partialvis_update_grids(Depsgraph &depsgraph,
|
||||
Object &object,
|
||||
const VisAction action,
|
||||
const VisArea area,
|
||||
const float planes[4][4],
|
||||
const Span<PBVHNode *> nodes)
|
||||
{
|
||||
SubdivCCG &subdiv_ccg = *ob->sculpt->subdiv_ccg;
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
const CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
|
||||
MutableSpan<BLI_bitmap *> grid_hidden = subdiv_ccg.grid_hidden;
|
||||
|
||||
for (PBVHNode *node : nodes) {
|
||||
bool any_changed = false;
|
||||
bool any_visible = false;
|
||||
|
||||
SCULPT_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
|
||||
|
||||
for (const int grid_index : BKE_pbvh_node_get_grid_indices(*node)) {
|
||||
int any_hidden = 0;
|
||||
BLI_bitmap *gh = grid_hidden[grid_index];
|
||||
if (!gh) {
|
||||
switch (action) {
|
||||
case VisAction::Hide:
|
||||
/* Create grid flags data. */
|
||||
gh = grid_hidden[grid_index] = BLI_BITMAP_NEW(key.grid_area,
|
||||
"partialvis_update_grids");
|
||||
break;
|
||||
case VisAction::Show:
|
||||
/* Entire grid is visible, nothing to show. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (action == VisAction::Show && area == VisArea::All) {
|
||||
/* Special case if we're showing all, just free the grid. */
|
||||
MEM_freeN(gh);
|
||||
grid_hidden[grid_index] = nullptr;
|
||||
any_changed = true;
|
||||
any_visible = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int y = 0; y < key.grid_size; y++) {
|
||||
for (int x = 0; x < key.grid_size; x++) {
|
||||
CCGElem *elem = CCG_grid_elem(&key, grids[grid_index], x, y);
|
||||
const float *co = CCG_elem_co(&key, elem);
|
||||
float mask = key.has_mask ? *CCG_elem_mask(&key, elem) : 0.0f;
|
||||
|
||||
/* Skip grid element if not in the effected area. */
|
||||
if (is_effected(area, planes, co, mask)) {
|
||||
/* Set or clear the hide flag. */
|
||||
BLI_BITMAP_SET(gh, y * key.grid_size + x, action == VisAction::Hide);
|
||||
|
||||
any_changed = true;
|
||||
}
|
||||
|
||||
/* Keep track of whether any elements are still hidden. */
|
||||
if (BLI_BITMAP_TEST(gh, y * key.grid_size + x)) {
|
||||
any_hidden = true;
|
||||
}
|
||||
else {
|
||||
any_visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If everything in the grid is now visible, free the grid flags. */
|
||||
if (!any_hidden) {
|
||||
MEM_freeN(gh);
|
||||
grid_hidden[grid_index] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark updates if anything was hidden/shown. */
|
||||
if (any_changed) {
|
||||
BKE_pbvh_node_mark_rebuild_draw(node);
|
||||
BKE_pbvh_node_fully_hidden_set(node, !any_visible);
|
||||
multires_mark_as_modified(depsgraph, ob, MULTIRES_HIDDEN_MODIFIED);
|
||||
}
|
||||
PBVH &pbvh = *object.sculpt->pbvh;
|
||||
SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
|
||||
if (action == VisAction::Show && area == VisArea::All) {
|
||||
grids_show_all(depsgraph, object, nodes);
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_pbvh_sync_visibility_from_verts(pbvh, static_cast<Mesh *>(ob->data));
|
||||
const bool value = action_to_hide(action);
|
||||
switch (area) {
|
||||
case VisArea::Inside:
|
||||
case VisArea::Outside: {
|
||||
const CCGKey key = *BKE_pbvh_get_grid_key(&pbvh);
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
grid_hide_update(
|
||||
depsgraph, object, nodes, [&](const int grid_index, MutableBoundedBitSpan hide) {
|
||||
CCGElem *grid = grids[grid_index];
|
||||
for (const int y : IndexRange(key.grid_size)) {
|
||||
for (const int x : IndexRange(key.grid_size)) {
|
||||
CCGElem *elem = CCG_grid_elem(&key, grid, x, y);
|
||||
if (isect_point_planes_v3(planes, 4, CCG_elem_co(&key, elem))) {
|
||||
hide[y * key.grid_size + x].set(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case VisArea::All:
|
||||
switch (action) {
|
||||
case VisAction::Hide:
|
||||
grid_hide_update(
|
||||
depsgraph, object, nodes, [&](const int /*verts*/, MutableBoundedBitSpan hide) {
|
||||
hide.fill(true);
|
||||
});
|
||||
break;
|
||||
case VisAction::Show:
|
||||
grids_show_all(depsgraph, object, nodes);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VisArea::Masked: {
|
||||
const CCGKey key = *BKE_pbvh_get_grid_key(&pbvh);
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
if (!key.has_mask) {
|
||||
grid_hide_update(
|
||||
depsgraph, object, nodes, [&](const int /*verts*/, MutableBoundedBitSpan hide) {
|
||||
hide.fill(value);
|
||||
});
|
||||
}
|
||||
else {
|
||||
grid_hide_update(
|
||||
depsgraph, object, nodes, [&](const int grid_index, MutableBoundedBitSpan hide) {
|
||||
CCGElem *grid = grids[grid_index];
|
||||
for (const int y : IndexRange(key.grid_size)) {
|
||||
for (const int x : IndexRange(key.grid_size)) {
|
||||
CCGElem *elem = CCG_grid_elem(&key, grid, x, y);
|
||||
if (*CCG_elem_mask(&key, elem) > 0.5f) {
|
||||
hide[y * key.grid_size + x].set(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void partialvis_update_bmesh_verts(BMesh *bm,
|
||||
|
@ -464,10 +522,10 @@ static int hide_show_exec(bContext *C, wmOperator *op)
|
|||
|
||||
switch (pbvh_type) {
|
||||
case PBVH_FACES:
|
||||
partialvis_update_mesh(*ob, *pbvh, action, area, clip_planes, nodes);
|
||||
partialvis_update_mesh(*ob, action, area, clip_planes, nodes);
|
||||
break;
|
||||
case PBVH_GRIDS:
|
||||
partialvis_update_grids(depsgraph, ob, pbvh, action, area, clip_planes, nodes);
|
||||
partialvis_update_grids(*depsgraph, *ob, action, area, clip_planes, nodes);
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
partialvis_update_bmesh(ob, pbvh, action, area, clip_planes, nodes);
|
||||
|
|
|
@ -417,9 +417,8 @@ bool SCULPT_vertex_visible_get(const SculptSession *ss, PBVHVertRef vertex)
|
|||
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
|
||||
const int grid_index = vertex.i / key->grid_area;
|
||||
const int vertex_index = vertex.i - grid_index * key->grid_area;
|
||||
const blender::Span<const BLI_bitmap *> grid_hidden = ss->subdiv_ccg->grid_hidden;
|
||||
if (grid_hidden[grid_index]) {
|
||||
return !BLI_BITMAP_TEST(grid_hidden[grid_index], vertex_index);
|
||||
if (!ss->subdiv_ccg->grid_hidden.is_empty()) {
|
||||
return !ss->subdiv_ccg->grid_hidden[grid_index][vertex_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,7 +200,7 @@ struct SculptUndoNode {
|
|||
int maxgrid; /* same for grid */
|
||||
int gridsize; /* same for grid */
|
||||
blender::Array<int> grids; /* to restore into right location */
|
||||
BLI_bitmap **grid_hidden;
|
||||
blender::BitGroupVector<> grid_hidden;
|
||||
|
||||
/* bmesh */
|
||||
BMLogEntry *bm_entry;
|
||||
|
|
|
@ -510,10 +510,19 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode, bool
|
|||
hide_vert.finish();
|
||||
}
|
||||
else if (!unode->grids.is_empty() && subdiv_ccg != nullptr) {
|
||||
if (unode->grid_hidden.is_empty()) {
|
||||
BKE_subdiv_ccg_grid_hidden_free(*subdiv_ccg);
|
||||
return true;
|
||||
}
|
||||
|
||||
blender::BitGroupVector<> &grid_hidden = BKE_subdiv_ccg_grid_hidden_ensure(*subdiv_ccg);
|
||||
const Span<int> grids = unode->grids;
|
||||
blender::MutableSpan<BLI_bitmap *> grid_hidden = subdiv_ccg->grid_hidden;
|
||||
for (const int i : grids.index_range()) {
|
||||
SWAP(BLI_bitmap *, unode->grid_hidden[i], grid_hidden[grids[i]]);
|
||||
const int grid_index = grids[i];
|
||||
/* Swap the two bit spans. */
|
||||
blender::BitVector<512> tmp(grid_hidden[grid_index]);
|
||||
grid_hidden[grid_index].copy_from(unode->grid_hidden[i].as_span());
|
||||
unode->grid_hidden[i].copy_from(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1087,13 +1096,6 @@ static void sculpt_undo_free_list(ListBase *lb)
|
|||
while (unode != nullptr) {
|
||||
SculptUndoNode *unode_next = unode->next;
|
||||
|
||||
if (unode->grid_hidden) {
|
||||
for (const int i : unode->grids.index_range()) {
|
||||
MEM_SAFE_FREE(unode->grid_hidden[i]);
|
||||
}
|
||||
MEM_freeN(unode->grid_hidden);
|
||||
}
|
||||
|
||||
if (unode->bm_entry) {
|
||||
BM_log_entry_drop(unode->bm_entry);
|
||||
}
|
||||
|
@ -1162,25 +1164,20 @@ SculptUndoNode *SCULPT_undo_get_first_node()
|
|||
static size_t sculpt_undo_alloc_and_store_hidden(SculptSession *ss, SculptUndoNode *unode)
|
||||
{
|
||||
PBVHNode *node = static_cast<PBVHNode *>(unode->node);
|
||||
const blender::Span<const BLI_bitmap *> grid_hidden = ss->subdiv_ccg->grid_hidden;
|
||||
|
||||
const Span<int> grid_indices = BKE_pbvh_node_get_grid_indices(*node);
|
||||
|
||||
size_t alloc_size = sizeof(*unode->grid_hidden) * grid_indices.size();
|
||||
unode->grid_hidden = static_cast<BLI_bitmap **>(MEM_callocN(alloc_size, "unode->grid_hidden"));
|
||||
|
||||
for (const int i : grid_indices.index_range()) {
|
||||
const int grid_index = grid_indices[i];
|
||||
if (grid_hidden[grid_index]) {
|
||||
unode->grid_hidden[i] = static_cast<BLI_bitmap *>(MEM_dupallocN(grid_hidden[grid_index]));
|
||||
alloc_size += MEM_allocN_len(unode->grid_hidden[i]);
|
||||
}
|
||||
else {
|
||||
unode->grid_hidden[i] = nullptr;
|
||||
}
|
||||
if (!ss->subdiv_ccg) {
|
||||
return 0;
|
||||
}
|
||||
const blender::BitGroupVector<> grid_hidden = ss->subdiv_ccg->grid_hidden;
|
||||
if (grid_hidden.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return alloc_size;
|
||||
const Span<int> grid_indices = BKE_pbvh_node_get_grid_indices(*node);
|
||||
for (const int i : grid_indices.index_range()) {
|
||||
unode->grid_hidden[i].copy_from(grid_hidden[grid_indices[i]]);
|
||||
}
|
||||
|
||||
return unode->grid_hidden.all_bits().full_ints_num() / blender::bits::BitsPerInt;
|
||||
}
|
||||
|
||||
/* Allocate node and initialize its default fields specific for the given undo type.
|
||||
|
|
Loading…
Reference in New Issue