diff --git a/terrain/voxel_lod_terrain.cpp b/terrain/voxel_lod_terrain.cpp index 20612cb..b73b2d7 100644 --- a/terrain/voxel_lod_terrain.cpp +++ b/terrain/voxel_lod_terrain.cpp @@ -527,6 +527,8 @@ void VoxelLodTerrain::_process() { VoxelProviderThread::InputData input; input.priority_block_position = viewer_block_pos; + input.use_exclusive_region = true; + input.exclusive_region_extent = get_block_region_extent(); for (unsigned int lod_index = 0; lod_index < get_lod_count(); ++lod_index) { Lod &lod = _lods[lod_index]; @@ -598,6 +600,9 @@ void VoxelLodTerrain::_process() { // Send mesh updates { VoxelMeshUpdater::Input input; + input.priority_position = viewer_block_pos; + input.use_exclusive_region = true; + input.exclusive_region_extent = get_block_region_extent(); for (unsigned int lod_index = 0; lod_index < get_lod_count(); ++lod_index) { Lod &lod = _lods[lod_index]; diff --git a/terrain/voxel_mesh_updater.cpp b/terrain/voxel_mesh_updater.cpp index 61de07c..eb7c612 100644 --- a/terrain/voxel_mesh_updater.cpp +++ b/terrain/voxel_mesh_updater.cpp @@ -73,7 +73,7 @@ void VoxelMeshUpdater::push(const Input &input) { if (index) { // The block is already in the update queue, replace it ++replaced_blocks; - _shared_input.blocks.write[*index] = block; + _shared_input.blocks[*index] = block; } else { @@ -88,6 +88,12 @@ void VoxelMeshUpdater::push(const Input &input) { } _shared_input.priority_position = input.priority_position; + + if (input.use_exclusive_region) { + _shared_input.use_exclusive_region = true; + _shared_input.exclusive_region_extent = input.exclusive_region_extent; + } + should_run = !_shared_input.is_empty(); } @@ -209,10 +215,12 @@ static void scale_mesh_data(VoxelMesher::Output &data, float factor) { // so you won't trash performance with pointless allocations surface[Mesh::ARRAY_VERTEX] = Variant(); - PoolVector3Array::Write w = positions.write(); - int len = positions.size(); - for (int j = 0; j < len; ++j) { - w[j] = w[j] * factor; + { + PoolVector3Array::Write w = positions.write(); + int len = positions.size(); + for (int j = 0; j < len; ++j) { + w[j] = w[j] * factor; + } } // Thank you @@ -282,9 +290,15 @@ void VoxelMeshUpdater::thread_sync(int queue_index, Stats stats) { // Get input MutexLock lock(_input_mutex); - _input.blocks.append_array(_shared_input.blocks); + append_array(_input.blocks, _shared_input.blocks); + _input.priority_position = _shared_input.priority_position; + if (_shared_input.use_exclusive_region) { + _input.use_exclusive_region = true; + _input.exclusive_region_extent = _shared_input.exclusive_region_extent; + } + _shared_input.blocks.clear(); for (unsigned int lod_index = 0; lod_index < MAX_LOD; ++lod_index) { @@ -307,12 +321,39 @@ void VoxelMeshUpdater::thread_sync(int queue_index, Stats stats) { _output.blocks.clear(); } + // Cancel blocks outside exclusive region + //int dropped_count = 0; + if (_input.use_exclusive_region) { + for (int i = 0; i < _input.blocks.size(); ++i) { + const InputBlock &ib = _input.blocks[i]; + + Rect3i box = Rect3i::from_center_extents(_input.priority_position >> ib.lod, Vector3i(_input.exclusive_region_extent)); + + if (!box.contains(ib.position)) { + + Vector3i shifted_block_pos = _input.blocks.back().position; + + _input.blocks[i] = _input.blocks.back(); + _input.blocks.pop_back(); + + _block_indexes[ib.lod].erase(ib.position); + _block_indexes[ib.lod][shifted_block_pos] = i; + + //++dropped_count; + } + } + } + + // if (dropped_count > 0) { + // print_line(String("Dropped {0} blocks to mesh from thread").format(varray(dropped_count))); + // } + if (!_input.blocks.empty() && needs_sort) { // Re-sort priority SortArray sorter; sorter.compare.center = _input.priority_position; - sorter.sort(_input.blocks.ptrw(), _input.blocks.size()); + sorter.sort(_input.blocks.data(), _input.blocks.size()); } } diff --git a/terrain/voxel_mesh_updater.h b/terrain/voxel_mesh_updater.h index 0dd2a47..0caa3d5 100644 --- a/terrain/voxel_mesh_updater.h +++ b/terrain/voxel_mesh_updater.h @@ -20,8 +20,10 @@ public: }; struct Input { - Vector blocks; - Vector3i priority_position; + std::vector blocks; + Vector3i priority_position; // In LOD0 block coordinates + int exclusive_region_extent = 0; + bool use_exclusive_region = false; bool is_empty() const { return blocks.empty(); diff --git a/terrain/voxel_provider_thread.cpp b/terrain/voxel_provider_thread.cpp index 367edb2..b0862f6 100644 --- a/terrain/voxel_provider_thread.cpp +++ b/terrain/voxel_provider_thread.cpp @@ -42,10 +42,15 @@ void VoxelProviderThread::push(const InputData &input) { // TODO If the same request is sent twice, keep only the latest one - _shared_input.blocks_to_emerge.append_array(input.blocks_to_emerge); - _shared_input.blocks_to_immerge.append_array(input.blocks_to_immerge); + append_array(_shared_input.blocks_to_emerge, input.blocks_to_emerge); + append_array(_shared_input.blocks_to_immerge, input.blocks_to_immerge); _shared_input.priority_block_position = input.priority_block_position; + if (input.use_exclusive_region) { + _shared_input.use_exclusive_region = true; + _shared_input.exclusive_region_extent = input.exclusive_region_extent; + } + should_run = !_shared_input.is_empty(); } @@ -112,10 +117,12 @@ void VoxelProviderThread::thread_func() { stats.min_time = time_taken; stats.max_time = time_taken; } else { - if (time_taken < stats.min_time) + if (time_taken < stats.min_time) { stats.min_time = time_taken; - if (time_taken > stats.max_time) + } + if (time_taken > stats.max_time) { stats.max_time = time_taken; + } } EmergeOutput eo; @@ -137,8 +144,9 @@ void VoxelProviderThread::thread_func() { } } - if (_thread_exit) + if (_thread_exit) { break; + } // Wait for future wake-up _semaphore->wait(); @@ -183,12 +191,18 @@ void VoxelProviderThread::thread_sync(int emerge_index, Stats stats) { // Get input MutexLock lock(_input_mutex); - _input.blocks_to_emerge.append_array(_shared_input.blocks_to_emerge); - _input.blocks_to_immerge.append_array(_shared_input.blocks_to_immerge); + append_array(_input.blocks_to_emerge, _shared_input.blocks_to_emerge); + append_array(_input.blocks_to_immerge, _shared_input.blocks_to_immerge); _input.priority_block_position = _shared_input.priority_block_position; + if (_shared_input.use_exclusive_region) { + _input.use_exclusive_region = true; + _input.exclusive_region_extent = _shared_input.exclusive_region_extent; + } + _shared_input.blocks_to_emerge.clear(); _shared_input.blocks_to_immerge.clear(); + _shared_input.use_exclusive_region = false; } stats.remaining_blocks = _input.blocks_to_emerge.size(); @@ -204,12 +218,32 @@ void VoxelProviderThread::thread_sync(int emerge_index, Stats stats) { _output.clear(); } + // Cancel blocks outside exclusive region + //int dropped_count = 0; + if (_input.use_exclusive_region) { + for (int i = 0; i < _input.blocks_to_emerge.size(); ++i) { + const EmergeInput &ei = _input.blocks_to_emerge[i]; + + Rect3i box = Rect3i::from_center_extents(_input.priority_block_position >> ei.lod, Vector3i(_input.exclusive_region_extent)); + + if (!box.contains(ei.block_position)) { + _input.blocks_to_emerge[i] = _input.blocks_to_emerge.back(); + _input.blocks_to_emerge.pop_back(); + //++dropped_count; + } + } + } + + // if (dropped_count > 0) { + // print_line(String("Dropped {0} blocks to load from thread").format(varray(dropped_count))); + // } + if (!_input.blocks_to_emerge.empty()) { // Re-sort priority SortArray sorter; sorter.compare.center = _input.priority_block_position; - sorter.sort(_input.blocks_to_emerge.ptrw(), _input.blocks_to_emerge.size()); + sorter.sort(_input.blocks_to_emerge.data(), _input.blocks_to_emerge.size()); } } diff --git a/terrain/voxel_provider_thread.h b/terrain/voxel_provider_thread.h index 5efce25..c40fc79 100644 --- a/terrain/voxel_provider_thread.h +++ b/terrain/voxel_provider_thread.h @@ -1,8 +1,9 @@ #ifndef VOXEL_PROVIDER_THREAD_H #define VOXEL_PROVIDER_THREAD_H -#include "../math/vector3i.h" +#include "../math/rect3i.h" #include +#include class VoxelProvider; class VoxelBuffer; @@ -23,9 +24,11 @@ public: }; struct InputData { - Vector blocks_to_immerge; - Vector blocks_to_emerge; - Vector3i priority_block_position; + std::vector blocks_to_immerge; + std::vector blocks_to_emerge; + Vector3i priority_block_position; // In LOD0 block coordinates + int exclusive_region_extent = 0; + bool use_exclusive_region = false; inline bool is_empty() { return blocks_to_emerge.empty() && blocks_to_immerge.empty(); diff --git a/util/utility.h b/util/utility.h index 3736711..8a8e245 100644 --- a/util/utility.h +++ b/util/utility.h @@ -103,4 +103,9 @@ inline bool is_mesh_empty(Ref mesh_ref) { return false; } +template +inline void append_array(std::vector &dst, const std::vector &src) { + dst.insert(dst.end(), src.begin(), src.end()); +} + #endif // HEADER_VOXEL_UTILITY_H