Added basic UI to VoxelInstancer to see how many instances exist
parent
5c47188773
commit
54ffc240ba
|
@ -39,6 +39,7 @@ Godot 4 is required from this version.
|
|||
- `VoxelGeneratorGraph`: Some nodes have default input connections, so it's no longer required to connect them manually to (X,Y,Z) inputs
|
||||
- `VoxelGeneratorGraph`: Added minor optimization to share branches of nodes doing the same calculations
|
||||
- `VoxelInstancer`: Added support for `VoxelTerrain`. This means only LOD0 works, but mesh-LODs should work.
|
||||
- `VoxelInstancer`: Editor: added basic UI to see how many instances exist
|
||||
- `VoxelLodTerrain`: exposed debug drawing options for development versions
|
||||
|
||||
- Smooth voxels
|
||||
|
|
|
@ -1,9 +1,33 @@
|
|||
#include "voxel_instancer_editor_plugin.h"
|
||||
#include "../../terrain/instancing/voxel_instancer.h"
|
||||
#include "voxel_instancer_stat_view.h"
|
||||
|
||||
#include <editor/editor_scale.h>
|
||||
#include <scene/gui/menu_button.h>
|
||||
|
||||
namespace zylann::voxel {
|
||||
|
||||
VoxelInstancerEditorPlugin::VoxelInstancerEditorPlugin() {}
|
||||
namespace {
|
||||
enum MenuItemID { //
|
||||
MENU_SHOW_STATS
|
||||
};
|
||||
}
|
||||
|
||||
VoxelInstancerEditorPlugin::VoxelInstancerEditorPlugin() {
|
||||
MenuButton *menu_button = memnew(MenuButton);
|
||||
menu_button->set_text(VoxelInstancer::get_class_static());
|
||||
{
|
||||
menu_button->get_popup()->add_item("Show statistics", MENU_SHOW_STATS);
|
||||
const int i = menu_button->get_popup()->get_item_index(MENU_SHOW_STATS);
|
||||
menu_button->get_popup()->set_item_as_checkable(i, true);
|
||||
menu_button->get_popup()->set_item_checked(i, false);
|
||||
}
|
||||
menu_button->get_popup()->connect(
|
||||
"id_pressed", callable_mp(this, &VoxelInstancerEditorPlugin::_on_menu_item_selected));
|
||||
menu_button->hide();
|
||||
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, menu_button);
|
||||
_menu_button = menu_button;
|
||||
}
|
||||
|
||||
bool VoxelInstancerEditorPlugin::handles(Object *p_object) const {
|
||||
ERR_FAIL_COND_V(p_object == nullptr, false);
|
||||
|
@ -16,15 +40,60 @@ void VoxelInstancerEditorPlugin::edit(Object *p_object) {
|
|||
instancer->debug_set_draw_enabled(true);
|
||||
instancer->debug_set_draw_flag(VoxelInstancer::DEBUG_DRAW_ALL_BLOCKS, true);
|
||||
_node = instancer;
|
||||
if (_stat_view != nullptr) {
|
||||
_stat_view->set_instancer(_node);
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelInstancerEditorPlugin::make_visible(bool visible) {
|
||||
_menu_button->set_visible(visible);
|
||||
|
||||
if (visible == false) {
|
||||
if (_node != nullptr) {
|
||||
_node->debug_set_draw_enabled(false);
|
||||
_node = nullptr;
|
||||
}
|
||||
if (_stat_view != nullptr) {
|
||||
_stat_view->hide();
|
||||
_stat_view->set_instancer(nullptr);
|
||||
}
|
||||
} else {
|
||||
if (_stat_view != nullptr) {
|
||||
_stat_view->set_instancer(_node);
|
||||
_stat_view->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelInstancerEditorPlugin::_on_menu_item_selected(int id) {
|
||||
switch (id) {
|
||||
case MENU_SHOW_STATS: {
|
||||
const bool active = toggle_stat_view();
|
||||
const int i = _menu_button->get_popup()->get_item_index(id);
|
||||
_menu_button->get_popup()->set_item_checked(i, active);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
bool VoxelInstancerEditorPlugin::toggle_stat_view() {
|
||||
bool active = _stat_view == nullptr;
|
||||
if (active) {
|
||||
if (_stat_view == nullptr) {
|
||||
_stat_view = memnew(VoxelInstancerStatView);
|
||||
_stat_view->set_custom_minimum_size(Vector2(0, EDSCALE * 50));
|
||||
add_control_to_container(CONTAINER_SPATIAL_EDITOR_BOTTOM, _stat_view);
|
||||
}
|
||||
_stat_view->set_instancer(_node);
|
||||
_stat_view->show();
|
||||
|
||||
} else {
|
||||
if (_stat_view != nullptr) {
|
||||
remove_control_from_container(CONTAINER_SPATIAL_EDITOR_BOTTOM, _stat_view);
|
||||
_stat_view->queue_delete();
|
||||
_stat_view = nullptr;
|
||||
}
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
} // namespace zylann::voxel
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
namespace zylann::voxel {
|
||||
|
||||
class VoxelInstancer;
|
||||
class VoxelInstancerStatView;
|
||||
|
||||
class VoxelInstancerEditorPlugin : public EditorPlugin {
|
||||
GDCLASS(VoxelInstancerEditorPlugin, EditorPlugin)
|
||||
|
@ -17,7 +18,12 @@ public:
|
|||
void make_visible(bool visible) override;
|
||||
|
||||
private:
|
||||
bool toggle_stat_view();
|
||||
void _on_menu_item_selected(int id);
|
||||
|
||||
MenuButton *_menu_button = nullptr;
|
||||
VoxelInstancer *_node = nullptr;
|
||||
VoxelInstancerStatView *_stat_view = nullptr;
|
||||
};
|
||||
|
||||
} // namespace zylann::voxel
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef VOXEL_INSTANCER_STAT_VIEW_H
|
||||
#define VOXEL_INSTANCER_STAT_VIEW_H
|
||||
|
||||
#include "../../terrain/instancing/voxel_instancer.h"
|
||||
|
||||
#include <scene/gui/box_container.h>
|
||||
#include <scene/gui/tree.h>
|
||||
|
||||
namespace zylann::voxel {
|
||||
|
||||
class VoxelInstancerStatView : public VBoxContainer {
|
||||
GDCLASS(VoxelInstancerStatView, VBoxContainer)
|
||||
public:
|
||||
VoxelInstancerStatView() {
|
||||
_tree = memnew(Tree);
|
||||
_tree->set_columns(2);
|
||||
_tree->set_select_mode(Tree::SELECT_ROW);
|
||||
_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
_tree->set_column_expand_ratio(0, 0.25f);
|
||||
add_child(_tree);
|
||||
}
|
||||
|
||||
void set_instancer(const VoxelInstancer *instancer) {
|
||||
_instancer = instancer;
|
||||
set_process(_instancer != nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
void _notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_PROCESS:
|
||||
_process();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _process() {
|
||||
ERR_FAIL_COND(_instancer == nullptr);
|
||||
const VoxelInstancer &instancer = *_instancer;
|
||||
|
||||
Ref<VoxelInstanceLibrary> library = instancer.get_library();
|
||||
|
||||
instancer.debug_get_instance_counts(_count_per_layer);
|
||||
|
||||
_tree->clear();
|
||||
|
||||
if (library.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeItem *root = _tree->create_item();
|
||||
_tree->set_hide_root(true);
|
||||
|
||||
for (auto it = _count_per_layer.begin(); it != _count_per_layer.end(); ++it) {
|
||||
TreeItem *tree_item = _tree->create_item(root);
|
||||
const VoxelInstanceLibraryItem *lib_item = library->get_item_const(it->first);
|
||||
ERR_CONTINUE(lib_item == nullptr);
|
||||
|
||||
String name = lib_item->get_item_name();
|
||||
if (name == "") {
|
||||
name = "[" + String::num_int64(it->first) + "]";
|
||||
}
|
||||
|
||||
tree_item->set_text(0, name);
|
||||
tree_item->set_text(1, String::num_int64(it->second));
|
||||
}
|
||||
}
|
||||
|
||||
Tree *_tree = nullptr;
|
||||
const VoxelInstancer *_instancer = nullptr;
|
||||
std::unordered_map<uint32_t, uint32_t> _count_per_layer;
|
||||
};
|
||||
|
||||
} // namespace zylann::voxel
|
||||
|
||||
#endif // VOXEL_INSTANCER_STAT_VIEW_H
|
|
@ -1605,28 +1605,33 @@ int VoxelInstancer::debug_get_block_count() const {
|
|||
return _blocks.size();
|
||||
}
|
||||
|
||||
Dictionary VoxelInstancer::debug_get_instance_counts() const {
|
||||
Dictionary d;
|
||||
void VoxelInstancer::debug_get_instance_counts(std::unordered_map<uint32_t, uint32_t> &counts_per_layer) const {
|
||||
ZN_PROFILE_SCOPE();
|
||||
|
||||
counts_per_layer.clear();
|
||||
|
||||
for (auto it = _blocks.begin(); it != _blocks.end(); ++it) {
|
||||
Block &block = **it;
|
||||
if (!block.multimesh_instance.is_valid()) {
|
||||
continue;
|
||||
const Block &block = **it;
|
||||
|
||||
uint32_t count = block.scene_instances.size();
|
||||
|
||||
if (block.multimesh_instance.is_valid()) {
|
||||
Ref<MultiMesh> multimesh = block.multimesh_instance.get_multimesh();
|
||||
ZN_ASSERT_CONTINUE(multimesh.is_valid());
|
||||
|
||||
count += get_visible_instance_count(**multimesh);
|
||||
}
|
||||
|
||||
Ref<MultiMesh> multimesh = block.multimesh_instance.get_multimesh();
|
||||
ERR_FAIL_COND_V(multimesh.is_null(), Dictionary());
|
||||
counts_per_layer[block.layer_id] += count;
|
||||
}
|
||||
}
|
||||
|
||||
const int count = get_visible_instance_count(**multimesh);
|
||||
|
||||
Variant *vptr = d.getptr(block.layer_id);
|
||||
if (vptr == nullptr) {
|
||||
d[block.layer_id] = count;
|
||||
|
||||
} else {
|
||||
ERR_FAIL_COND_V(vptr->get_type() != Variant::INT, Dictionary());
|
||||
*vptr = vptr->operator signed int() + count;
|
||||
}
|
||||
Dictionary VoxelInstancer::_b_debug_get_instance_counts() const {
|
||||
Dictionary d;
|
||||
std::unordered_map<uint32_t, uint32_t> map;
|
||||
debug_get_instance_counts(map);
|
||||
for (auto it = map.begin(); it != map.end(); ++it) {
|
||||
d[it->first] = it->second;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
@ -1773,7 +1778,7 @@ void VoxelInstancer::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_up_mode"), &VoxelInstancer::get_up_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("debug_get_block_count"), &VoxelInstancer::debug_get_block_count);
|
||||
ClassDB::bind_method(D_METHOD("debug_get_instance_counts"), &VoxelInstancer::debug_get_instance_counts);
|
||||
ClassDB::bind_method(D_METHOD("debug_get_instance_counts"), &VoxelInstancer::_b_debug_get_instance_counts);
|
||||
ClassDB::bind_method(D_METHOD("debug_dump_as_scene", "fpath"), &VoxelInstancer::debug_dump_as_scene);
|
||||
ClassDB::bind_method(D_METHOD("debug_set_draw_enabled", "enabled"), &VoxelInstancer::debug_set_draw_enabled);
|
||||
ClassDB::bind_method(D_METHOD("debug_is_draw_enabled"), &VoxelInstancer::debug_is_draw_enabled);
|
||||
|
|
|
@ -84,7 +84,7 @@ public:
|
|||
// Debug
|
||||
|
||||
int debug_get_block_count() const;
|
||||
Dictionary debug_get_instance_counts() const;
|
||||
void debug_get_instance_counts(std::unordered_map<uint32_t, uint32_t> &counts_per_layer) const;
|
||||
void debug_dump_as_scene(String fpath) const;
|
||||
Node *debug_dump_as_nodes() const;
|
||||
|
||||
|
@ -161,6 +161,8 @@ private:
|
|||
static void remove_floating_scene_instances(Block &block, const Transform3D &parent_transform, Box3i p_voxel_box,
|
||||
const VoxelTool &voxel_tool, int block_size_po2);
|
||||
|
||||
Dictionary _b_debug_get_instance_counts() const;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
// TODO Rename RenderBlock?
|
||||
|
|
Loading…
Reference in New Issue