From 776623d56b2fe4799a083f4dbfb99500ecb644ee Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Sun, 1 Aug 2021 08:56:26 +0100 Subject: [PATCH] Portals - Improve UI and add shortcuts This PR makes the 'convert rooms' button permanently on the toolbar and accessible whichever node is selected, so you can convert rooms without having to select the RoomManager first. It also adds a togglable item 'view portal culling' to the 'View' menu which is a simple way of setting the RoomManager 'active' setting without the RoomManager being the selected node. Both of these have keyboard shortcuts, which should make it much faster to reconvert rooms and edit. In addition there the string in the 'Perspective' Listbox is modified to show [portals active] when portal culling is operational, for visual feedback. This is updated when you change modes, and when the rooms are invalidated. --- editor/plugins/room_manager_editor_plugin.cpp | 18 +---- editor/plugins/room_manager_editor_plugin.h | 2 - editor/plugins/spatial_editor_plugin.cpp | 61 ++++++++++++++ editor/plugins/spatial_editor_plugin.h | 8 +- scene/3d/room_manager.cpp | 81 +++++++++++++++---- scene/3d/room_manager.h | 6 ++ servers/visual/portals/portal_renderer.h | 1 + servers/visual/visual_server_raster.h | 3 + servers/visual/visual_server_scene.cpp | 6 ++ servers/visual/visual_server_scene.h | 3 + servers/visual/visual_server_wrap_mt.h | 3 + servers/visual_server.h | 3 + 12 files changed, 162 insertions(+), 33 deletions(-) diff --git a/editor/plugins/room_manager_editor_plugin.cpp b/editor/plugins/room_manager_editor_plugin.cpp index 28e32e81576..ea152135b7a 100644 --- a/editor/plugins/room_manager_editor_plugin.cpp +++ b/editor/plugins/room_manager_editor_plugin.cpp @@ -32,12 +32,6 @@ #include "editor/spatial_editor_gizmos.h" -void RoomManagerEditorPlugin::_rooms_convert() { - if (_room_manager) { - _room_manager->rooms_convert(); - } -} - void RoomManagerEditorPlugin::_flip_portals() { if (_room_manager) { _room_manager->rooms_flip_portals(); @@ -59,16 +53,15 @@ bool RoomManagerEditorPlugin::handles(Object *p_object) const { void RoomManagerEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - button_rooms_convert->show(); button_flip_portals->show(); } else { - button_rooms_convert->hide(); button_flip_portals->hide(); } + + SpatialEditor::get_singleton()->show_advanced_portal_tools(p_visible); } void RoomManagerEditorPlugin::_bind_methods() { - ClassDB::bind_method("_rooms_convert", &RoomManagerEditorPlugin::_rooms_convert); ClassDB::bind_method("_flip_portals", &RoomManagerEditorPlugin::_flip_portals); } @@ -82,13 +75,6 @@ RoomManagerEditorPlugin::RoomManagerEditorPlugin(EditorNode *p_node) { button_flip_portals->connect("pressed", this, "_flip_portals"); add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, button_flip_portals); - button_rooms_convert = memnew(ToolButton); - button_rooms_convert->set_icon(editor->get_gui_base()->get_icon("RoomGroup", "EditorIcons")); - button_rooms_convert->set_text(TTR("Convert Rooms")); - button_rooms_convert->hide(); - button_rooms_convert->connect("pressed", this, "_rooms_convert"); - add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, button_rooms_convert); - _room_manager = nullptr; Ref room_gizmo_plugin = Ref(memnew(RoomGizmoPlugin)); diff --git a/editor/plugins/room_manager_editor_plugin.h b/editor/plugins/room_manager_editor_plugin.h index 97903d1abf4..d865661a0a4 100644 --- a/editor/plugins/room_manager_editor_plugin.h +++ b/editor/plugins/room_manager_editor_plugin.h @@ -43,11 +43,9 @@ class RoomManagerEditorPlugin : public EditorPlugin { RoomManager *_room_manager; - ToolButton *button_rooms_convert; ToolButton *button_flip_portals; EditorNode *editor; - void _rooms_convert(); void _flip_portals(); protected: diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 97fb0ad5c20..f0b46fd84c6 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -47,6 +47,7 @@ #include "scene/3d/collision_shape.h" #include "scene/3d/mesh_instance.h" #include "scene/3d/physics_body.h" +#include "scene/3d/room_manager.h" #include "scene/3d/visual_instance.h" #include "scene/gui/viewport_container.h" #include "scene/resources/packed_scene.h" @@ -733,6 +734,10 @@ void SpatialEditorViewport::_update_name() { view_mode += " [auto]"; } + if (RoomManager::static_rooms_get_active_and_loaded()) { + view_mode += " [portals active]"; + } + if (name != "") { view_menu->set_text(name + " " + view_mode); } else { @@ -4303,6 +4308,42 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) { } } +void SpatialEditor::show_advanced_portal_tools(bool p_show) { + // toolbar button + Button *const button = tool_button[TOOL_CONVERT_ROOMS]; + if (p_show) { + button->set_text(TTR("Convert Rooms")); + } else { + button->set_text(""); + } +} + +void SpatialEditor::update_portal_tools() { + // the view portal culling toggle + int view_portal_item_index = view_menu->get_popup()->get_item_index(MENU_VIEW_PORTAL_CULLING); + if (RoomManager::active_room_manager) { + view_menu->get_popup()->set_item_disabled(view_portal_item_index, false); + + bool active = RoomManager::static_rooms_get_active(); + view_menu->get_popup()->set_item_checked(view_portal_item_index, active); + } else { + view_menu->get_popup()->set_item_disabled(view_portal_item_index, true); + } + + // toolbar button + Button *const button = tool_button[TOOL_CONVERT_ROOMS]; + + if (RoomManager::active_room_manager) { + button->show(); + } else { + button->hide(); + } + + for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) { + viewports[i]->_update_name(); + } +} + void SpatialEditor::update_transform_gizmo() { List &selection = editor_selection->get_selected_node_list(); AABB center; @@ -4791,6 +4832,10 @@ void SpatialEditor::_menu_item_pressed(int p_option) { update_transform_gizmo(); } break; + case MENU_TOOL_CONVERT_ROOMS: { + RoomManager::static_rooms_convert(); + update_portal_tools(); + } break; case MENU_TRANSFORM_CONFIGURE_SNAP: { snap_dialog->popup_centered(Size2(200, 180)); } break; @@ -4897,6 +4942,11 @@ void SpatialEditor::_menu_item_pressed(int p_option) { view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), grid_enabled); } break; + case MENU_VIEW_PORTAL_CULLING: { + bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option)); + RoomManager::static_rooms_set_active(!is_checked); + update_portal_tools(); + } break; case MENU_VIEW_CAMERA_SETTINGS: { settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50)); } break; @@ -5916,6 +5966,7 @@ void SpatialEditor::_notification(int p_what) { tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons")); tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons")); tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons")); + tool_button[SpatialEditor::TOOL_CONVERT_ROOMS]->set_icon(get_icon("RoomGroup", "EditorIcons")); tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons")); tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons")); @@ -6293,6 +6344,15 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", this, "_menu_item_toggled", button_binds); _update_camera_override_button(false); + tool_button[TOOL_CONVERT_ROOMS] = memnew(ToolButton); + hbc_menu->add_child(tool_button[TOOL_CONVERT_ROOMS]); + tool_button[TOOL_CONVERT_ROOMS]->set_toggle_mode(false); + tool_button[TOOL_CONVERT_ROOMS]->set_flat(true); + button_binds.write[0] = MENU_TOOL_CONVERT_ROOMS; + tool_button[TOOL_CONVERT_ROOMS]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_CONVERT_ROOMS]->set_shortcut(ED_SHORTCUT("spatial_editor/convert_rooms", TTR("Convert Rooms"), KEY_MASK_ALT | KEY_C)); + tool_button[TOOL_CONVERT_ROOMS]->set_tooltip(TTR("Converts rooms for portal culling.")); + hbc_menu->add_child(memnew(VSeparator)); // Drag and drop support; @@ -6363,6 +6423,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p->add_separator(); p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN); p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid"), KEY_MASK_CMD + KEY_G), MENU_VIEW_GRID); + p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_portal_culling", TTR("View Portal Culling"), KEY_MASK_ALT | KEY_P), MENU_VIEW_PORTAL_CULLING); p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index efad5978db7..5030cb4eb3c 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -207,7 +207,8 @@ class SpatialEditorViewport : public Control { VIEW_DISPLAY_SHADELESS, VIEW_LOCK_ROTATION, VIEW_CINEMATIC_PREVIEW, - VIEW_AUTO_ORTHOGONAL + VIEW_AUTO_ORTHOGONAL, + VIEW_PORTAL_CULLING, }; public: @@ -545,6 +546,7 @@ public: TOOL_UNLOCK_SELECTED, TOOL_GROUP_SELECTED, TOOL_UNGROUP_SELECTED, + TOOL_CONVERT_ROOMS, TOOL_MAX }; @@ -624,6 +626,7 @@ private: MENU_TOOL_LOCAL_COORDS, MENU_TOOL_USE_SNAP, MENU_TOOL_OVERRIDE_CAMERA, + MENU_TOOL_CONVERT_ROOMS, MENU_TRANSFORM_CONFIGURE_SNAP, MENU_TRANSFORM_DIALOG, MENU_VIEW_USE_1_VIEWPORT, @@ -634,6 +637,7 @@ private: MENU_VIEW_USE_4_VIEWPORTS, MENU_VIEW_ORIGIN, MENU_VIEW_GRID, + MENU_VIEW_PORTAL_CULLING, MENU_VIEW_GIZMOS_3D_ICONS, MENU_VIEW_CAMERA_SETTINGS, MENU_LOCK_SELECTED, @@ -762,6 +766,8 @@ public: void update_grid(); void update_transform_gizmo(); + void update_portal_tools(); + void show_advanced_portal_tools(bool p_show); void update_all_gizmos(Node *p_node = nullptr); void snap_selected_nodes_to_floor(); void select_gizmo_highlight_axis(int p_axis); diff --git a/scene/3d/room_manager.cpp b/scene/3d/room_manager.cpp index 260b891e3d1..3db17a2d900 100644 --- a/scene/3d/room_manager.cpp +++ b/scene/3d/room_manager.cpp @@ -43,6 +43,10 @@ #include "scene/3d/light.h" #include "visibility_notifier.h" +#ifdef TOOLS_ENABLED +#include "editor/plugins/spatial_editor_plugin.h" +#endif + #include "modules/modules_enabled.gen.h" #ifdef MODULE_CSG_ENABLED #include "modules/csg/csg_shape.h" @@ -54,31 +58,55 @@ #include "core/math/convex_hull.h" #endif -#ifdef TOOLS_ENABLED -RoomManager *RoomManager::active_room_manager = nullptr; -#endif - // This needs to be static because it cannot easily be propagated to portals // during load (as the RoomManager may be loaded before Portals enter the scene tree) real_t RoomManager::_default_portal_margin = 1.0; +#ifdef TOOLS_ENABLED +RoomManager *RoomManager::active_room_manager = nullptr; + +// static versions of functions for use from editor toolbars +void RoomManager::static_rooms_set_active(bool p_active) { + if (active_room_manager) { + active_room_manager->rooms_set_active(p_active); + active_room_manager->property_list_changed_notify(); + } +} + +bool RoomManager::static_rooms_get_active() { + if (active_room_manager) { + return active_room_manager->rooms_get_active(); + } + + return false; +} + +bool RoomManager::static_rooms_get_active_and_loaded() { + if (active_room_manager) { + if (active_room_manager->rooms_get_active()) { + Ref world = active_room_manager->get_world(); + RID scenario = world->get_scenario(); + return active_room_manager->rooms_get_active() && VisualServer::get_singleton()->rooms_is_loaded(scenario); + } + } + + return false; +} + +void RoomManager::static_rooms_convert() { + if (active_room_manager) { + return active_room_manager->rooms_convert(); + } +} +#endif + RoomManager::RoomManager() { // some high value, we want room manager to be processed after other // nodes because the camera should be moved first set_process_priority(10000); - -#ifdef TOOLS_ENABLED - // note this mechanism may fail to work correctly if the user creates two room managers, - // but should not create major problems as it is just used to auto update when portals etc - // are changed in the editor, and there is a check for nullptr. - active_room_manager = this; -#endif } RoomManager::~RoomManager() { -#ifdef TOOLS_ENABLED - active_room_manager = nullptr; -#endif } String RoomManager::get_configuration_warning() const { @@ -173,12 +201,33 @@ void RoomManager::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { if (Engine::get_singleton()->is_editor_hint()) { set_process_internal(_godot_preview_camera_ID != (ObjectID)-1); +#ifdef TOOLS_ENABLED + // note this mechanism may fail to work correctly if the user creates two room managers, + // but should not create major problems as it is just used to auto update when portals etc + // are changed in the editor, and there is a check for nullptr. + active_room_manager = this; + SpatialEditor *spatial_editor = SpatialEditor::get_singleton(); + if (spatial_editor) { + spatial_editor->update_portal_tools(); + } +#endif } else { if (_settings_gameplay_monitor_enabled) { set_process_internal(true); } } } break; + case NOTIFICATION_EXIT_TREE: { +#ifdef TOOLS_ENABLED + active_room_manager = nullptr; + if (Engine::get_singleton()->is_editor_hint()) { + SpatialEditor *spatial_editor = SpatialEditor::get_singleton(); + if (spatial_editor) { + spatial_editor->update_portal_tools(); + } + } +#endif + } break; case NOTIFICATION_INTERNAL_PROCESS: { // can't call visual server if not inside world if (!is_inside_world()) { @@ -459,6 +508,10 @@ void RoomManager::rooms_set_active(bool p_active) { if (is_inside_world() && get_world().is_valid()) { VisualServer::get_singleton()->rooms_set_active(get_world()->get_scenario(), p_active); _active = p_active; + +#ifdef TOOLS_ENABLED + SpatialEditor::get_singleton()->update_portal_tools(); +#endif } } diff --git a/scene/3d/room_manager.h b/scene/3d/room_manager.h index 63a74c90e65..cb1e53cec31 100644 --- a/scene/3d/room_manager.h +++ b/scene/3d/room_manager.h @@ -135,6 +135,12 @@ public: // an easy way of grabbing the active room manager for tools purposes #ifdef TOOLS_ENABLED static RoomManager *active_room_manager; + + // static versions of functions for use from editor toolbars + static void static_rooms_set_active(bool p_active); + static bool static_rooms_get_active(); + static bool static_rooms_get_active_and_loaded(); + static void static_rooms_convert(); #endif private: diff --git a/servers/visual/portals/portal_renderer.h b/servers/visual/portals/portal_renderer.h index d35d203122d..d3b16802d44 100644 --- a/servers/visual/portals/portal_renderer.h +++ b/servers/visual/portals/portal_renderer.h @@ -159,6 +159,7 @@ public: // for use in the editor only, to allow a cheap way of turning off portals // if there has been a change, e.g. moving a room etc. void rooms_unload() { _ensure_unloaded(); } + bool rooms_is_loaded() const { return _loaded; } // debugging void set_debug_sprawl(bool p_active) { _debug_sprawl = p_active; } diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 116fa6cfba8..df3d55a7939 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -593,6 +593,9 @@ public: BIND3(rooms_set_debug_feature, RID, RoomsDebugFeature, bool) BIND2(rooms_update_gameplay_monitor, RID, const Vector &) + // don't use this in a game + BIND1RC(bool, rooms_is_loaded, RID) + // Callbacks BIND1(callbacks_register, VisualServerCallbacks *) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 9625d375c54..5c64652fcef 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1308,6 +1308,12 @@ void VisualServerScene::rooms_update_gameplay_monitor(RID p_scenario, const Vect scenario->_portal_renderer.rooms_update_gameplay_monitor(p_camera_positions); } +bool VisualServerScene::rooms_is_loaded(RID p_scenario) const { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND_V(!scenario, false); + return scenario->_portal_renderer.rooms_is_loaded(); +} + Vector VisualServerScene::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const { Vector instances; Scenario *scenario = scenario_owner.get(p_scenario); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 8d026b928f2..6733b00ade9 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -647,6 +647,9 @@ public: virtual void rooms_set_debug_feature(RID p_scenario, VisualServer::RoomsDebugFeature p_feature, bool p_active); virtual void rooms_update_gameplay_monitor(RID p_scenario, const Vector &p_camera_positions); + // don't use this in a game + virtual bool rooms_is_loaded(RID p_scenario) const; + virtual void callbacks_register(VisualServerCallbacks *p_callbacks); VisualServerCallbacks *get_callbacks() const { return _visual_server_callbacks; } diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index fcd7273e527..1d1555df1ef 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -516,6 +516,9 @@ public: FUNC3(rooms_set_debug_feature, RID, RoomsDebugFeature, bool) FUNC2(rooms_update_gameplay_monitor, RID, const Vector &) + // don't use this in a game + FUNC1RC(bool, rooms_is_loaded, RID) + // Callbacks FUNC1(callbacks_register, VisualServerCallbacks *) diff --git a/servers/visual_server.h b/servers/visual_server.h index e5b752f4ca4..3ed4e0e556b 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -909,6 +909,9 @@ public: virtual void rooms_set_debug_feature(RID p_scenario, RoomsDebugFeature p_feature, bool p_active) = 0; virtual void rooms_update_gameplay_monitor(RID p_scenario, const Vector &p_camera_positions) = 0; + // don't use this in a game! + virtual bool rooms_is_loaded(RID p_scenario) const = 0; + // callbacks are used to send messages back from the visual server to scene tree in thread friendly manner virtual void callbacks_register(VisualServerCallbacks *p_callbacks) = 0;