diff --git a/SCsub b/SCsub index 61fb2a0d..5cd8dcfb 100644 --- a/SCsub +++ b/SCsub @@ -59,6 +59,7 @@ if env["tools"]: "editor/graph/*.cpp", "editor/terrain/*.cpp", "editor/fast_noise_lite/*.cpp", + "editor/instancer/*.cpp", "editor/instance_library/*.cpp", "editor/vox/*.cpp", ] diff --git a/editor/instancer/voxel_instancer_editor_plugin.cpp b/editor/instancer/voxel_instancer_editor_plugin.cpp new file mode 100644 index 00000000..02351c9f --- /dev/null +++ b/editor/instancer/voxel_instancer_editor_plugin.cpp @@ -0,0 +1,25 @@ +#include "voxel_instancer_editor_plugin.h" +#include "../../terrain/instancing/voxel_instancer.h" + +VoxelInstancerEditorPlugin::VoxelInstancerEditorPlugin(EditorNode *p_node) {} + +bool VoxelInstancerEditorPlugin::handles(Object *p_object) const { + ERR_FAIL_COND_V(p_object == nullptr, false); + return Object::cast_to(p_object) != nullptr; +} + +void VoxelInstancerEditorPlugin::edit(Object *p_object) { + VoxelInstancer *instancer = Object::cast_to(p_object); + ERR_FAIL_COND(instancer == nullptr); + instancer->set_show_gizmos(true); + _node = instancer; +} + +void VoxelInstancerEditorPlugin::make_visible(bool visible) { + if (visible == false) { + if (_node != nullptr) { + _node->set_show_gizmos(false); + _node = nullptr; + } + } +} diff --git a/editor/instancer/voxel_instancer_editor_plugin.h b/editor/instancer/voxel_instancer_editor_plugin.h new file mode 100644 index 00000000..bfc8500a --- /dev/null +++ b/editor/instancer/voxel_instancer_editor_plugin.h @@ -0,0 +1,21 @@ +#ifndef VOXEL_INSTANCER_EDITOR_PLUGIN_H +#define VOXEL_INSTANCER_EDITOR_PLUGIN_H + +#include + +class VoxelInstancer; + +class VoxelInstancerEditorPlugin : public EditorPlugin { + GDCLASS(VoxelInstancerEditorPlugin, EditorPlugin) +public: + VoxelInstancerEditorPlugin(EditorNode *p_node); + + bool handles(Object *p_object) const override; + void edit(Object *p_object) override; + void make_visible(bool visible) override; + +private: + VoxelInstancer *_node = nullptr; +}; + +#endif // VOXEL_INSTANCER_EDITOR_PLUGIN_H diff --git a/editor/voxel_debug.cpp b/editor/voxel_debug.cpp index b2f9b62d..32b2a002 100644 --- a/editor/voxel_debug.cpp +++ b/editor/voxel_debug.cpp @@ -252,7 +252,7 @@ void DebugMultiMeshRenderer::begin() { } void DebugMultiMeshRenderer::draw_box(const Transform3D &t, Color8 color) { - _items.push_back(DirectMultiMeshInstance::TransformAndColor32{ t, color }); + _items.push_back(DirectMultiMeshInstance::TransformAndColor32{ t, Color(color) }); } void DebugMultiMeshRenderer::end() { diff --git a/editor/voxel_debug.h b/editor/voxel_debug.h index e6cb4e7d..cbbc18f9 100644 --- a/editor/voxel_debug.h +++ b/editor/voxel_debug.h @@ -37,6 +37,7 @@ private: std::vector _items; Ref _multimesh; DirectMultiMeshInstance _multimesh_instance; + // TODO World3D is a reference, do not store it by pointer World3D *_world = nullptr; bool _inside_block = false; PackedFloat32Array _bulk_array; @@ -49,18 +50,28 @@ class DebugRenderer { public: ~DebugRenderer(); + // This class does not uses nodes. Call this first to choose in which world it renders. void set_world(World3D *world); + // Call this before issuing drawing commands void begin(); + void draw_box(const Transform3D &t, ColorID color); + + // Draws a box wireframe using MultiMesh, allowing to draw much more without slowing down. + // The box's origin is its lower corner. Size is defined by the transform's basis. void draw_box_mm(const Transform3D &t, Color8 color); + + // Call this after issuing all drawing commands void end(); + void clear(); private: std::vector _items; unsigned int _current = 0; bool _inside_block = false; + // TODO World3D is a reference, do not store it by pointer World3D *_world = nullptr; DebugMultiMeshRenderer _mm_renderer; }; diff --git a/register_types.cpp b/register_types.cpp index 6d047e35..6ad242b6 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -47,6 +47,7 @@ #include "editor/fast_noise_lite/fast_noise_lite_editor_plugin.h" #include "editor/graph/voxel_graph_editor_plugin.h" #include "editor/instance_library/voxel_instance_library_editor_plugin.h" +#include "editor/instancer/voxel_instancer_editor_plugin.h" #include "editor/terrain/voxel_terrain_editor_plugin.h" #include "editor/vox/vox_editor_plugin.h" #include "editor/voxel_debug.h" @@ -151,6 +152,7 @@ void register_voxel_types() { EditorPlugins::add_by_type(); EditorPlugins::add_by_type(); EditorPlugins::add_by_type(); + EditorPlugins::add_by_type(); #endif #ifdef VOXEL_RUN_TESTS diff --git a/terrain/instancing/voxel_instancer.cpp b/terrain/instancing/voxel_instancer.cpp index b2b51ce1..34b35e51 100644 --- a/terrain/instancing/voxel_instancer.cpp +++ b/terrain/instancing/voxel_instancer.cpp @@ -90,10 +90,16 @@ void VoxelInstancer::_notification(int p_what) { case NOTIFICATION_ENTER_WORLD: set_world(*get_world_3d()); update_visibility(); +#ifdef TOOLS_ENABLED + _debug_renderer.set_world(get_world_3d().ptr()); +#endif break; case NOTIFICATION_EXIT_WORLD: set_world(nullptr); +#ifdef TOOLS_ENABLED + _debug_renderer.set_world(nullptr); +#endif break; case NOTIFICATION_PARENTED: @@ -141,16 +147,77 @@ void VoxelInstancer::_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: update_visibility(); +#ifdef TOOLS_ENABLED + if (_gizmos_enabled) { + _debug_renderer.set_world(is_visible_in_tree() ? *get_world_3d() : nullptr); + } +#endif break; case NOTIFICATION_INTERNAL_PROCESS: if (_parent != nullptr && _library.is_valid()) { process_mesh_lods(); } +#ifdef TOOLS_ENABLED + if (_gizmos_enabled) { + process_gizmos(); + } +#endif break; } } +#ifdef TOOLS_ENABLED + +void VoxelInstancer::set_show_gizmos(bool enable) { + _gizmos_enabled = enable; + if (_gizmos_enabled) { + _debug_renderer.set_world(is_visible_in_tree() ? *get_world_3d() : nullptr); + } else { + _debug_renderer.clear(); + } +} + +void VoxelInstancer::process_gizmos() { + ERR_FAIL_COND(_parent == nullptr); + const Transform3D parent_transform = get_global_transform(); + const int base_block_size_po2 = _parent->get_mesh_block_size_pow2(); + + _debug_renderer.begin(); + + for (auto it = _blocks.begin(); it != _blocks.end(); ++it) { + const Block *block = *it; + CRASH_COND(block == nullptr); + + Color8 color(0, 255, 0, 255); + if (block->multimesh_instance.is_valid()) { + if (block->multimesh_instance.get_multimesh().is_null()) { + // Allocated but without multimesh (wut?) + color = Color8(128, 0, 0, 255); + } else if (get_visible_instance_count(**block->multimesh_instance.get_multimesh()) == 0) { + // Allocated but empty multimesh + color = Color8(255, 64, 0, 255); + } + } else if (block->scene_instances.size() == 0) { + // Only draw blocks that are setup + continue; + } + + const int block_size_po2 = base_block_size_po2 + block->lod_index; + const int block_size = 1 << block_size_po2; + const Vector3 block_local_pos(block->grid_position << block_size_po2); + const Transform3D box_transform( + parent_transform.basis * (Basis().scaled(Vector3(block_size, block_size, block_size))), + parent_transform.xform(block_local_pos)); + + _debug_renderer.draw_box_mm(box_transform, color); + } + + _debug_renderer.end(); +} + +#endif + VoxelInstancer::Layer *VoxelInstancer::get_layer(int id) { Layer *ptr = _layers.getptr(id); CRASH_COND(ptr == nullptr); diff --git a/terrain/instancing/voxel_instancer.h b/terrain/instancing/voxel_instancer.h index 41a1668b..fb871b9a 100644 --- a/terrain/instancing/voxel_instancer.h +++ b/terrain/instancing/voxel_instancer.h @@ -9,6 +9,10 @@ #include "voxel_instance_library.h" #include "voxel_instance_library_item.h" +#ifdef TOOLS_ENABLED +#include "../../editor/voxel_debug.h" +#endif + #include //#include // Included by node.h lol #include @@ -72,6 +76,10 @@ public: void debug_dump_as_scene(String fpath) const; Node *debug_dump_as_nodes() const; +#ifdef TOOLS_ENABLED + void set_show_gizmos(bool enable); +#endif + TypedArray get_configuration_warnings() const override; protected: @@ -100,6 +108,10 @@ private: void update_layer_scenes(int layer_id); void create_render_blocks(Vector3i grid_position, int lod_index, Array surface_arrays); +#ifdef TOOLS_ENABLED + void process_gizmos(); +#endif + struct SceneInstance { VoxelInstanceComponent *component = nullptr; Node3D *root = nullptr; @@ -192,6 +204,11 @@ private: std::vector _transform_cache; VoxelLodTerrain *_parent; + +#ifdef TOOLS_ENABLED + VoxelDebug::DebugRenderer _debug_renderer; + bool _gizmos_enabled = true; +#endif }; VARIANT_ENUM_CAST(VoxelInstancer::UpMode);