diff --git a/providers/voxel_provider.cpp b/providers/voxel_provider.cpp index db5e258..ad3d5e3 100644 --- a/providers/voxel_provider.cpp +++ b/providers/voxel_provider.cpp @@ -1,43 +1,47 @@ #include "voxel_provider.h" #include -void VoxelProvider::emerge_block(Ref out_buffer, Vector3i origin_in_voxels) { +void VoxelProvider::emerge_block(Ref out_buffer, Vector3i origin_in_voxels, int lod) { ERR_FAIL_COND(out_buffer.is_null()); ScriptInstance *script = get_script_instance(); if (script) { // Call script to generate buffer Variant arg1 = out_buffer; Variant arg2 = origin_in_voxels.to_vec3(); - const Variant *args[2] = { &arg1, &arg2 }; + Variant arg3 = lod; + const Variant *args[3] = { &arg1, &arg2, &arg3 }; //Variant::CallError err; // wut - script->call_multilevel("emerge_block", args, 2); + script->call("emerge_block", args, 3); } } -void VoxelProvider::immerge_block(Ref buffer, Vector3i origin_in_voxels) { +void VoxelProvider::immerge_block(Ref buffer, Vector3i origin_in_voxels, int lod) { ERR_FAIL_COND(buffer.is_null()); ScriptInstance *script = get_script_instance(); if (script) { // Call script to save buffer Variant arg1 = buffer; Variant arg2 = origin_in_voxels.to_vec3(); - const Variant *args[2] = { &arg1, &arg2 }; + Variant arg3 = lod; + const Variant *args[3] = { &arg1, &arg2, &arg3 }; //Variant::CallError err; // wut - script->call_multilevel("immerge_block", args, 2); + script->call("immerge_block", args, 3); } } -void VoxelProvider::_emerge_block(Ref out_buffer, Vector3 origin_in_voxels) { - emerge_block(out_buffer, Vector3i(origin_in_voxels)); +void VoxelProvider::_emerge_block(Ref out_buffer, Vector3 origin_in_voxels, int lod) { + ERR_FAIL_COND(lod < 0); + emerge_block(out_buffer, Vector3i(origin_in_voxels), lod); } -void VoxelProvider::_immerge_block(Ref buffer, Vector3 origin_in_voxels) { - immerge_block(buffer, Vector3i(origin_in_voxels)); +void VoxelProvider::_immerge_block(Ref buffer, Vector3 origin_in_voxels, int lod) { + ERR_FAIL_COND(lod < 0); + immerge_block(buffer, Vector3i(origin_in_voxels), lod); } void VoxelProvider::_bind_methods() { // Note: C++ inheriting classes don't need to re-bind these, because they are bindings that call the actual virtual methods - ClassDB::bind_method(D_METHOD("emerge_block", "out_buffer", "origin_in_voxels"), &VoxelProvider::_emerge_block); - ClassDB::bind_method(D_METHOD("immerge_block", "buffer", "origin_in_voxels"), &VoxelProvider::_immerge_block); + ClassDB::bind_method(D_METHOD("emerge_block", "out_buffer", "origin_in_voxels", "lod"), &VoxelProvider::_emerge_block); + ClassDB::bind_method(D_METHOD("immerge_block", "buffer", "origin_in_voxels", "lod"), &VoxelProvider::_immerge_block); } diff --git a/providers/voxel_provider.h b/providers/voxel_provider.h index a7e016a..e00831e 100644 --- a/providers/voxel_provider.h +++ b/providers/voxel_provider.h @@ -7,14 +7,14 @@ class VoxelProvider : public Resource { GDCLASS(VoxelProvider, Resource) public: - virtual void emerge_block(Ref out_buffer, Vector3i origin_in_voxels); - virtual void immerge_block(Ref buffer, Vector3i origin_in_voxels); + virtual void emerge_block(Ref out_buffer, Vector3i origin_in_voxels, int lod); + virtual void immerge_block(Ref buffer, Vector3i origin_in_voxels, int lod); protected: static void _bind_methods(); - void _emerge_block(Ref out_buffer, Vector3 origin_in_voxels); - void _immerge_block(Ref buffer, Vector3 origin_in_voxels); + void _emerge_block(Ref out_buffer, Vector3 origin_in_voxels, int lod); + void _immerge_block(Ref buffer, Vector3 origin_in_voxels, int lod); }; #endif // VOXEL_PROVIDER_H diff --git a/providers/voxel_provider_image.cpp b/providers/voxel_provider_image.cpp index 7871fa2..ae32c6d 100644 --- a/providers/voxel_provider_image.cpp +++ b/providers/voxel_provider_image.cpp @@ -41,7 +41,12 @@ inline float get_height_blurred(Image &im, int x, int y) { } // namespace -void VoxelProviderImage::emerge_block(Ref p_out_buffer, Vector3i origin_in_voxels) { +void VoxelProviderImage::emerge_block(Ref p_out_buffer, Vector3i origin_in_voxels, int lod) { + + if (lod != 0) { + // TODO Handle higher lods + return; + } int ox = origin_in_voxels.x; int oy = origin_in_voxels.y; diff --git a/providers/voxel_provider_image.h b/providers/voxel_provider_image.h index 5d34211..cd80b9a 100644 --- a/providers/voxel_provider_image.h +++ b/providers/voxel_provider_image.h @@ -17,7 +17,7 @@ public: void set_channel(VoxelBuffer::ChannelId channel); int get_channel() const; - void emerge_block(Ref p_out_buffer, Vector3i origin_in_voxels); + void emerge_block(Ref p_out_buffer, Vector3i origin_in_voxels, int lod); private: static void _bind_methods(); diff --git a/providers/voxel_provider_test.cpp b/providers/voxel_provider_test.cpp index 8516c41..855fbf6 100644 --- a/providers/voxel_provider_test.cpp +++ b/providers/voxel_provider_test.cpp @@ -29,22 +29,27 @@ void VoxelProviderTest::set_pattern_offset(Vector3i offset) { _pattern_offset = offset; } -void VoxelProviderTest::emerge_block(Ref out_buffer, Vector3i origin) { +void VoxelProviderTest::emerge_block(Ref out_buffer, Vector3i origin, int lod) { ERR_FAIL_COND(out_buffer.is_null()); + if (lod != 0) { + // TODO Handle higher lods + return; + } + switch (_mode) { case MODE_FLAT: - generate_block_flat(**out_buffer, origin); + generate_block_flat(**out_buffer, origin, lod); break; case MODE_WAVES: - generate_block_waves(**out_buffer, origin); + generate_block_waves(**out_buffer, origin, lod); break; } } -void VoxelProviderTest::generate_block_flat(VoxelBuffer &out_buffer, Vector3i origin) { +void VoxelProviderTest::generate_block_flat(VoxelBuffer &out_buffer, Vector3i origin, int lod) { // TODO Don't expect a block pos, but a voxel pos! Vector3i size = out_buffer.get_size(); @@ -62,7 +67,7 @@ void VoxelProviderTest::generate_block_flat(VoxelBuffer &out_buffer, Vector3i or } } -void VoxelProviderTest::generate_block_waves(VoxelBuffer &out_buffer, Vector3i origin) { +void VoxelProviderTest::generate_block_waves(VoxelBuffer &out_buffer, Vector3i origin, int lod) { // TODO Don't expect a block pos, but a voxel pos! Vector3i size = out_buffer.get_size(); diff --git a/providers/voxel_provider_test.h b/providers/voxel_provider_test.h index 9a48e76..def4d4b 100644 --- a/providers/voxel_provider_test.h +++ b/providers/voxel_provider_test.h @@ -14,7 +14,7 @@ public: VoxelProviderTest(); - virtual void emerge_block(Ref out_buffer, Vector3i origin); + virtual void emerge_block(Ref out_buffer, Vector3i origin, int lod); void set_mode(Mode mode); Mode get_mode() const { return _mode; } @@ -29,8 +29,8 @@ public: void set_pattern_offset(Vector3i offset); protected: - void generate_block_flat(VoxelBuffer &out_buffer, Vector3i origin); - void generate_block_waves(VoxelBuffer &out_buffer, Vector3i origin); + void generate_block_flat(VoxelBuffer &out_buffer, Vector3i origin, int lod); + void generate_block_waves(VoxelBuffer &out_buffer, Vector3i origin, int lod); static void _bind_methods(); diff --git a/terrain/voxel_provider_thread.cpp b/terrain/voxel_provider_thread.cpp index b2f1dec..8b22411 100644 --- a/terrain/voxel_provider_thread.cpp +++ b/terrain/voxel_provider_thread.cpp @@ -89,7 +89,7 @@ void VoxelProviderThread::thread_func() { if (!_input.blocks_to_emerge.empty()) { - Vector3i block_pos = _input.blocks_to_emerge[emerge_index]; + EmergeInput block = _input.blocks_to_emerge[emerge_index]; ++emerge_index; if (emerge_index >= _input.blocks_to_emerge.size()) { @@ -101,9 +101,9 @@ void VoxelProviderThread::thread_func() { buffer->create(bs, bs, bs); // Query voxel provider - Vector3i block_origin_in_voxels = block_pos * bs; + Vector3i block_origin_in_voxels = block.block_position * bs; uint64_t time_before = OS::get_singleton()->get_ticks_usec(); - _voxel_provider->emerge_block(buffer, block_origin_in_voxels); + _voxel_provider->emerge_block(buffer, block_origin_in_voxels, block.lod); uint64_t time_taken = OS::get_singleton()->get_ticks_usec() - time_before; // Do some stats @@ -148,9 +148,12 @@ void VoxelProviderThread::thread_func() { // Sorts distance to viewer // The closest block will be the first one in the array struct BlockPositionComparator { + // In LOD0 block coordinates Vector3i center; - inline bool operator()(const Vector3i &a, const Vector3i &b) const { - return a.distance_sq(center) < b.distance_sq(center); + inline bool operator()(const VoxelProviderThread::EmergeInput &a, const VoxelProviderThread::EmergeInput &b) const { + int da = (a.block_position * (1 << a.lod)).distance_sq(center); + int db = (b.block_position * (1 << b.lod)).distance_sq(center); + return da < db; } }; @@ -197,7 +200,7 @@ void VoxelProviderThread::thread_sync(int emerge_index, Stats stats) { if (!_input.blocks_to_emerge.empty()) { // Re-sort priority - SortArray sorter; + SortArray sorter; sorter.compare.center = _input.priority_block_position; sorter.sort(_input.blocks_to_emerge.ptrw(), _input.blocks_to_emerge.size()); } diff --git a/terrain/voxel_provider_thread.h b/terrain/voxel_provider_thread.h index dd3bf6c..f376c93 100644 --- a/terrain/voxel_provider_thread.h +++ b/terrain/voxel_provider_thread.h @@ -14,11 +14,17 @@ public: struct ImmergeInput { Vector3i origin; Ref voxels; + int lod = 0; + }; + + struct EmergeInput { + Vector3i block_position; + int lod = 0; }; struct InputData { Vector blocks_to_immerge; - Vector blocks_to_emerge; + Vector blocks_to_emerge; Vector3i priority_block_position; inline bool is_empty() { @@ -29,19 +35,14 @@ public: struct EmergeOutput { Ref voxels; Vector3i origin_in_voxels; + int lod = 0; }; struct Stats { - bool first; - uint64_t min_time; - uint64_t max_time; - int remaining_blocks; - - Stats() : - first(true), - min_time(0), - max_time(0), - remaining_blocks(0) {} + bool first = true; + uint64_t min_time = 0; + uint64_t max_time = 0; + int remaining_blocks = 0; }; struct OutputData { diff --git a/terrain/voxel_terrain.cpp b/terrain/voxel_terrain.cpp index abbb2b4..2e56e19 100644 --- a/terrain/voxel_terrain.cpp +++ b/terrain/voxel_terrain.cpp @@ -186,6 +186,7 @@ void VoxelTerrain::make_block_dirty(Vector3i bpos) { _dirty_blocks[bpos] = BLOCK_UPDATE_NOT_SENT; } else { + _blocks_pending_load.push_back(bpos); _dirty_blocks[bpos] = BLOCK_LOAD; } @@ -605,8 +606,13 @@ void VoxelTerrain::_process() { VoxelProviderThread::InputData input; input.priority_block_position = viewer_block_pos; - input.blocks_to_emerge.append_array(_blocks_pending_load); - //input.blocks_to_immerge.append_array(); + + for (int i = 0; i < _blocks_pending_load.size(); ++i) { + VoxelProviderThread::EmergeInput input_block; + input_block.block_position = _blocks_pending_load[i]; + input_block.lod = 0; + input.blocks_to_emerge.push_back(input_block); + } //print_line(String("Sending {0} block requests").format(varray(input.blocks_to_emerge.size()))); _blocks_pending_load.clear();