Browse Source

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.
lawnjelly 4 years ago
parent
commit
776623d56b

+ 2 - 16
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<RoomGizmoPlugin> room_gizmo_plugin = Ref<RoomGizmoPlugin>(memnew(RoomGizmoPlugin));

+ 0 - 2
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:

+ 61 - 0
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<Node *> &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);

+ 7 - 1
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);

+ 67 - 14
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> 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
 	}
 }
 

+ 6 - 0
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:

+ 1 - 0
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; }

+ 3 - 0
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<Vector3> &)
 
+	// don't use this in a game
+	BIND1RC(bool, rooms_is_loaded, RID)
+
 	// Callbacks
 	BIND1(callbacks_register, VisualServerCallbacks *)
 

+ 6 - 0
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<ObjectID> VisualServerScene::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const {
 	Vector<ObjectID> instances;
 	Scenario *scenario = scenario_owner.get(p_scenario);

+ 3 - 0
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<Vector3> &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; }
 

+ 3 - 0
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<Vector3> &)
 
+	// don't use this in a game
+	FUNC1RC(bool, rooms_is_loaded, RID)
+
 	// Callbacks
 	FUNC1(callbacks_register, VisualServerCallbacks *)
 

+ 3 - 0
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<Vector3> &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;