Use refs in VoxelMeshBlock iteration, no null should be found

master
Marc Gilleron 2022-03-20 19:16:58 +00:00
parent f6b361f553
commit d6203a917a
5 changed files with 79 additions and 75 deletions

View File

@ -76,13 +76,13 @@ Ref<ArrayMesh> build_mesh(
struct BeforeUnloadMeshAction {
std::vector<Ref<ShaderMaterial>> &shader_material_pool;
void operator()(VoxelMeshBlock *block) {
void operator()(VoxelMeshBlock &block) {
VOXEL_PROFILE_SCOPE_NAMED("Recycle material");
// Recycle material
Ref<ShaderMaterial> sm = block->get_shader_material();
Ref<ShaderMaterial> sm = block.get_shader_material();
if (sm.is_valid()) {
shader_material_pool.push_back(sm);
block->set_shader_material(Ref<ShaderMaterial>());
block.set_shader_material(Ref<ShaderMaterial>());
}
}
};
@ -289,8 +289,8 @@ Ref<VoxelGenerator> VoxelLodTerrain::get_generator() const {
void VoxelLodTerrain::_on_gi_mode_changed() {
const GIMode gi_mode = get_gi_mode();
for (unsigned int lod_index = 0; lod_index < _update_data->state.lods.size(); ++lod_index) {
_mesh_maps_per_lod[lod_index].for_each_block([gi_mode](VoxelMeshBlock *block) { //
block->set_gi_mode(DirectMeshInstance::GIMode(gi_mode));
_mesh_maps_per_lod[lod_index].for_each_block([gi_mode](VoxelMeshBlock &block) { //
block.set_gi_mode(DirectMeshInstance::GIMode(gi_mode));
});
}
}
@ -406,8 +406,8 @@ void VoxelLodTerrain::set_mesh_block_size(unsigned int mesh_block_size) {
if (_instancer != nullptr) {
// Unload instances
VoxelInstancer *instancer = _instancer;
mesh_map.for_each_block([lod_index, instancer](VoxelMeshBlock *block) {
instancer->on_mesh_block_exit(block->position, lod_index);
mesh_map.for_each_block([lod_index, instancer](VoxelMeshBlock &block) {
instancer->on_mesh_block_exit(block.position, lod_index);
});
}
// Unload mesh blocks
@ -879,8 +879,8 @@ void VoxelLodTerrain::set_collision_layer(int layer) {
_collision_layer = layer;
for (unsigned int lod_index = 0; lod_index < lod_count; ++lod_index) {
VoxelMeshMap &mesh_map = _mesh_maps_per_lod[lod_index];
mesh_map.for_each_block([layer](VoxelMeshBlock *block) { //
block->set_collision_layer(layer);
mesh_map.for_each_block([layer](VoxelMeshBlock &block) { //
block.set_collision_layer(layer);
});
}
}
@ -895,8 +895,8 @@ void VoxelLodTerrain::set_collision_mask(int mask) {
_collision_mask = mask;
for (unsigned int lod_index = 0; lod_index < lod_count; ++lod_index) {
VoxelMeshMap &mesh_map = _mesh_maps_per_lod[lod_index];
mesh_map.for_each_block([mask](VoxelMeshBlock *block) { //
block->set_collision_mask(mask);
mesh_map.for_each_block([mask](VoxelMeshBlock &block) { //
block.set_collision_mask(mask);
});
}
}
@ -911,8 +911,8 @@ void VoxelLodTerrain::set_collision_margin(float margin) {
_collision_margin = margin;
for (unsigned int lod_index = 0; lod_index < lod_count; ++lod_index) {
VoxelMeshMap &mesh_map = _mesh_maps_per_lod[lod_index];
mesh_map.for_each_block([margin](VoxelMeshBlock *block) { //
block->set_collision_margin(margin);
mesh_map.for_each_block([margin](VoxelMeshBlock &block) { //
block.set_collision_margin(margin);
});
}
}
@ -984,8 +984,8 @@ void VoxelLodTerrain::_notification(int p_what) {
VoxelLodTerrainUpdateData::State &state = _update_data->state;
for (unsigned int lod_index = 0; lod_index < state.lods.size(); ++lod_index) {
VoxelMeshMap &mesh_map = _mesh_maps_per_lod[lod_index];
mesh_map.for_each_block([world](VoxelMeshBlock *block) { //
block->set_world(world);
mesh_map.for_each_block([world](VoxelMeshBlock &block) { //
block.set_world(world);
});
}
#ifdef TOOLS_ENABLED
@ -1001,8 +1001,8 @@ void VoxelLodTerrain::_notification(int p_what) {
VoxelLodTerrainUpdateData::State &state = _update_data->state;
for (unsigned int lod_index = 0; lod_index < state.lods.size(); ++lod_index) {
VoxelMeshMap &mesh_map = _mesh_maps_per_lod[lod_index];
mesh_map.for_each_block([](VoxelMeshBlock *block) { //
block->set_world(nullptr);
mesh_map.for_each_block([](VoxelMeshBlock &block) { //
block.set_world(nullptr);
});
}
#ifdef TOOLS_ENABLED
@ -1016,8 +1016,8 @@ void VoxelLodTerrain::_notification(int p_what) {
for (unsigned int lod_index = 0; lod_index < state.lods.size(); ++lod_index) {
VoxelMeshMap &mesh_map = _mesh_maps_per_lod[lod_index];
mesh_map.for_each_block([visible](VoxelMeshBlock *block) { //
block->set_parent_visible(visible);
mesh_map.for_each_block([visible](VoxelMeshBlock &block) { //
block.set_parent_visible(visible);
});
}
@ -1044,8 +1044,8 @@ void VoxelLodTerrain::_notification(int p_what) {
for (unsigned int lod_index = 0; lod_index < state.lods.size(); ++lod_index) {
VoxelMeshMap &mesh_map = _mesh_maps_per_lod[lod_index];
mesh_map.for_each_block([&transform](VoxelMeshBlock *block) { //
block->set_parent_transform(transform);
mesh_map.for_each_block([&transform](VoxelMeshBlock &block) { //
block.set_parent_transform(transform);
});
}
} break;
@ -1608,9 +1608,9 @@ void VoxelLodTerrain::get_meshed_block_positions_at_lod(int lod_index, std::vect
const VoxelMeshMap &mesh_map = _mesh_maps_per_lod[lod_index];
mesh_map.for_each_block([&out_positions](const VoxelMeshBlock *block) {
if (block->has_mesh()) {
out_positions.push_back(block->position);
mesh_map.for_each_block([&out_positions](const VoxelMeshBlock &block) {
if (block.has_mesh()) {
out_positions.push_back(block.position);
}
});
}
@ -2133,8 +2133,8 @@ Error VoxelLodTerrain::_b_debug_dump_as_scene(String fpath, bool include_instanc
for (unsigned int lod_index = 0; lod_index < lod_count; ++lod_index) {
const VoxelMeshMap &mesh_map = _mesh_maps_per_lod[lod_index];
mesh_map.for_each_block([root](const VoxelMeshBlock *block) {
block->for_each_mesh_instance_with_transform([root, block](const DirectMeshInstance &dmi, Transform3D t) {
mesh_map.for_each_block([root](const VoxelMeshBlock &block) {
block.for_each_mesh_instance_with_transform([root, &block](const DirectMeshInstance &dmi, Transform3D t) {
Ref<Mesh> mesh = dmi.get_mesh();
if (mesh.is_valid()) {
@ -2142,7 +2142,7 @@ Error VoxelLodTerrain::_b_debug_dump_as_scene(String fpath, bool include_instanc
mi->set_mesh(mesh);
mi->set_transform(t);
// TODO Transition mesh visibility?
mi->set_visible(block->is_visible());
mi->set_visible(block.is_visible());
root->add_child(mi);
// The owner must be set after adding to parent
mi->set_owner(root);

View File

@ -16,7 +16,7 @@ namespace zylann::voxel {
// Stores mesh and collider for one chunk of the rendered volume.
// It doesn't store voxel data, because it may be using different block size, or different data structure.
class VoxelMeshBlock {
class VoxelMeshBlock : public NonCopyable {
public:
// TODO This is now only relevant for `VoxelTerrain`
enum MeshState {

View File

@ -47,7 +47,7 @@ public:
unsigned int get_lod_index() const;
struct NoAction {
inline void operator()(VoxelMeshBlock *block) {}
inline void operator()(VoxelMeshBlock &block) {}
};
template <typename Action_T>
@ -63,7 +63,7 @@ public:
#endif
VoxelMeshBlock *block = _blocks[i];
ERR_FAIL_COND(block == nullptr);
pre_delete(block);
pre_delete(*block);
queue_free_mesh_block(block);
remove_block_internal(bpos, i);
}
@ -84,16 +84,22 @@ public:
template <typename Op_T>
inline void for_each_block(Op_T op) {
for (auto it = _blocks.begin(); it != _blocks.end(); ++it) {
// TODO Send a ref? We only send non-null blocks
op(*it);
VoxelMeshBlock *block = *it;
#ifdef DEBUG_ENABLED
CRASH_COND(block == nullptr);
#endif
op(*block);
}
}
template <typename Op_T>
inline void for_each_block(Op_T op) const {
for (auto it = _blocks.begin(); it != _blocks.end(); ++it) {
// TODO Send a ref? We only send non-null blocks
op(*it);
const VoxelMeshBlock *block = *it;
#ifdef DEBUG_ENABLED
CRASH_COND(block == nullptr);
#endif
op(*block);
}
}

View File

@ -263,8 +263,8 @@ void VoxelTerrain::_on_stream_params_changed() {
void VoxelTerrain::_on_gi_mode_changed() {
const GIMode gi_mode = get_gi_mode();
_mesh_map.for_each_block([gi_mode](VoxelMeshBlock *block) { //
block->set_gi_mode(DirectMeshInstance::GIMode(gi_mode));
_mesh_map.for_each_block([gi_mode](VoxelMeshBlock &block) { //
block.set_gi_mode(DirectMeshInstance::GIMode(gi_mode));
});
}
@ -316,8 +316,8 @@ void VoxelTerrain::set_generate_collisions(bool enabled) {
void VoxelTerrain::set_collision_layer(int layer) {
_collision_layer = layer;
_mesh_map.for_each_block([layer](VoxelMeshBlock *block) { //
block->set_collision_layer(layer);
_mesh_map.for_each_block([layer](VoxelMeshBlock &block) { //
block.set_collision_layer(layer);
});
}
@ -327,8 +327,8 @@ int VoxelTerrain::get_collision_layer() const {
void VoxelTerrain::set_collision_mask(int mask) {
_collision_mask = mask;
_mesh_map.for_each_block([mask](VoxelMeshBlock *block) { //
block->set_collision_mask(mask);
_mesh_map.for_each_block([mask](VoxelMeshBlock &block) { //
block.set_collision_mask(mask);
});
}
@ -338,8 +338,8 @@ int VoxelTerrain::get_collision_mask() const {
void VoxelTerrain::set_collision_margin(float margin) {
_collision_margin = margin;
_mesh_map.for_each_block([margin](VoxelMeshBlock *block) { //
block->set_collision_margin(margin);
_mesh_map.for_each_block([margin](VoxelMeshBlock &block) { //
block.set_collision_margin(margin);
});
}
@ -400,14 +400,12 @@ Ref<Material> VoxelTerrain::get_material(unsigned int id) const {
return _materials[id];
}
void VoxelTerrain::try_schedule_mesh_update(VoxelMeshBlock *mesh_block) {
CRASH_COND(mesh_block == nullptr);
if (mesh_block->get_mesh_state() == VoxelMeshBlock::MESH_UPDATE_NOT_SENT) {
void VoxelTerrain::try_schedule_mesh_update(VoxelMeshBlock &mesh_block) {
if (mesh_block.get_mesh_state() == VoxelMeshBlock::MESH_UPDATE_NOT_SENT) {
// Already in the list
return;
}
if (mesh_block->mesh_viewers.get() == 0 && mesh_block->collision_viewers.get() == 0) {
if (mesh_block.mesh_viewers.get() == 0 && mesh_block.collision_viewers.get() == 0) {
// No viewers want mesh on this block (why even call this function then?)
return;
}
@ -416,7 +414,7 @@ void VoxelTerrain::try_schedule_mesh_update(VoxelMeshBlock *mesh_block) {
const Box3i bounds_in_data_blocks = _bounds_in_voxels.downscaled(get_data_block_size());
// Pad by 1 because meshing needs neighbors
const Box3i data_box =
Box3i(mesh_block->position * render_to_data_factor, Vector3iUtil::create(render_to_data_factor))
Box3i(mesh_block.position * render_to_data_factor, Vector3iUtil::create(render_to_data_factor))
.padded(1)
.clipped(bounds_in_data_blocks);
@ -424,13 +422,15 @@ void VoxelTerrain::try_schedule_mesh_update(VoxelMeshBlock *mesh_block) {
ERR_FAIL_COND(data_box.is_empty());
// Check if we have the data
const bool data_available = data_box.all_cells_match([this](Vector3i bpos) { return _data_map.has_block(bpos); });
const bool data_available = data_box.all_cells_match([this](Vector3i bpos) { //
return _data_map.has_block(bpos);
});
if (data_available) {
// Regardless of if the updater is updating the block already,
// the block could have been modified again so we schedule another update
mesh_block->set_mesh_state(VoxelMeshBlock::MESH_UPDATE_NOT_SENT);
_blocks_pending_update.push_back(mesh_block->position);
mesh_block.set_mesh_state(VoxelMeshBlock::MESH_UPDATE_NOT_SENT);
_blocks_pending_update.push_back(mesh_block.position);
}
}
@ -490,6 +490,7 @@ void VoxelTerrain::view_mesh_block(Vector3i bpos, bool mesh_flag, bool collision
block->set_world(get_world_3d());
_mesh_map.set_block(bpos, block);
}
CRASH_COND(block == nullptr);
if (mesh_flag) {
block->mesh_viewers.add();
@ -501,7 +502,7 @@ void VoxelTerrain::view_mesh_block(Vector3i bpos, bool mesh_flag, bool collision
// This is needed in case a viewer wants to view meshes in places data blocks are already present.
// Before that, meshes were updated only when a data block was loaded or modified,
// so changing block size or viewer flags did not make meshes appear.
try_schedule_mesh_update(block);
try_schedule_mesh_update(*block);
// TODO viewers with varying flags during the game is not supported at the moment.
// They have to be re-created, which may cause world re-load...
@ -617,11 +618,11 @@ void VoxelTerrain::unload_data_block(Vector3i bpos) {
void VoxelTerrain::unload_mesh_block(Vector3i bpos) {
std::vector<Vector3i> &blocks_pending_update = _blocks_pending_update;
_mesh_map.remove_block(bpos, [&blocks_pending_update](const VoxelMeshBlock *block) {
if (block->get_mesh_state() == VoxelMeshBlock::MESH_UPDATE_NOT_SENT) {
_mesh_map.remove_block(bpos, [&blocks_pending_update](const VoxelMeshBlock &block) {
if (block.get_mesh_state() == VoxelMeshBlock::MESH_UPDATE_NOT_SENT) {
// That block was in the list of blocks to update later in the process loop, we'll need to unregister it.
// We expect that block to be in that list. If it isn't, something wrong happened with its state.
ERR_FAIL_COND(!unordered_remove_value(blocks_pending_update, block->position));
ERR_FAIL_COND(!unordered_remove_value(blocks_pending_update, block.position));
}
});
}
@ -668,14 +669,6 @@ void VoxelTerrain::start_updater() {
}
void VoxelTerrain::stop_updater() {
struct ResetMeshStateAction {
void operator()(VoxelMeshBlock *block) {
if (block->get_mesh_state() == VoxelMeshBlock::MESH_UPDATE_SENT) {
block->set_mesh_state(VoxelMeshBlock::MESH_UPDATE_NOT_SENT);
}
}
};
VoxelServer::get_singleton()->invalidate_volume_mesh_requests(_volume_id);
VoxelServer::get_singleton()->set_volume_mesher(_volume_id, Ref<VoxelMesher>());
@ -684,12 +677,15 @@ void VoxelTerrain::stop_updater() {
_blocks_pending_update.clear();
ResetMeshStateAction a;
_mesh_map.for_each_block(a);
_mesh_map.for_each_block([](VoxelMeshBlock &block) {
if (block.get_mesh_state() == VoxelMeshBlock::MESH_UPDATE_SENT) {
block.set_mesh_state(VoxelMeshBlock::MESH_UPDATE_NOT_SENT);
}
});
}
void VoxelTerrain::remesh_all_blocks() {
_mesh_map.for_each_block([this](VoxelMeshBlock *block) { //
_mesh_map.for_each_block([this](VoxelMeshBlock &block) { //
try_schedule_mesh_update(block);
});
}
@ -743,7 +739,9 @@ void VoxelTerrain::stop_streamer() {
void VoxelTerrain::reset_map() {
// Discard everything, to reload it all
_data_map.for_each_block([this](VoxelDataBlock *block) { emit_data_block_unloaded(block); });
_data_map.for_each_block([this](VoxelDataBlock *block) { //
emit_data_block_unloaded(block);
});
_data_map.create(get_data_block_size_pow2(), 0);
_mesh_map.create(get_mesh_block_size_pow2(), 0);
@ -769,7 +767,7 @@ void VoxelTerrain::try_schedule_mesh_update_from_data(const Box3i &box_in_voxels
// There isn't necessarily a mesh block, if the edit happens in a boundary,
// or if it is done next to a viewer that doesn't need meshes
if (block != nullptr) {
try_schedule_mesh_update(block);
try_schedule_mesh_update(*block);
}
});
}
@ -799,16 +797,16 @@ void VoxelTerrain::_notification(int p_what) {
struct SetWorldAction {
World3D *world;
SetWorldAction(World3D *w) : world(w) {}
void operator()(VoxelMeshBlock *block) {
block->set_world(world);
void operator()(VoxelMeshBlock &block) {
block.set_world(world);
}
};
struct SetParentVisibilityAction {
bool visible;
SetParentVisibilityAction(bool v) : visible(v) {}
void operator()(VoxelMeshBlock *block) {
block->set_parent_visible(visible);
void operator()(VoxelMeshBlock &block) {
block.set_parent_visible(visible);
}
};
@ -851,8 +849,8 @@ void VoxelTerrain::_notification(int p_what) {
return;
}
_mesh_map.for_each_block([&transform](VoxelMeshBlock *block) { //
block->set_parent_transform(transform);
_mesh_map.for_each_block([&transform](VoxelMeshBlock &block) { //
block.set_parent_transform(transform);
});
} break;

View File

@ -161,7 +161,7 @@ private:
void unload_data_block(Vector3i bpos);
void unload_mesh_block(Vector3i bpos);
//void make_data_block_dirty(Vector3i bpos);
void try_schedule_mesh_update(VoxelMeshBlock *block);
void try_schedule_mesh_update(VoxelMeshBlock &block);
void try_schedule_mesh_update_from_data(const Box3i &box_in_voxels);
void save_all_modified_blocks(bool with_copy);