Cleanup: Pass PBVH node grid indices as Span
This commit is contained in:
@@ -377,13 +377,8 @@ bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node);
|
||||
void BKE_pbvh_mark_rebuild_pixels(PBVH *pbvh);
|
||||
void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, PBVHVertRef vertex);
|
||||
|
||||
void BKE_pbvh_node_get_grids(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
const int **grid_indices,
|
||||
int *totgrid,
|
||||
int *maxgrid,
|
||||
int *gridsize,
|
||||
CCGElem *const **r_griddata);
|
||||
blender::Span<int> BKE_pbvh_node_get_grid_indices(const PBVHNode &node);
|
||||
|
||||
void BKE_pbvh_node_num_verts(const PBVH *pbvh,
|
||||
const PBVHNode *node,
|
||||
int *r_uniquevert,
|
||||
|
||||
@@ -1662,27 +1662,19 @@ 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;
|
||||
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)) {
|
||||
CCGElem *const *grids;
|
||||
const int *grid_indices;
|
||||
int totgrid, i;
|
||||
|
||||
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, nullptr, nullptr, &grids);
|
||||
const Span<const BLI_bitmap *> grid_hidden = pbvh->subdiv_ccg->grid_hidden;
|
||||
CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
|
||||
|
||||
for (i = 0; i < totgrid; i++) {
|
||||
int g = grid_indices[i], x, y;
|
||||
const BLI_bitmap *gh = grid_hidden[g];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (y = 0; y < key.grid_size; y++) {
|
||||
for (x = 0; x < key.grid_size; x++) {
|
||||
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)) {
|
||||
BKE_pbvh_node_fully_hidden_set(node, false);
|
||||
return;
|
||||
@@ -2054,51 +2046,9 @@ int BKE_pbvh_node_num_unique_verts(const PBVH &pbvh, const PBVHNode &node)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BKE_pbvh_node_get_grids(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
const int **r_grid_indices,
|
||||
int *r_totgrid,
|
||||
int *r_maxgrid,
|
||||
int *r_gridsize,
|
||||
CCGElem *const **r_griddata)
|
||||
Span<int> BKE_pbvh_node_get_grid_indices(const PBVHNode &node)
|
||||
{
|
||||
switch (pbvh->header.type) {
|
||||
case PBVH_GRIDS:
|
||||
if (r_grid_indices) {
|
||||
*r_grid_indices = node->prim_indices.data();
|
||||
}
|
||||
if (r_totgrid) {
|
||||
*r_totgrid = node->prim_indices.size();
|
||||
}
|
||||
if (r_maxgrid) {
|
||||
*r_maxgrid = pbvh->subdiv_ccg->grids.size();
|
||||
}
|
||||
if (r_gridsize) {
|
||||
*r_gridsize = pbvh->gridkey.grid_size;
|
||||
}
|
||||
if (r_griddata) {
|
||||
*r_griddata = pbvh->subdiv_ccg->grids.data();
|
||||
}
|
||||
break;
|
||||
case PBVH_FACES:
|
||||
case PBVH_BMESH:
|
||||
if (r_grid_indices) {
|
||||
*r_grid_indices = nullptr;
|
||||
}
|
||||
if (r_totgrid) {
|
||||
*r_totgrid = 0;
|
||||
}
|
||||
if (r_maxgrid) {
|
||||
*r_maxgrid = 0;
|
||||
}
|
||||
if (r_gridsize) {
|
||||
*r_gridsize = 0;
|
||||
}
|
||||
if (r_griddata) {
|
||||
*r_griddata = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return node.prim_indices;
|
||||
}
|
||||
|
||||
void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3])
|
||||
@@ -3084,24 +3034,29 @@ void BKE_pbvh_node_color_buffer_free(PBVH *pbvh)
|
||||
|
||||
void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode)
|
||||
{
|
||||
CCGElem *const *grids;
|
||||
const int *grid_indices;
|
||||
int totgrid, gridsize, uniq_verts, totvert;
|
||||
|
||||
vi->grid = nullptr;
|
||||
vi->no = nullptr;
|
||||
vi->fno = nullptr;
|
||||
vi->vert_positions = {};
|
||||
vi->vertex.i = 0LL;
|
||||
|
||||
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, nullptr, &gridsize, &grids);
|
||||
int uniq_verts, totvert;
|
||||
BKE_pbvh_node_num_verts(pbvh, node, &uniq_verts, &totvert);
|
||||
vi->key = pbvh->gridkey;
|
||||
|
||||
vi->grids = grids;
|
||||
vi->grid_indices = grid_indices;
|
||||
vi->totgrid = (grids) ? totgrid : 1;
|
||||
vi->gridsize = gridsize;
|
||||
if (pbvh->header.type == PBVH_GRIDS) {
|
||||
vi->key = pbvh->gridkey;
|
||||
vi->grids = pbvh->subdiv_ccg->grids.data();
|
||||
vi->grid_indices = node->prim_indices.data();
|
||||
vi->totgrid = node->prim_indices.size();
|
||||
vi->gridsize = pbvh->gridkey.grid_size;
|
||||
}
|
||||
else {
|
||||
vi->key = {};
|
||||
vi->grids = nullptr;
|
||||
vi->grid_indices = nullptr;
|
||||
vi->totgrid = 1;
|
||||
vi->gridsize = 0;
|
||||
}
|
||||
|
||||
if (mode == PBVH_ITER_ALL) {
|
||||
vi->totvert = totvert;
|
||||
|
||||
@@ -225,25 +225,19 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
|
||||
const float planes[4][4],
|
||||
const Span<PBVHNode *> nodes)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
|
||||
MutableSpan<BLI_bitmap *> grid_hidden = subdiv_ccg->grid_hidden;
|
||||
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) {
|
||||
CCGElem *const *grids;
|
||||
const int *grid_indices;
|
||||
int totgrid;
|
||||
bool any_changed = false, any_visible = false;
|
||||
|
||||
/* Get PBVH data. */
|
||||
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, nullptr, nullptr, &grids);
|
||||
bool any_changed = false;
|
||||
bool any_visible = false;
|
||||
|
||||
SCULPT_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
|
||||
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
for (const int grid_index : BKE_pbvh_node_get_grid_indices(*node)) {
|
||||
int any_hidden = 0;
|
||||
const int grid_index = grid_indices[i];
|
||||
BLI_bitmap *gh = grid_hidden[grid_index];
|
||||
if (!gh) {
|
||||
switch (action) {
|
||||
|
||||
@@ -199,7 +199,6 @@ struct SculptUndoNode {
|
||||
/* multires */
|
||||
int maxgrid; /* same for grid */
|
||||
int gridsize; /* same for grid */
|
||||
int totgrid; /* to restore into right location */
|
||||
blender::Array<int> grids; /* to restore into right location */
|
||||
BLI_bitmap **grid_hidden;
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ static void update_cb(PBVHNode *node, void *rebuild)
|
||||
struct PartialUpdateData {
|
||||
PBVH *pbvh;
|
||||
bool rebuild;
|
||||
char *modified_grids;
|
||||
bool *modified_grids;
|
||||
bool *modified_hidden_verts;
|
||||
bool *modified_mask_verts;
|
||||
bool *modified_color_verts;
|
||||
@@ -304,18 +304,12 @@ static void update_cb_partial(PBVHNode *node, void *userdata)
|
||||
{
|
||||
PartialUpdateData *data = static_cast<PartialUpdateData *>(userdata);
|
||||
if (BKE_pbvh_type(data->pbvh) == PBVH_GRIDS) {
|
||||
const int *node_grid_indices;
|
||||
int totgrid;
|
||||
bool update = false;
|
||||
BKE_pbvh_node_get_grids(
|
||||
data->pbvh, node, &node_grid_indices, &totgrid, nullptr, nullptr, nullptr);
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
if (data->modified_grids[node_grid_indices[i]] == 1) {
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
if (update) {
|
||||
update_cb(node, &(data->rebuild));
|
||||
const Span<int> grid_indices = BKE_pbvh_node_get_grid_indices(*node);
|
||||
if (std::any_of(grid_indices.begin(), grid_indices.end(), [&](const int grid) {
|
||||
return data->modified_grids[grid];
|
||||
}))
|
||||
{
|
||||
update_cb(node, &data->rebuild);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -383,6 +377,7 @@ static bool sculpt_undo_restore_deformed(
|
||||
|
||||
static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, SculptUndoNode *unode)
|
||||
{
|
||||
using namespace blender;
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
@@ -467,23 +462,20 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (unode->maxgrid && subdiv_ccg != nullptr) {
|
||||
/* Multires restore. */
|
||||
CCGElem **grids, *grid;
|
||||
else if (!unode->grids.is_empty() && subdiv_ccg != nullptr) {
|
||||
const int gridsize = subdiv_ccg->grid_size;
|
||||
CCGKey key;
|
||||
int gridsize;
|
||||
|
||||
grids = subdiv_ccg->grids.data();
|
||||
gridsize = subdiv_ccg->grid_size;
|
||||
BKE_subdiv_ccg_key_top_level(key, *subdiv_ccg);
|
||||
const Span<int> grid_indices = unode->grids;
|
||||
|
||||
blender::MutableSpan<blender::float3> co = unode->co;
|
||||
int index = 0;
|
||||
for (int j = 0; j < unode->totgrid; j++) {
|
||||
grid = grids[unode->grids[j]];
|
||||
MutableSpan<CCGElem *> grids = subdiv_ccg->grids;
|
||||
|
||||
for (int i = 0; i < gridsize * gridsize; i++) {
|
||||
swap_v3_v3(CCG_elem_offset_co(&key, grid, i), co[index]);
|
||||
int index = 0;
|
||||
for (const int i : grid_indices.index_range()) {
|
||||
CCGElem *grid = grids[grid_indices[i]];
|
||||
for (const int j : IndexRange(gridsize * gridsize)) {
|
||||
swap_v3_v3(CCG_elem_offset_co(&key, grid, j), co[index]);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@@ -517,11 +509,11 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode, bool
|
||||
}
|
||||
hide_vert.finish();
|
||||
}
|
||||
else if (unode->maxgrid && subdiv_ccg != nullptr) {
|
||||
else if (!unode->grids.is_empty() && subdiv_ccg != nullptr) {
|
||||
const Span<int> grids = unode->grids;
|
||||
blender::MutableSpan<BLI_bitmap *> grid_hidden = subdiv_ccg->grid_hidden;
|
||||
|
||||
for (int i = 0; i < unode->totgrid; i++) {
|
||||
SWAP(BLI_bitmap *, unode->grid_hidden[i], grid_hidden[unode->grids[i]]);
|
||||
for (const int i : grids.index_range()) {
|
||||
SWAP(BLI_bitmap *, unode->grid_hidden[i], grid_hidden[grids[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,23 +581,22 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode, bool *m
|
||||
|
||||
mask.finish();
|
||||
}
|
||||
else if (unode->maxgrid && subdiv_ccg != nullptr) {
|
||||
/* Multires restore. */
|
||||
CCGElem **grids, *grid;
|
||||
else if (!unode->grids.is_empty() && subdiv_ccg != nullptr) {
|
||||
const int gridsize = subdiv_ccg->grid_size;
|
||||
CCGKey key;
|
||||
int gridsize;
|
||||
BKE_subdiv_ccg_key_top_level(key, *subdiv_ccg);
|
||||
const Span<int> grid_indices = unode->grids;
|
||||
|
||||
grids = subdiv_ccg->grids.data();
|
||||
gridsize = subdiv_ccg->grid_size;
|
||||
BKE_subdiv_ccg_key_top_level(key, *subdiv_ccg);
|
||||
|
||||
blender::MutableSpan<float> mask = unode->mask;
|
||||
int index = 0;
|
||||
for (int j = 0; j < unode->totgrid; j++) {
|
||||
grid = grids[unode->grids[j]];
|
||||
MutableSpan<CCGElem *> grids = subdiv_ccg->grids;
|
||||
|
||||
for (int i = 0; i < gridsize * gridsize; i++) {
|
||||
std::swap(*CCG_elem_offset_mask(&key, grid, i), mask[index]);
|
||||
int index = 0;
|
||||
for (const int i : grid_indices.index_range()) {
|
||||
CCGElem *grid = grids[grid_indices[i]];
|
||||
for (const int j : IndexRange(gridsize * gridsize)) {
|
||||
std::swap(*CCG_elem_offset_mask(&key, grid, j), mask[index]);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@@ -917,7 +908,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
||||
bool *modified_mask_verts = nullptr;
|
||||
bool *modified_color_verts = nullptr;
|
||||
bool *modified_face_set_faces = nullptr;
|
||||
char *undo_modified_grids = nullptr;
|
||||
bool *undo_modified_grids = nullptr;
|
||||
bool use_multires_undo = false;
|
||||
|
||||
LISTBASE_FOREACH (SculptUndoNode *, unode, lb) {
|
||||
@@ -1012,12 +1003,12 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
||||
}
|
||||
|
||||
if (undo_modified_grids == nullptr) {
|
||||
undo_modified_grids = static_cast<char *>(
|
||||
MEM_callocN(sizeof(char) * unode->maxgrid, "undo_grids"));
|
||||
undo_modified_grids = static_cast<bool *>(
|
||||
MEM_callocN(sizeof(bool) * unode->maxgrid, "undo_grids"));
|
||||
}
|
||||
|
||||
for (int i = 0; i < unode->totgrid; i++) {
|
||||
undo_modified_grids[unode->grids[i]] = 1;
|
||||
for (const int grid : unode->grids) {
|
||||
undo_modified_grids[grid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1097,10 +1088,8 @@ static void sculpt_undo_free_list(ListBase *lb)
|
||||
SculptUndoNode *unode_next = unode->next;
|
||||
|
||||
if (unode->grid_hidden) {
|
||||
for (int i = 0; i < unode->totgrid; i++) {
|
||||
if (unode->grid_hidden[i]) {
|
||||
MEM_freeN(unode->grid_hidden[i]);
|
||||
}
|
||||
for (const int i : unode->grids.index_range()) {
|
||||
MEM_SAFE_FREE(unode->grid_hidden[i]);
|
||||
}
|
||||
MEM_freeN(unode->grid_hidden);
|
||||
}
|
||||
@@ -1172,21 +1161,18 @@ SculptUndoNode *SCULPT_undo_get_first_node()
|
||||
|
||||
static size_t sculpt_undo_alloc_and_store_hidden(SculptSession *ss, SculptUndoNode *unode)
|
||||
{
|
||||
PBVH *pbvh = ss->pbvh;
|
||||
PBVHNode *node = static_cast<PBVHNode *>(unode->node);
|
||||
const blender::Span<const BLI_bitmap *> grid_hidden = ss->subdiv_ccg->grid_hidden;
|
||||
|
||||
const int *grid_indices;
|
||||
int totgrid;
|
||||
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, nullptr, nullptr, nullptr);
|
||||
const Span<int> grid_indices = BKE_pbvh_node_get_grid_indices(*node);
|
||||
|
||||
size_t alloc_size = sizeof(*unode->grid_hidden) * size_t(totgrid);
|
||||
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 (int i = 0; i < totgrid; i++) {
|
||||
if (grid_hidden[grid_indices[i]]) {
|
||||
unode->grid_hidden[i] = static_cast<BLI_bitmap *>(
|
||||
MEM_dupallocN(grid_hidden[grid_indices[i]]));
|
||||
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 {
|
||||
@@ -1233,23 +1219,21 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
|
||||
{
|
||||
UndoSculpt *usculpt = sculpt_undo_get_nodes();
|
||||
SculptSession *ss = ob->sculpt;
|
||||
int totvert = 0;
|
||||
int allvert = 0;
|
||||
int totgrid = 0;
|
||||
int maxgrid = 0;
|
||||
int gridsize = 0;
|
||||
const int *grids = nullptr;
|
||||
|
||||
SculptUndoNode *unode = sculpt_undo_alloc_node_type(ob, type);
|
||||
unode->node = node;
|
||||
|
||||
if (node) {
|
||||
BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
|
||||
BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, &maxgrid, &gridsize, nullptr);
|
||||
int totvert = 0;
|
||||
int allvert = 0;
|
||||
BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
|
||||
|
||||
unode->totvert = totvert;
|
||||
Span<int> grids;
|
||||
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
|
||||
grids = BKE_pbvh_node_get_grid_indices(*node);
|
||||
}
|
||||
|
||||
unode->totvert = totvert;
|
||||
|
||||
bool need_loops = type == SCULPT_UNDO_COLOR;
|
||||
const bool need_faces = type == SCULPT_UNDO_FACE_SETS;
|
||||
|
||||
@@ -1281,13 +1265,13 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
|
||||
break;
|
||||
}
|
||||
case SCULPT_UNDO_HIDDEN: {
|
||||
if (maxgrid) {
|
||||
usculpt->undo_size += sculpt_undo_alloc_and_store_hidden(ss, unode);
|
||||
}
|
||||
else {
|
||||
if (grids.is_empty()) {
|
||||
unode->vert_hidden.resize(allvert);
|
||||
usculpt->undo_size += BLI_BITMAP_SIZE(allvert);
|
||||
}
|
||||
else {
|
||||
usculpt->undo_size += sculpt_undo_alloc_and_store_hidden(ss, unode);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1323,13 +1307,12 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
|
||||
}
|
||||
}
|
||||
|
||||
if (maxgrid) {
|
||||
if (!grids.is_empty()) {
|
||||
/* Multires. */
|
||||
unode->maxgrid = maxgrid;
|
||||
unode->totgrid = totgrid;
|
||||
unode->gridsize = gridsize;
|
||||
unode->maxgrid = ss->subdiv_ccg->grids.size();
|
||||
unode->gridsize = ss->subdiv_ccg->grid_size;
|
||||
|
||||
unode->grids.reinitialize(totgrid);
|
||||
unode->grids.reinitialize(grids.size());
|
||||
usculpt->undo_size += unode->grids.as_span().size_in_bytes();
|
||||
}
|
||||
else {
|
||||
@@ -1556,10 +1539,7 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
|
||||
*/
|
||||
|
||||
if (!unode->grids.is_empty()) {
|
||||
int totgrid;
|
||||
const int *grids;
|
||||
BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, nullptr, nullptr, nullptr);
|
||||
unode->grids.as_mutable_span().copy_from({grids, totgrid});
|
||||
unode->grids.as_mutable_span().copy_from(BKE_pbvh_node_get_grid_indices(*node));
|
||||
}
|
||||
else {
|
||||
unode->index.as_mutable_span().copy_from(BKE_pbvh_node_get_vert_indices(node));
|
||||
@@ -2038,7 +2018,8 @@ static void sculpt_undo_push_all_grids(Object *object)
|
||||
* to the current operation without making any stroke in between.
|
||||
*
|
||||
* Skip pushing nodes based on the following logic: on redo SCULPT_UNDO_COORDS will ensure
|
||||
* PBVH for the new base geometry, which will have same coordinates as if we create PBVH here. */
|
||||
* PBVH for the new base geometry, which will have same coordinates as if we create PBVH here.
|
||||
*/
|
||||
if (ss->pbvh == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user