diff --git a/CHANGELOG.md b/CHANGELOG.md index 09ddef75..28a31ffa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ Semver is not yet in place, so each version can have breaking changes, although - Voxel nodes can be moved, scaled and rotated - Voxel nodes can be limited to specific bounds, rather than being infinitely paging volumes (multiples of block size) +- Smooth voxels + - Shaders now have access to the transform of each block, useful for triplanar mapping on moving volumes + - Blocky voxels - Introduced a second blocky mesher dedicated to colored cubes, with greedy meshing and palette support - Replaced `transparent` property with `transparency_index` for more control on the culling of transparent faces @@ -24,9 +27,14 @@ Semver is not yet in place, so each version can have breaking changes, although - Breaking changes - `VoxelViewer` now replaces the `viewer_path` property on `VoxelTerrain`, and allows multiple loading points - Defined `COLOR` channel in `VoxelBuffer`, previously known as `DATA3` + - `VoxelGenerator` is no longer the base for script-based generators, use `VoxelGeneratorScript` instead + - `VoxelStream` is no longer the base for script-based streams, use `VoxelStreamScript` instead + +- Fixes + - C# should be able to properly implement generator/stream functions - Known issues - - `VoxelLodTerrain` does not support `VoxelViewer`, but a refactoring pass is planned for it. + - `VoxelLodTerrain` does not entirely support `VoxelViewer`, but a refactoring pass is planned for it. `godot3.2.3` - 08/09/2020 diff --git a/config.py b/config.py index bcc30a67..74c45554 100644 --- a/config.py +++ b/config.py @@ -25,6 +25,7 @@ def get_doc_classes(): "VoxelViewer", "VoxelStream", + "VoxelStreamScript", "VoxelStreamFile", "VoxelStreamBlockFiles", "VoxelStreamRegionFiles", @@ -36,6 +37,7 @@ def get_doc_classes(): "VoxelGeneratorNoise2D", "VoxelGeneratorTest", "VoxelGeneratorGraph", + "VoxelGeneratorScript", "VoxelBoxMover", "VoxelTool", diff --git a/generators/voxel_generator.cpp b/generators/voxel_generator.cpp index 3b54f644..88e2cd24 100644 --- a/generators/voxel_generator.cpp +++ b/generators/voxel_generator.cpp @@ -6,8 +6,6 @@ VoxelGenerator::VoxelGenerator() { void VoxelGenerator::generate_block(VoxelBlockRequest &input) { ERR_FAIL_COND(input.voxel_buffer.is_null()); - try_call_script(this, VoxelStringNames::get_singleton()->generate_block, - input.voxel_buffer, input.origin_in_voxels.to_vec3(), input.lod, nullptr); } //bool VoxelGenerator::is_thread_safe() const { @@ -30,7 +28,6 @@ void VoxelGenerator::_b_generate_block(Ref out_buffer, Vector3 orig } void VoxelGenerator::_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("generate_block", "out_buffer", "origin_in_voxels", "lod"), &VoxelGenerator::_b_generate_block); + ClassDB::bind_method(D_METHOD("generate_block", "out_buffer", "origin_in_voxels", "lod"), + &VoxelGenerator::_b_generate_block); } diff --git a/generators/voxel_generator_script.cpp b/generators/voxel_generator_script.cpp new file mode 100644 index 00000000..c56ff19f --- /dev/null +++ b/generators/voxel_generator_script.cpp @@ -0,0 +1,28 @@ +#include "voxel_generator_script.h" +#include "../voxel_string_names.h" + +VoxelGeneratorScript::VoxelGeneratorScript() { +} + +void VoxelGeneratorScript::generate_block(VoxelBlockRequest &input) { + ERR_FAIL_COND(input.voxel_buffer.is_null()); + try_call_script(this, VoxelStringNames::get_singleton()->_generate_block, + input.voxel_buffer, input.origin_in_voxels.to_vec3(), input.lod, nullptr); +} + +int VoxelGeneratorScript::get_used_channels_mask() const { + Variant ret; + if (try_call_script(this, VoxelStringNames::get_singleton()->_get_used_channels_mask, nullptr, 0, &ret)) { + return ret; + } + return 0; +} + +void VoxelGeneratorScript::_bind_methods() { + BIND_VMETHOD(MethodInfo("_generate_block", + PropertyInfo(Variant::OBJECT, "out_buffer", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "VoxelBuffer"), + PropertyInfo(Variant::VECTOR3, "origin_in_voxels"), + PropertyInfo(Variant::INT, "lod"))); + + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_used_channels_mask")); +} diff --git a/generators/voxel_generator_script.h b/generators/voxel_generator_script.h new file mode 100644 index 00000000..0f3c2084 --- /dev/null +++ b/generators/voxel_generator_script.h @@ -0,0 +1,19 @@ +#ifndef VOXEL_GENERATOR_SCRIPT_H +#define VOXEL_GENERATOR_SCRIPT_H + +#include "voxel_generator.h" + +// Generator based on a script, like GDScript, C# or NativeScript +class VoxelGeneratorScript : public VoxelGenerator { + GDCLASS(VoxelGeneratorScript, VoxelGenerator) +public: + VoxelGeneratorScript(); + + void generate_block(VoxelBlockRequest &input) override; + int get_used_channels_mask() const override; + +private: + static void _bind_methods(); +}; + +#endif // VOXEL_GENERATOR_SCRIPT_H diff --git a/register_types.cpp b/register_types.cpp index fd656049..9fe923b9 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -11,6 +11,7 @@ #include "generators/voxel_generator_image.h" #include "generators/voxel_generator_noise.h" #include "generators/voxel_generator_noise_2d.h" +#include "generators/voxel_generator_script.h" #include "generators/voxel_generator_waves.h" #include "meshers/blocky/voxel_library.h" #include "meshers/blocky/voxel_mesher_blocky.h" @@ -23,6 +24,7 @@ #include "streams/voxel_stream_block_files.h" #include "streams/voxel_stream_file.h" #include "streams/voxel_stream_region_files.h" +#include "streams/voxel_stream_script.h" #include "terrain/voxel_box_mover.h" #include "terrain/voxel_lod_terrain.h" #include "terrain/voxel_map.h" @@ -65,6 +67,7 @@ void register_voxel_types() { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); // Generators ClassDB::register_class(); @@ -75,6 +78,7 @@ void register_voxel_types() { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); // Utilities ClassDB::register_class(); diff --git a/streams/voxel_stream.cpp b/streams/voxel_stream.cpp index 21aa27c5..8b813ce1 100644 --- a/streams/voxel_stream.cpp +++ b/streams/voxel_stream.cpp @@ -7,12 +7,10 @@ VoxelStream::VoxelStream() { void VoxelStream::emerge_block(Ref out_buffer, Vector3i origin_in_voxels, int lod) { ERR_FAIL_COND(out_buffer.is_null()); - try_call_script(this, VoxelStringNames::get_singleton()->emerge_block, out_buffer, origin_in_voxels.to_vec3(), lod, nullptr); } void VoxelStream::immerge_block(Ref buffer, Vector3i origin_in_voxels, int lod) { ERR_FAIL_COND(buffer.is_null()); - try_call_script(this, VoxelStringNames::get_singleton()->immerge_block, buffer, origin_in_voxels.to_vec3(), lod, nullptr); } void VoxelStream::emerge_blocks(Vector &p_blocks) { @@ -49,10 +47,6 @@ void VoxelStream::_immerge_block(Ref buffer, Vector3 origin_in_voxe } int VoxelStream::get_used_channels_mask() const { - Variant ret; - if (try_call_script(this, VoxelStringNames::get_singleton()->get_used_channels_mask, nullptr, 0, &ret)) { - return ret; - } return 0; } @@ -70,8 +64,6 @@ bool VoxelStream::has_script() const { } void VoxelStream::_bind_methods() { - // TODO Make these proper virtual, it confuses C# bindings - // 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", "lod"), &VoxelStream::_emerge_block); ClassDB::bind_method(D_METHOD("immerge_block", "buffer", "origin_in_voxels", "lod"), &VoxelStream::_immerge_block); ClassDB::bind_method(D_METHOD("get_used_channels_mask"), &VoxelStream::_get_used_channels_mask); diff --git a/streams/voxel_stream_script.cpp b/streams/voxel_stream_script.cpp new file mode 100644 index 00000000..161d2b71 --- /dev/null +++ b/streams/voxel_stream_script.cpp @@ -0,0 +1,36 @@ +#include "voxel_stream_script.h" +#include "../voxel_string_names.h" + +void VoxelStreamScript::emerge_block(Ref out_buffer, Vector3i origin_in_voxels, int lod) { + ERR_FAIL_COND(out_buffer.is_null()); + try_call_script(this, VoxelStringNames::get_singleton()->_emerge_block, + out_buffer, origin_in_voxels.to_vec3(), lod, nullptr); +} + +void VoxelStreamScript::immerge_block(Ref buffer, Vector3i origin_in_voxels, int lod) { + ERR_FAIL_COND(buffer.is_null()); + try_call_script(this, VoxelStringNames::get_singleton()->_immerge_block, + buffer, origin_in_voxels.to_vec3(), lod, nullptr); +} + +int VoxelStreamScript::get_used_channels_mask() const { + Variant ret; + if (try_call_script(this, VoxelStringNames::get_singleton()->_get_used_channels_mask, nullptr, 0, &ret)) { + return ret; + } + return 0; +} + +void VoxelStreamScript::_bind_methods() { + BIND_VMETHOD(MethodInfo("_emerge_block", + PropertyInfo(Variant::OBJECT, "out_buffer", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "VoxelBuffer"), + PropertyInfo(Variant::VECTOR3, "origin_in_voxels"), + PropertyInfo(Variant::INT, "lod"))); + + BIND_VMETHOD(MethodInfo("_immerge_block", + PropertyInfo(Variant::OBJECT, "buffer", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "VoxelBuffer"), + PropertyInfo(Variant::VECTOR3, "origin_in_voxels"), + PropertyInfo(Variant::INT, "lod"))); + + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_used_channels_mask")); +} diff --git a/streams/voxel_stream_script.h b/streams/voxel_stream_script.h new file mode 100644 index 00000000..82bbcc3f --- /dev/null +++ b/streams/voxel_stream_script.h @@ -0,0 +1,21 @@ +#ifndef VOXEL_STREAM_SCRIPT_H +#define VOXEL_STREAM_SCRIPT_H + +#include "voxel_stream.h" + +// Provides access to a source of paged voxel data, which may load and save. +// Must be implemented in a multi-thread-safe way. +// If you are looking for a more specialized API to generate voxels, use VoxelGenerator. +class VoxelStreamScript : public VoxelStream { + GDCLASS(VoxelStreamScript, VoxelStream) +public: + void emerge_block(Ref out_buffer, Vector3i origin_in_voxels, int lod) override; + void immerge_block(Ref buffer, Vector3i origin_in_voxels, int lod) override; + + int get_used_channels_mask() const override; + +protected: + static void _bind_methods(); +}; + +#endif // VOXEL_STREAM_SCRIPT_H diff --git a/util/utility.cpp b/util/utility.cpp index b02f6d68..cced9ced 100644 --- a/util/utility.cpp +++ b/util/utility.cpp @@ -26,6 +26,7 @@ bool is_mesh_empty(Ref mesh_ref) { bool try_call_script(const Object *obj, StringName method_name, const Variant **args, unsigned int argc, Variant *out_ret) { ScriptInstance *script = obj->get_script_instance(); + // TODO Is has_method() needed? I've seen `call()` being called anyways in ButtonBase if (script == nullptr || !script->has_method(method_name)) { return false; } diff --git a/voxel_string_names.cpp b/voxel_string_names.cpp index 13536a2b..bdd0f4c8 100644 --- a/voxel_string_names.cpp +++ b/voxel_string_names.cpp @@ -14,10 +14,11 @@ void VoxelStringNames::destroy_singleton() { } VoxelStringNames::VoxelStringNames() { - emerge_block = StaticCString::create("emerge_block"); - immerge_block = StaticCString::create("immerge_block"); - generate_block = StaticCString::create("generate_block"); - get_used_channels_mask = StaticCString::create("get_used_channels_mask"); + _emerge_block = StaticCString::create("_emerge_block"); + _immerge_block = StaticCString::create("_immerge_block"); + _generate_block = StaticCString::create("_generate_block"); + _get_used_channels_mask = StaticCString::create("_get_used_channels_mask"); + block_loaded = StaticCString::create("block_loaded"); block_unloaded = StaticCString::create("block_unloaded"); diff --git a/voxel_string_names.h b/voxel_string_names.h index f556648f..4116683e 100644 --- a/voxel_string_names.h +++ b/voxel_string_names.h @@ -17,10 +17,11 @@ public: VoxelStringNames(); - StringName emerge_block; - StringName immerge_block; - StringName generate_block; - StringName get_used_channels_mask; + StringName _emerge_block; + StringName _immerge_block; + StringName _generate_block; + StringName _get_used_channels_mask; + StringName block_loaded; StringName block_unloaded;