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 cbcb46c7ba3..bd77c97e5c4 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 4a38d03b3b5..64b9dc341b1 100644 --- a/scene/3d/room_manager.h +++ b/scene/3d/room_manager.h @@ -134,6 +134,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;