mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 11:32:13 +00:00
Add "Game" editor for better runtime debugging
This commit is contained in:
parent
8004c7524f
commit
16524a8a01
@ -116,6 +116,10 @@ void Engine::set_time_scale(double p_scale) {
|
||||
}
|
||||
|
||||
double Engine::get_time_scale() const {
|
||||
return freeze_time_scale ? 0 : _time_scale;
|
||||
}
|
||||
|
||||
double Engine::get_unfrozen_time_scale() const {
|
||||
return _time_scale;
|
||||
}
|
||||
|
||||
@ -404,6 +408,10 @@ bool Engine::notify_frame_server_synced() {
|
||||
return server_syncs > SERVER_SYNC_FRAME_COUNT_WARNING;
|
||||
}
|
||||
|
||||
void Engine::set_freeze_time_scale(bool p_frozen) {
|
||||
freeze_time_scale = p_frozen;
|
||||
}
|
||||
|
||||
Engine::Engine() {
|
||||
singleton = this;
|
||||
}
|
||||
|
@ -99,6 +99,8 @@ private:
|
||||
int server_syncs = 0;
|
||||
bool frame_server_synced = false;
|
||||
|
||||
bool freeze_time_scale = false;
|
||||
|
||||
public:
|
||||
static Engine *get_singleton();
|
||||
|
||||
@ -130,6 +132,7 @@ public:
|
||||
|
||||
void set_time_scale(double p_scale);
|
||||
double get_time_scale() const;
|
||||
double get_unfrozen_time_scale() const;
|
||||
|
||||
void set_print_to_stdout(bool p_enabled);
|
||||
bool is_printing_to_stdout() const;
|
||||
@ -197,6 +200,8 @@ public:
|
||||
void increment_frames_drawn();
|
||||
bool notify_frame_server_synced();
|
||||
|
||||
void set_freeze_time_scale(bool p_frozen);
|
||||
|
||||
Engine();
|
||||
virtual ~Engine();
|
||||
};
|
||||
|
@ -87,11 +87,50 @@ Input *Input::get_singleton() {
|
||||
|
||||
void Input::set_mouse_mode(MouseMode p_mode) {
|
||||
ERR_FAIL_INDEX((int)p_mode, 5);
|
||||
|
||||
if (p_mode == mouse_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow to be set even if overridden, to see if the platform allows the mode.
|
||||
set_mouse_mode_func(p_mode);
|
||||
mouse_mode = get_mouse_mode_func();
|
||||
|
||||
if (mouse_mode_override_enabled) {
|
||||
set_mouse_mode_func(mouse_mode_override);
|
||||
}
|
||||
}
|
||||
|
||||
Input::MouseMode Input::get_mouse_mode() const {
|
||||
return get_mouse_mode_func();
|
||||
return mouse_mode;
|
||||
}
|
||||
|
||||
void Input::set_mouse_mode_override_enabled(bool p_enabled) {
|
||||
if (p_enabled == mouse_mode_override_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mouse_mode_override_enabled = p_enabled;
|
||||
|
||||
if (p_enabled) {
|
||||
set_mouse_mode_func(mouse_mode_override);
|
||||
mouse_mode_override = get_mouse_mode_func();
|
||||
} else {
|
||||
set_mouse_mode_func(mouse_mode);
|
||||
}
|
||||
}
|
||||
|
||||
void Input::set_mouse_mode_override(MouseMode p_mode) {
|
||||
ERR_FAIL_INDEX((int)p_mode, 5);
|
||||
|
||||
if (p_mode == mouse_mode_override) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse_mode_override_enabled) {
|
||||
set_mouse_mode_func(p_mode);
|
||||
mouse_mode_override = get_mouse_mode_func();
|
||||
}
|
||||
}
|
||||
|
||||
void Input::_bind_methods() {
|
||||
@ -252,6 +291,10 @@ Input::VelocityTrack::VelocityTrack() {
|
||||
bool Input::is_anything_pressed() const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (disable_input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!keys_pressed.is_empty() || !joy_buttons_pressed.is_empty() || !mouse_button_mask.is_empty()) {
|
||||
return true;
|
||||
}
|
||||
@ -267,21 +310,41 @@ bool Input::is_anything_pressed() const {
|
||||
|
||||
bool Input::is_key_pressed(Key p_keycode) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (disable_input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return keys_pressed.has(p_keycode);
|
||||
}
|
||||
|
||||
bool Input::is_physical_key_pressed(Key p_keycode) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (disable_input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return physical_keys_pressed.has(p_keycode);
|
||||
}
|
||||
|
||||
bool Input::is_key_label_pressed(Key p_keycode) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (disable_input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return key_label_pressed.has(p_keycode);
|
||||
}
|
||||
|
||||
bool Input::is_mouse_button_pressed(MouseButton p_button) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (disable_input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mouse_button_mask.has_flag(mouse_button_to_mask(p_button));
|
||||
}
|
||||
|
||||
@ -295,11 +358,21 @@ static JoyButton _combine_device(JoyButton p_value, int p_device) {
|
||||
|
||||
bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (disable_input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return joy_buttons_pressed.has(_combine_device(p_button, p_device));
|
||||
}
|
||||
|
||||
bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
|
||||
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
|
||||
|
||||
if (disable_input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
|
||||
if (!E) {
|
||||
return false;
|
||||
@ -310,6 +383,11 @@ bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
|
||||
|
||||
bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
|
||||
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
|
||||
|
||||
if (disable_input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
|
||||
if (!E) {
|
||||
return false;
|
||||
@ -331,6 +409,11 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
|
||||
|
||||
bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
|
||||
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
|
||||
|
||||
if (disable_input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
|
||||
if (!E) {
|
||||
return false;
|
||||
@ -352,6 +435,11 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
|
||||
|
||||
float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
|
||||
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
|
||||
|
||||
if (disable_input) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
|
||||
if (!E) {
|
||||
return 0.0f;
|
||||
@ -366,6 +454,11 @@ float Input::get_action_strength(const StringName &p_action, bool p_exact) const
|
||||
|
||||
float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
|
||||
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
|
||||
|
||||
if (disable_input) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
|
||||
if (!E) {
|
||||
return 0.0f;
|
||||
@ -410,6 +503,11 @@ Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_po
|
||||
|
||||
float Input::get_joy_axis(int p_device, JoyAxis p_axis) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
if (disable_input) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
JoyAxis c = _combine_device(p_axis, p_device);
|
||||
if (_joy_axis.has(c)) {
|
||||
return _joy_axis[c];
|
||||
@ -1664,6 +1762,14 @@ int Input::get_unused_joy_id() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Input::set_disable_input(bool p_disable) {
|
||||
disable_input = p_disable;
|
||||
}
|
||||
|
||||
bool Input::is_input_disabled() const {
|
||||
return disable_input;
|
||||
}
|
||||
|
||||
Input::Input() {
|
||||
singleton = this;
|
||||
|
||||
|
@ -103,6 +103,11 @@ private:
|
||||
Vector2 mouse_pos;
|
||||
int64_t mouse_window = 0;
|
||||
bool legacy_just_pressed_behavior = false;
|
||||
bool disable_input = false;
|
||||
|
||||
MouseMode mouse_mode = MOUSE_MODE_VISIBLE;
|
||||
bool mouse_mode_override_enabled = false;
|
||||
MouseMode mouse_mode_override = MOUSE_MODE_VISIBLE;
|
||||
|
||||
struct ActionState {
|
||||
uint64_t pressed_physics_frame = UINT64_MAX;
|
||||
@ -279,6 +284,8 @@ protected:
|
||||
public:
|
||||
void set_mouse_mode(MouseMode p_mode);
|
||||
MouseMode get_mouse_mode() const;
|
||||
void set_mouse_mode_override_enabled(bool p_enabled);
|
||||
void set_mouse_mode_override(MouseMode p_mode);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
|
||||
@ -380,6 +387,9 @@ public:
|
||||
|
||||
void set_event_dispatch_function(EventDispatchFunc p_function);
|
||||
|
||||
void set_disable_input(bool p_disable);
|
||||
bool is_input_disabled() const;
|
||||
|
||||
Input();
|
||||
~Input();
|
||||
};
|
||||
|
@ -121,7 +121,10 @@
|
||||
<constant name="FEATURE_HISTORY_DOCK" value="7" enum="Feature">
|
||||
The History dock. If this feature is disabled, the History dock won't be visible.
|
||||
</constant>
|
||||
<constant name="FEATURE_MAX" value="8" enum="Feature">
|
||||
<constant name="FEATURE_GAME" value="8" enum="Feature">
|
||||
The Game tab, which allows embedding the game window and selecting nodes by clicking inside of it. If this feature is disabled, the Game tab won't display.
|
||||
</constant>
|
||||
<constant name="FEATURE_MAX" value="9" enum="Feature">
|
||||
Represents the size of the [enum Feature] enum.
|
||||
</constant>
|
||||
</constants>
|
||||
|
@ -105,6 +105,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
|
||||
node->connect("breakpoint_selected", callable_mp(this, &EditorDebuggerNode::_error_selected).bind(id));
|
||||
node->connect("clear_execution", callable_mp(this, &EditorDebuggerNode::_clear_execution));
|
||||
node->connect("breaked", callable_mp(this, &EditorDebuggerNode::_breaked).bind(id));
|
||||
node->connect("remote_tree_select_requested", callable_mp(this, &EditorDebuggerNode::_remote_tree_select_requested).bind(id));
|
||||
node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated).bind(id));
|
||||
node->connect("remote_object_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_updated).bind(id));
|
||||
node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated).bind(id));
|
||||
@ -637,6 +638,13 @@ void EditorDebuggerNode::request_remote_tree() {
|
||||
get_current_debugger()->request_remote_tree();
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_select_requested(ObjectID p_id, int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
}
|
||||
remote_scene_tree->select_node(p_id);
|
||||
}
|
||||
|
||||
void EditorDebuggerNode::_remote_tree_updated(int p_debugger) {
|
||||
if (p_debugger != tabs->get_current_tab()) {
|
||||
return;
|
||||
|
@ -51,11 +51,8 @@ class EditorDebuggerNode : public MarginContainer {
|
||||
public:
|
||||
enum CameraOverride {
|
||||
OVERRIDE_NONE,
|
||||
OVERRIDE_2D,
|
||||
OVERRIDE_3D_1, // 3D Viewport 1
|
||||
OVERRIDE_3D_2, // 3D Viewport 2
|
||||
OVERRIDE_3D_3, // 3D Viewport 3
|
||||
OVERRIDE_3D_4 // 3D Viewport 4
|
||||
OVERRIDE_INGAME,
|
||||
OVERRIDE_EDITORS,
|
||||
};
|
||||
|
||||
private:
|
||||
@ -132,6 +129,7 @@ protected:
|
||||
void _debugger_stopped(int p_id);
|
||||
void _debugger_wants_stop(int p_id);
|
||||
void _debugger_changed(int p_tab);
|
||||
void _remote_tree_select_requested(ObjectID p_id, int p_debugger);
|
||||
void _remote_tree_updated(int p_debugger);
|
||||
void _remote_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
|
||||
void _remote_object_updated(ObjectID p_id, int p_debugger);
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include "editor_debugger_tree.h"
|
||||
|
||||
#include "editor/debugger/editor_debugger_node.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "editor/gui/editor_file_dialog.h"
|
||||
@ -148,7 +149,8 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||
updating_scene_tree = true;
|
||||
const String last_path = get_selected_path();
|
||||
const String filter = SceneTreeDock::get_singleton()->get_filter();
|
||||
bool filter_changed = filter != last_filter;
|
||||
bool should_scroll = scrolling_to_item || filter != last_filter;
|
||||
scrolling_to_item = false;
|
||||
TreeItem *scroll_item = nullptr;
|
||||
|
||||
// Nodes are in a flatten list, depth first. Use a stack of parents, avoid recursion.
|
||||
@ -185,8 +187,18 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||
// Select previously selected node.
|
||||
if (debugger_id == p_debugger) { // Can use remote id.
|
||||
if (node.id == inspected_object_id) {
|
||||
if (selection_uncollapse_all) {
|
||||
selection_uncollapse_all = false;
|
||||
|
||||
// Temporarily set to `false`, to allow caching the unfolds.
|
||||
updating_scene_tree = false;
|
||||
item->uncollapse_tree();
|
||||
updating_scene_tree = true;
|
||||
}
|
||||
|
||||
item->select(0);
|
||||
if (filter_changed) {
|
||||
|
||||
if (should_scroll) {
|
||||
scroll_item = item;
|
||||
}
|
||||
}
|
||||
@ -194,7 +206,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||
if (last_path == _get_path(item)) {
|
||||
updating_scene_tree = false; // Force emission of new selection.
|
||||
item->select(0);
|
||||
if (filter_changed) {
|
||||
if (should_scroll) {
|
||||
scroll_item = item;
|
||||
}
|
||||
updating_scene_tree = true;
|
||||
@ -258,14 +270,30 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||
}
|
||||
}
|
||||
}
|
||||
debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree
|
||||
|
||||
debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree.
|
||||
if (scroll_item) {
|
||||
callable_mp((Tree *)this, &Tree::scroll_to_item).call_deferred(scroll_item, false);
|
||||
scroll_to_item(scroll_item, false);
|
||||
}
|
||||
last_filter = filter;
|
||||
updating_scene_tree = false;
|
||||
}
|
||||
|
||||
void EditorDebuggerTree::select_node(ObjectID p_id) {
|
||||
// Manually select, as the tree control may be out-of-date for some reason (e.g. not shown yet).
|
||||
selection_uncollapse_all = true;
|
||||
inspected_object_id = uint64_t(p_id);
|
||||
scrolling_to_item = true;
|
||||
emit_signal(SNAME("object_selected"), inspected_object_id, debugger_id);
|
||||
|
||||
if (!updating_scene_tree) {
|
||||
// Request a tree refresh.
|
||||
EditorDebuggerNode::get_singleton()->request_remote_tree();
|
||||
}
|
||||
// Set the value immediately, so no update flooding happens and causes a crash.
|
||||
updating_scene_tree = true;
|
||||
}
|
||||
|
||||
Variant EditorDebuggerTree::get_drag_data(const Point2 &p_point) {
|
||||
if (get_button_id_at_position(p_point) != -1) {
|
||||
return Variant();
|
||||
|
@ -49,6 +49,8 @@ private:
|
||||
ObjectID inspected_object_id;
|
||||
int debugger_id = 0;
|
||||
bool updating_scene_tree = false;
|
||||
bool scrolling_to_item = false;
|
||||
bool selection_uncollapse_all = false;
|
||||
HashSet<ObjectID> unfold_cache;
|
||||
PopupMenu *item_menu = nullptr;
|
||||
EditorFileDialog *file_dialog = nullptr;
|
||||
@ -78,6 +80,7 @@ public:
|
||||
ObjectID get_selected_object();
|
||||
int get_current_debugger(); // Would love to have one tree for every debugger.
|
||||
void update_scene_tree(const SceneDebuggerTree *p_tree, int p_debugger);
|
||||
void select_node(ObjectID p_id);
|
||||
EditorDebuggerTree();
|
||||
};
|
||||
|
||||
|
@ -806,6 +806,10 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread
|
||||
} else if (p_msg == "request_quit") {
|
||||
emit_signal(SNAME("stop_requested"));
|
||||
_stop_and_notify();
|
||||
} else if (p_msg == "remote_node_clicked") {
|
||||
if (!p_data.is_empty()) {
|
||||
emit_signal(SNAME("remote_tree_select_requested"), p_data[0]);
|
||||
}
|
||||
} else if (p_msg == "performance:profile_names") {
|
||||
Vector<StringName> monitors;
|
||||
monitors.resize(p_data.size());
|
||||
@ -905,37 +909,42 @@ void ScriptEditorDebugger::_notification(int p_what) {
|
||||
if (is_session_active()) {
|
||||
peer->poll();
|
||||
|
||||
if (camera_override == CameraOverride::OVERRIDE_2D) {
|
||||
Dictionary state = CanvasItemEditor::get_singleton()->get_state();
|
||||
float zoom = state["zoom"];
|
||||
Point2 offset = state["ofs"];
|
||||
Transform2D transform;
|
||||
if (camera_override == CameraOverride::OVERRIDE_EDITORS) {
|
||||
// CanvasItem Editor
|
||||
{
|
||||
Dictionary state = CanvasItemEditor::get_singleton()->get_state();
|
||||
float zoom = state["zoom"];
|
||||
Point2 offset = state["ofs"];
|
||||
Transform2D transform;
|
||||
|
||||
transform.scale_basis(Size2(zoom, zoom));
|
||||
transform.columns[2] = -offset * zoom;
|
||||
transform.scale_basis(Size2(zoom, zoom));
|
||||
transform.columns[2] = -offset * zoom;
|
||||
|
||||
Array msg;
|
||||
msg.push_back(transform);
|
||||
_put_msg("scene:override_camera_2D:transform", msg);
|
||||
|
||||
} else if (camera_override >= CameraOverride::OVERRIDE_3D_1) {
|
||||
int viewport_idx = camera_override - CameraOverride::OVERRIDE_3D_1;
|
||||
Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_editor_viewport(viewport_idx);
|
||||
Camera3D *const cam = viewport->get_camera_3d();
|
||||
|
||||
Array msg;
|
||||
msg.push_back(cam->get_camera_transform());
|
||||
if (cam->get_projection() == Camera3D::PROJECTION_ORTHOGONAL) {
|
||||
msg.push_back(false);
|
||||
msg.push_back(cam->get_size());
|
||||
} else {
|
||||
msg.push_back(true);
|
||||
msg.push_back(cam->get_fov());
|
||||
Array msg;
|
||||
msg.push_back(transform);
|
||||
_put_msg("scene:transform_camera_2d", msg);
|
||||
}
|
||||
|
||||
// Node3D Editor
|
||||
{
|
||||
Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_last_used_viewport();
|
||||
const Camera3D *cam = viewport->get_camera_3d();
|
||||
|
||||
Array msg;
|
||||
msg.push_back(cam->get_camera_transform());
|
||||
if (cam->get_projection() == Camera3D::PROJECTION_ORTHOGONAL) {
|
||||
msg.push_back(false);
|
||||
msg.push_back(cam->get_size());
|
||||
} else {
|
||||
msg.push_back(true);
|
||||
msg.push_back(cam->get_fov());
|
||||
}
|
||||
msg.push_back(cam->get_near());
|
||||
msg.push_back(cam->get_far());
|
||||
_put_msg("scene:transform_camera_3d", msg);
|
||||
}
|
||||
msg.push_back(cam->get_near());
|
||||
msg.push_back(cam->get_far());
|
||||
_put_msg("scene:override_camera_3D:transform", msg);
|
||||
}
|
||||
|
||||
if (is_breaked() && can_request_idle_draw) {
|
||||
_put_msg("servers:draw", Array());
|
||||
can_request_idle_draw = false;
|
||||
@ -1469,23 +1478,10 @@ CameraOverride ScriptEditorDebugger::get_camera_override() const {
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::set_camera_override(CameraOverride p_override) {
|
||||
if (p_override == CameraOverride::OVERRIDE_2D && camera_override != CameraOverride::OVERRIDE_2D) {
|
||||
Array msg;
|
||||
msg.push_back(true);
|
||||
_put_msg("scene:override_camera_2D:set", msg);
|
||||
} else if (p_override != CameraOverride::OVERRIDE_2D && camera_override == CameraOverride::OVERRIDE_2D) {
|
||||
Array msg;
|
||||
msg.push_back(false);
|
||||
_put_msg("scene:override_camera_2D:set", msg);
|
||||
} else if (p_override >= CameraOverride::OVERRIDE_3D_1 && camera_override < CameraOverride::OVERRIDE_3D_1) {
|
||||
Array msg;
|
||||
msg.push_back(true);
|
||||
_put_msg("scene:override_camera_3D:set", msg);
|
||||
} else if (p_override < CameraOverride::OVERRIDE_3D_1 && camera_override >= CameraOverride::OVERRIDE_3D_1) {
|
||||
Array msg;
|
||||
msg.push_back(false);
|
||||
_put_msg("scene:override_camera_3D:set", msg);
|
||||
}
|
||||
Array msg;
|
||||
msg.push_back(p_override != CameraOverride::OVERRIDE_NONE);
|
||||
msg.push_back(p_override == CameraOverride::OVERRIDE_EDITORS);
|
||||
_put_msg("scene:override_cameras", msg);
|
||||
|
||||
camera_override = p_override;
|
||||
}
|
||||
@ -1776,6 +1772,7 @@ void ScriptEditorDebugger::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("remote_object_updated", PropertyInfo(Variant::INT, "id")));
|
||||
ADD_SIGNAL(MethodInfo("remote_object_property_updated", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property")));
|
||||
ADD_SIGNAL(MethodInfo("remote_tree_updated"));
|
||||
ADD_SIGNAL(MethodInfo("remote_tree_select_requested", PropertyInfo(Variant::NODE_PATH, "path")));
|
||||
ADD_SIGNAL(MethodInfo("output", PropertyInfo(Variant::STRING, "msg"), PropertyInfo(Variant::INT, "level")));
|
||||
ADD_SIGNAL(MethodInfo("stack_dump", PropertyInfo(Variant::ARRAY, "stack_dump")));
|
||||
ADD_SIGNAL(MethodInfo("stack_frame_vars", PropertyInfo(Variant::INT, "num_vars")));
|
||||
|
@ -43,6 +43,7 @@
|
||||
const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = {
|
||||
TTRC("3D Editor"),
|
||||
TTRC("Script Editor"),
|
||||
TTRC("Game View"),
|
||||
TTRC("Asset Library"),
|
||||
TTRC("Scene Tree Editing"),
|
||||
TTRC("Node Dock"),
|
||||
@ -54,6 +55,7 @@ const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = {
|
||||
const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = {
|
||||
TTRC("Allows to view and edit 3D scenes."),
|
||||
TTRC("Allows to edit scripts using the integrated script editor."),
|
||||
TTRC("Provides tools for selecting and debugging nodes at runtime."),
|
||||
TTRC("Provides built-in access to the Asset Library."),
|
||||
TTRC("Allows editing the node hierarchy in the Scene dock."),
|
||||
TTRC("Allows to work with signals and groups of the node selected in the Scene dock."),
|
||||
@ -65,6 +67,7 @@ const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = {
|
||||
const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
|
||||
"3d",
|
||||
"script",
|
||||
"game",
|
||||
"asset_lib",
|
||||
"scene_tree",
|
||||
"node_dock",
|
||||
@ -307,6 +310,7 @@ void EditorFeatureProfile::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(FEATURE_FILESYSTEM_DOCK);
|
||||
BIND_ENUM_CONSTANT(FEATURE_IMPORT_DOCK);
|
||||
BIND_ENUM_CONSTANT(FEATURE_HISTORY_DOCK);
|
||||
BIND_ENUM_CONSTANT(FEATURE_GAME);
|
||||
BIND_ENUM_CONSTANT(FEATURE_MAX);
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@ public:
|
||||
FEATURE_FILESYSTEM_DOCK,
|
||||
FEATURE_IMPORT_DOCK,
|
||||
FEATURE_HISTORY_DOCK,
|
||||
FEATURE_GAME,
|
||||
FEATURE_MAX
|
||||
};
|
||||
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
EDITOR_2D = 0,
|
||||
EDITOR_3D,
|
||||
EDITOR_SCRIPT,
|
||||
EDITOR_GAME,
|
||||
EDITOR_ASSETLIB,
|
||||
};
|
||||
|
||||
|
@ -145,6 +145,7 @@
|
||||
#include "editor/plugins/editor_plugin.h"
|
||||
#include "editor/plugins/editor_preview_plugins.h"
|
||||
#include "editor/plugins/editor_resource_conversion_plugin.h"
|
||||
#include "editor/plugins/game_view_plugin.h"
|
||||
#include "editor/plugins/gdextension_export_plugin.h"
|
||||
#include "editor/plugins/material_editor_plugin.h"
|
||||
#include "editor/plugins/mesh_library_editor_plugin.h"
|
||||
@ -357,6 +358,8 @@ void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) {
|
||||
editor_main_screen->select(EditorMainScreen::EDITOR_3D);
|
||||
} else if (ED_IS_SHORTCUT("editor/editor_script", p_event)) {
|
||||
editor_main_screen->select(EditorMainScreen::EDITOR_SCRIPT);
|
||||
} else if (ED_IS_SHORTCUT("editor/editor_game", p_event)) {
|
||||
editor_main_screen->select(EditorMainScreen::EDITOR_GAME);
|
||||
} else if (ED_IS_SHORTCUT("editor/editor_help", p_event)) {
|
||||
emit_signal(SNAME("request_help_search"), "");
|
||||
} else if (ED_IS_SHORTCUT("editor/editor_assetlib", p_event) && AssetLibraryEditorPlugin::is_available()) {
|
||||
@ -6577,6 +6580,7 @@ void EditorNode::_feature_profile_changed() {
|
||||
|
||||
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_3D, !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D));
|
||||
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_SCRIPT, !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT));
|
||||
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_GAME, !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_GAME));
|
||||
if (AssetLibraryEditorPlugin::is_available()) {
|
||||
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_ASSETLIB, !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB));
|
||||
}
|
||||
@ -6587,6 +6591,7 @@ void EditorNode::_feature_profile_changed() {
|
||||
editor_dock_manager->set_dock_enabled(history_dock, true);
|
||||
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_3D, true);
|
||||
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_SCRIPT, true);
|
||||
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_GAME, true);
|
||||
if (AssetLibraryEditorPlugin::is_available()) {
|
||||
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_ASSETLIB, true);
|
||||
}
|
||||
@ -7714,6 +7719,7 @@ EditorNode::EditorNode() {
|
||||
add_editor_plugin(memnew(CanvasItemEditorPlugin));
|
||||
add_editor_plugin(memnew(Node3DEditorPlugin));
|
||||
add_editor_plugin(memnew(ScriptEditorPlugin));
|
||||
add_editor_plugin(memnew(GameViewPlugin));
|
||||
|
||||
EditorAudioBuses *audio_bus_editor = EditorAudioBuses::register_editor();
|
||||
|
||||
@ -7896,12 +7902,14 @@ EditorNode::EditorNode() {
|
||||
ED_SHORTCUT_AND_COMMAND("editor/editor_2d", TTR("Open 2D Editor"), KeyModifierMask::CTRL | Key::F1);
|
||||
ED_SHORTCUT_AND_COMMAND("editor/editor_3d", TTR("Open 3D Editor"), KeyModifierMask::CTRL | Key::F2);
|
||||
ED_SHORTCUT_AND_COMMAND("editor/editor_script", TTR("Open Script Editor"), KeyModifierMask::CTRL | Key::F3);
|
||||
ED_SHORTCUT_AND_COMMAND("editor/editor_assetlib", TTR("Open Asset Library"), KeyModifierMask::CTRL | Key::F4);
|
||||
ED_SHORTCUT_AND_COMMAND("editor/editor_game", TTR("Open Game View"), KeyModifierMask::CTRL | Key::F4);
|
||||
ED_SHORTCUT_AND_COMMAND("editor/editor_assetlib", TTR("Open Asset Library"), KeyModifierMask::CTRL | Key::F5);
|
||||
|
||||
ED_SHORTCUT_OVERRIDE("editor/editor_2d", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_1);
|
||||
ED_SHORTCUT_OVERRIDE("editor/editor_3d", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_2);
|
||||
ED_SHORTCUT_OVERRIDE("editor/editor_script", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_3);
|
||||
ED_SHORTCUT_OVERRIDE("editor/editor_assetlib", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_4);
|
||||
ED_SHORTCUT_OVERRIDE("editor/editor_game", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_4);
|
||||
ED_SHORTCUT_OVERRIDE("editor/editor_assetlib", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_5);
|
||||
|
||||
ED_SHORTCUT_AND_COMMAND("editor/editor_next", TTR("Open the next Editor"));
|
||||
ED_SHORTCUT_AND_COMMAND("editor/editor_prev", TTR("Open the previous Editor"));
|
||||
|
1
editor/icons/2DNodes.svg
Normal file
1
editor/icons/2DNodes.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path fill="none" stroke="#8da5f3" stroke-width="2" d="M 8,13 C 5.2385763,13 3,10.761424 3,8 3,5.2385763 5.2385763,3 8,3"/><path fill="none" stroke="#8eef97" stroke-width="2" d="m 8,13 c 2.761424,0 5,-2.238576 5,-5 C 13,5.2385763 10.761424,3 8,3"/></svg>
|
After Width: | Height: | Size: 338 B |
1
editor/icons/Camera.svg
Normal file
1
editor/icons/Camera.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path fill="#e0e0e0" d="M9 2a3 3 0 0 0-3 2.777 3 3 0 1 0-3 5.047V12a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-1l3 2V7l-3 2V7.23A3 3 0 0 0 9 2z"/></svg>
|
After Width: | Height: | Size: 224 B |
1
editor/icons/Game.svg
Normal file
1
editor/icons/Game.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M 1,15 V 12 C 1,11.5 1.5,11 2,11 H 3 V 10 C 3,9.5 3.5,9 4,9 h 1 c 0.5,0 1,0.5 1,1 v 1 H 8 V 5 h 2 v 6 h 4 c 0.5,0 1,0.5 1,1 v 3 z"/><circle cx="9" cy="4" r="3" fill="#e0e0e0"/></svg>
|
After Width: | Height: | Size: 269 B |
1
editor/icons/NextFrame.svg
Normal file
1
editor/icons/NextFrame.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="m 12,3 c -0.552285,0 -1,0.4477153 -1,1 v 8 c 0,0.552285 0.447715,1 1,1 h 1 c 0.552285,0 1,-0.447715 1,-1 V 4 C 14,3.4477153 13.552285,3 13,3 Z M 2.975,3.002 C 2.4332786,3.0155465 2.0009144,3.45811 2,4 v 8 c -3.148e-4,0.838862 0.9701632,1.305289 1.625,0.781 l 5,-4 c 0.4989606,-0.4003069 0.4989606,-1.1596931 0,-1.56 l -5,-4 C 3.4409271,3.0736532 3.2107095,2.9960875 2.975,3.002 Z"/></svg>
|
After Width: | Height: | Size: 475 B |
@ -3977,7 +3977,6 @@ void CanvasItemEditor::_update_editor_settings() {
|
||||
grid_snap_button->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
|
||||
snap_config_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
|
||||
skeleton_menu->set_button_icon(get_editor_theme_icon(SNAME("Bone")));
|
||||
override_camera_button->set_button_icon(get_editor_theme_icon(SNAME("Camera2D")));
|
||||
pan_button->set_button_icon(get_editor_theme_icon(SNAME("ToolPan")));
|
||||
ruler_button->set_button_icon(get_editor_theme_icon(SNAME("Ruler")));
|
||||
pivot_button->set_button_icon(get_editor_theme_icon(SNAME("EditPivot")));
|
||||
@ -4016,8 +4015,6 @@ void CanvasItemEditor::_notification(int p_what) {
|
||||
case NOTIFICATION_READY: {
|
||||
_update_lock_and_group_button();
|
||||
|
||||
EditorRunBar::get_singleton()->connect("play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
|
||||
EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
|
||||
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &CanvasItemEditor::_project_settings_changed));
|
||||
} break;
|
||||
|
||||
@ -4116,15 +4113,6 @@ void CanvasItemEditor::_notification(int p_what) {
|
||||
_update_editor_settings();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
if (!is_visible() && override_camera_button->is_pressed()) {
|
||||
EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
|
||||
|
||||
debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
|
||||
override_camera_button->set_pressed(false);
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_APPLICATION_FOCUS_OUT:
|
||||
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
|
||||
if (drag_type != DRAG_NONE) {
|
||||
@ -4282,16 +4270,6 @@ void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) {
|
||||
viewport->queue_redraw();
|
||||
}
|
||||
|
||||
void CanvasItemEditor::_button_override_camera(bool p_pressed) {
|
||||
EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
|
||||
|
||||
if (p_pressed) {
|
||||
debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_2D);
|
||||
} else {
|
||||
debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasItemEditor::_button_tool_select(int p_index) {
|
||||
Button *tb[TOOL_MAX] = { select_button, list_select_button, move_button, scale_button, rotate_button, pivot_button, pan_button, ruler_button };
|
||||
for (int i = 0; i < TOOL_MAX; i++) {
|
||||
@ -4398,17 +4376,6 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
|
||||
te->commit_insert_queue();
|
||||
}
|
||||
|
||||
void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
|
||||
if (p_game_running) {
|
||||
override_camera_button->set_disabled(false);
|
||||
override_camera_button->set_tooltip_text(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
|
||||
} else {
|
||||
override_camera_button->set_disabled(true);
|
||||
override_camera_button->set_pressed(false);
|
||||
override_camera_button->set_tooltip_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasItemEditor::_popup_callback(int p_op) {
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
last_option = MenuOption(p_op);
|
||||
@ -5514,16 +5481,6 @@ CanvasItemEditor::CanvasItemEditor() {
|
||||
|
||||
main_menu_hbox->add_child(memnew(VSeparator));
|
||||
|
||||
override_camera_button = memnew(Button);
|
||||
override_camera_button->set_theme_type_variation("FlatButton");
|
||||
main_menu_hbox->add_child(override_camera_button);
|
||||
override_camera_button->connect(SceneStringName(toggled), callable_mp(this, &CanvasItemEditor::_button_override_camera));
|
||||
override_camera_button->set_toggle_mode(true);
|
||||
override_camera_button->set_disabled(true);
|
||||
_update_override_camera_button(false);
|
||||
|
||||
main_menu_hbox->add_child(memnew(VSeparator));
|
||||
|
||||
view_menu = memnew(MenuButton);
|
||||
view_menu->set_flat(false);
|
||||
view_menu->set_theme_type_variation("FlatMenuButton");
|
||||
|
@ -335,7 +335,6 @@ private:
|
||||
Button *group_button = nullptr;
|
||||
Button *ungroup_button = nullptr;
|
||||
|
||||
Button *override_camera_button = nullptr;
|
||||
MenuButton *view_menu = nullptr;
|
||||
PopupMenu *grid_menu = nullptr;
|
||||
PopupMenu *theme_menu = nullptr;
|
||||
@ -518,11 +517,8 @@ private:
|
||||
void _zoom_on_position(real_t p_zoom, Point2 p_position = Point2());
|
||||
void _button_toggle_smart_snap(bool p_status);
|
||||
void _button_toggle_grid_snap(bool p_status);
|
||||
void _button_override_camera(bool p_pressed);
|
||||
void _button_tool_select(int p_index);
|
||||
|
||||
void _update_override_camera_button(bool p_game_running);
|
||||
|
||||
HSplitContainer *left_panel_split = nullptr;
|
||||
HSplitContainer *right_panel_split = nullptr;
|
||||
VSplitContainer *bottom_split = nullptr;
|
||||
|
478
editor/plugins/game_view_plugin.cpp
Normal file
478
editor/plugins/game_view_plugin.cpp
Normal file
@ -0,0 +1,478 @@
|
||||
/**************************************************************************/
|
||||
/* game_view_plugin.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "game_view_plugin.h"
|
||||
|
||||
#include "editor/editor_main_screen.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/menu_button.h"
|
||||
#include "scene/gui/panel.h"
|
||||
#include "scene/gui/separator.h"
|
||||
|
||||
void GameViewDebugger::_session_started(Ref<EditorDebuggerSession> p_session) {
|
||||
p_session->send_message("scene:runtime_node_select_setup", Array());
|
||||
|
||||
Array type;
|
||||
type.append(node_type);
|
||||
p_session->send_message("scene:runtime_node_select_set_type", type);
|
||||
Array visible;
|
||||
visible.append(selection_visible);
|
||||
p_session->send_message("scene:runtime_node_select_set_visible", visible);
|
||||
Array mode;
|
||||
mode.append(select_mode);
|
||||
p_session->send_message("scene:runtime_node_select_set_mode", mode);
|
||||
|
||||
emit_signal(SNAME("session_started"));
|
||||
}
|
||||
|
||||
void GameViewDebugger::_session_stopped() {
|
||||
emit_signal(SNAME("session_stopped"));
|
||||
}
|
||||
|
||||
void GameViewDebugger::set_suspend(bool p_enabled) {
|
||||
Array message;
|
||||
message.append(p_enabled);
|
||||
|
||||
for (Ref<EditorDebuggerSession> &I : sessions) {
|
||||
if (I->is_active()) {
|
||||
I->send_message("scene:suspend_changed", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameViewDebugger::next_frame() {
|
||||
for (Ref<EditorDebuggerSession> &I : sessions) {
|
||||
if (I->is_active()) {
|
||||
I->send_message("scene:next_frame", Array());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameViewDebugger::set_node_type(int p_type) {
|
||||
node_type = p_type;
|
||||
|
||||
Array message;
|
||||
message.append(p_type);
|
||||
|
||||
for (Ref<EditorDebuggerSession> &I : sessions) {
|
||||
if (I->is_active()) {
|
||||
I->send_message("scene:runtime_node_select_set_type", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameViewDebugger::set_selection_visible(bool p_visible) {
|
||||
selection_visible = p_visible;
|
||||
|
||||
Array message;
|
||||
message.append(p_visible);
|
||||
|
||||
for (Ref<EditorDebuggerSession> &I : sessions) {
|
||||
if (I->is_active()) {
|
||||
I->send_message("scene:runtime_node_select_set_visible", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameViewDebugger::set_select_mode(int p_mode) {
|
||||
select_mode = p_mode;
|
||||
|
||||
Array message;
|
||||
message.append(p_mode);
|
||||
|
||||
for (Ref<EditorDebuggerSession> &I : sessions) {
|
||||
if (I->is_active()) {
|
||||
I->send_message("scene:runtime_node_select_set_mode", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameViewDebugger::set_camera_override(bool p_enabled) {
|
||||
EditorDebuggerNode::get_singleton()->set_camera_override(p_enabled ? camera_override_mode : EditorDebuggerNode::OVERRIDE_NONE);
|
||||
}
|
||||
|
||||
void GameViewDebugger::set_camera_manipulate_mode(EditorDebuggerNode::CameraOverride p_mode) {
|
||||
camera_override_mode = p_mode;
|
||||
|
||||
if (EditorDebuggerNode::get_singleton()->get_camera_override() != EditorDebuggerNode::OVERRIDE_NONE) {
|
||||
set_camera_override(true);
|
||||
}
|
||||
}
|
||||
|
||||
void GameViewDebugger::reset_camera_2d_position() {
|
||||
for (Ref<EditorDebuggerSession> &I : sessions) {
|
||||
if (I->is_active()) {
|
||||
I->send_message("scene:runtime_node_select_reset_camera_2d", Array());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameViewDebugger::reset_camera_3d_position() {
|
||||
for (Ref<EditorDebuggerSession> &I : sessions) {
|
||||
if (I->is_active()) {
|
||||
I->send_message("scene:runtime_node_select_reset_camera_3d", Array());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameViewDebugger::setup_session(int p_session_id) {
|
||||
Ref<EditorDebuggerSession> session = get_session(p_session_id);
|
||||
ERR_FAIL_COND(session.is_null());
|
||||
|
||||
sessions.append(session);
|
||||
|
||||
session->connect("started", callable_mp(this, &GameViewDebugger::_session_started).bind(session));
|
||||
session->connect("stopped", callable_mp(this, &GameViewDebugger::_session_stopped));
|
||||
}
|
||||
|
||||
void GameViewDebugger::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("session_started"));
|
||||
ADD_SIGNAL(MethodInfo("session_stopped"));
|
||||
}
|
||||
|
||||
///////
|
||||
|
||||
void GameView::_sessions_changed() {
|
||||
// The debugger session's `session_started/stopped` signal can be unreliable, so count it manually.
|
||||
active_sessions = 0;
|
||||
Array sessions = debugger->get_sessions();
|
||||
for (int i = 0; i < sessions.size(); i++) {
|
||||
if (Object::cast_to<EditorDebuggerSession>(sessions[i])->is_active()) {
|
||||
active_sessions++;
|
||||
}
|
||||
}
|
||||
|
||||
_update_debugger_buttons();
|
||||
}
|
||||
|
||||
void GameView::_update_debugger_buttons() {
|
||||
bool empty = active_sessions == 0;
|
||||
|
||||
suspend_button->set_disabled(empty);
|
||||
camera_override_button->set_disabled(empty);
|
||||
|
||||
PopupMenu *menu = camera_override_menu->get_popup();
|
||||
|
||||
bool disable_camera_reset = empty || !camera_override_button->is_pressed() || !menu->is_item_checked(menu->get_item_index(CAMERA_MODE_INGAME));
|
||||
menu->set_item_disabled(CAMERA_RESET_2D, disable_camera_reset);
|
||||
menu->set_item_disabled(CAMERA_RESET_3D, disable_camera_reset);
|
||||
|
||||
if (empty) {
|
||||
suspend_button->set_pressed(false);
|
||||
camera_override_button->set_pressed(false);
|
||||
}
|
||||
next_frame_button->set_disabled(!suspend_button->is_pressed());
|
||||
}
|
||||
|
||||
void GameView::_suspend_button_toggled(bool p_pressed) {
|
||||
_update_debugger_buttons();
|
||||
|
||||
debugger->set_suspend(p_pressed);
|
||||
}
|
||||
|
||||
void GameView::_node_type_pressed(int p_option) {
|
||||
RuntimeNodeSelect::NodeType type = (RuntimeNodeSelect::NodeType)p_option;
|
||||
for (int i = 0; i < RuntimeNodeSelect::NODE_TYPE_MAX; i++) {
|
||||
node_type_button[i]->set_pressed_no_signal(i == type);
|
||||
}
|
||||
|
||||
_update_debugger_buttons();
|
||||
|
||||
debugger->set_node_type(type);
|
||||
}
|
||||
|
||||
void GameView::_select_mode_pressed(int p_option) {
|
||||
RuntimeNodeSelect::SelectMode mode = (RuntimeNodeSelect::SelectMode)p_option;
|
||||
for (int i = 0; i < RuntimeNodeSelect::SELECT_MODE_MAX; i++) {
|
||||
select_mode_button[i]->set_pressed_no_signal(i == mode);
|
||||
}
|
||||
|
||||
debugger->set_select_mode(mode);
|
||||
}
|
||||
|
||||
void GameView::_hide_selection_toggled(bool p_pressed) {
|
||||
hide_selection->set_button_icon(get_editor_theme_icon(p_pressed ? SNAME("GuiVisibilityHidden") : SNAME("GuiVisibilityVisible")));
|
||||
|
||||
debugger->set_selection_visible(!p_pressed);
|
||||
}
|
||||
|
||||
void GameView::_camera_override_button_toggled(bool p_pressed) {
|
||||
_update_debugger_buttons();
|
||||
|
||||
debugger->set_camera_override(p_pressed);
|
||||
}
|
||||
|
||||
void GameView::_camera_override_menu_id_pressed(int p_id) {
|
||||
PopupMenu *menu = camera_override_menu->get_popup();
|
||||
if (p_id != CAMERA_RESET_2D && p_id != CAMERA_RESET_3D) {
|
||||
for (int i = 0; i < menu->get_item_count(); i++) {
|
||||
menu->set_item_checked(i, false);
|
||||
}
|
||||
}
|
||||
|
||||
switch (p_id) {
|
||||
case CAMERA_RESET_2D: {
|
||||
debugger->reset_camera_2d_position();
|
||||
} break;
|
||||
case CAMERA_RESET_3D: {
|
||||
debugger->reset_camera_3d_position();
|
||||
} break;
|
||||
case CAMERA_MODE_INGAME: {
|
||||
debugger->set_camera_manipulate_mode(EditorDebuggerNode::OVERRIDE_INGAME);
|
||||
menu->set_item_checked(menu->get_item_index(p_id), true);
|
||||
|
||||
_update_debugger_buttons();
|
||||
} break;
|
||||
case CAMERA_MODE_EDITORS: {
|
||||
debugger->set_camera_manipulate_mode(EditorDebuggerNode::OVERRIDE_EDITORS);
|
||||
menu->set_item_checked(menu->get_item_index(p_id), true);
|
||||
|
||||
_update_debugger_buttons();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void GameView::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
suspend_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
|
||||
next_frame_button->set_button_icon(get_editor_theme_icon(SNAME("NextFrame")));
|
||||
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_button_icon(get_editor_theme_icon(SNAME("InputEventJoypadMotion")));
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_button_icon(get_editor_theme_icon(SNAME("2DNodes")));
|
||||
#ifndef _3D_DISABLED
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_button_icon(get_editor_theme_icon(SNAME("Node3D")));
|
||||
#endif // _3D_DISABLED
|
||||
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_button_icon(get_editor_theme_icon(SNAME("ListSelect")));
|
||||
|
||||
hide_selection->set_button_icon(get_editor_theme_icon(hide_selection->is_pressed() ? SNAME("GuiVisibilityHidden") : SNAME("GuiVisibilityVisible")));
|
||||
|
||||
camera_override_button->set_button_icon(get_editor_theme_icon(SNAME("Camera")));
|
||||
camera_override_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void GameView::set_state(const Dictionary &p_state) {
|
||||
if (p_state.has("hide_selection")) {
|
||||
hide_selection->set_pressed(p_state["hide_selection"]);
|
||||
_hide_selection_toggled(hide_selection->is_pressed());
|
||||
}
|
||||
if (p_state.has("select_mode")) {
|
||||
_select_mode_pressed(p_state["select_mode"]);
|
||||
}
|
||||
if (p_state.has("camera_override_mode")) {
|
||||
_camera_override_menu_id_pressed(p_state["camera_override_mode"]);
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary GameView::get_state() const {
|
||||
Dictionary d;
|
||||
d["hide_selection"] = hide_selection->is_pressed();
|
||||
|
||||
for (int i = 0; i < RuntimeNodeSelect::SELECT_MODE_MAX; i++) {
|
||||
if (select_mode_button[i]->is_pressed()) {
|
||||
d["select_mode"] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PopupMenu *menu = camera_override_menu->get_popup();
|
||||
for (int i = CAMERA_MODE_INGAME; i < CAMERA_MODE_EDITORS + 1; i++) {
|
||||
if (menu->is_item_checked(menu->get_item_index(i))) {
|
||||
d["camera_override_mode"] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
GameView::GameView(Ref<GameViewDebugger> p_debugger) {
|
||||
debugger = p_debugger;
|
||||
|
||||
// Add some margin to the sides for better aesthetics.
|
||||
// This prevents the first button's hover/pressed effect from "touching" the panel's border,
|
||||
// which looks ugly.
|
||||
MarginContainer *toolbar_margin = memnew(MarginContainer);
|
||||
toolbar_margin->add_theme_constant_override("margin_left", 4 * EDSCALE);
|
||||
toolbar_margin->add_theme_constant_override("margin_right", 4 * EDSCALE);
|
||||
add_child(toolbar_margin);
|
||||
|
||||
HBoxContainer *main_menu_hbox = memnew(HBoxContainer);
|
||||
toolbar_margin->add_child(main_menu_hbox);
|
||||
|
||||
suspend_button = memnew(Button);
|
||||
main_menu_hbox->add_child(suspend_button);
|
||||
suspend_button->set_toggle_mode(true);
|
||||
suspend_button->set_theme_type_variation("FlatButton");
|
||||
suspend_button->connect(SceneStringName(toggled), callable_mp(this, &GameView::_suspend_button_toggled));
|
||||
suspend_button->set_tooltip_text(TTR("Suspend"));
|
||||
|
||||
next_frame_button = memnew(Button);
|
||||
main_menu_hbox->add_child(next_frame_button);
|
||||
next_frame_button->set_theme_type_variation("FlatButton");
|
||||
next_frame_button->connect(SceneStringName(pressed), callable_mp(*debugger, &GameViewDebugger::next_frame));
|
||||
next_frame_button->set_tooltip_text(TTR("Next Frame"));
|
||||
|
||||
main_menu_hbox->add_child(memnew(VSeparator));
|
||||
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE] = memnew(Button);
|
||||
main_menu_hbox->add_child(node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]);
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_text(TTR("Input"));
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_toggle_mode(true);
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_pressed(true);
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_theme_type_variation("FlatButton");
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_node_type_pressed).bind(RuntimeNodeSelect::NODE_TYPE_NONE));
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_tooltip_text(TTR("Allow game input."));
|
||||
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D] = memnew(Button);
|
||||
main_menu_hbox->add_child(node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]);
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_text(TTR("2D"));
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_toggle_mode(true);
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_theme_type_variation("FlatButton");
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_node_type_pressed).bind(RuntimeNodeSelect::NODE_TYPE_2D));
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_tooltip_text(TTR("Disable game input and allow to select Node2Ds, Controls, and manipulate the 2D camera."));
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D] = memnew(Button);
|
||||
main_menu_hbox->add_child(node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]);
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_text(TTR("3D"));
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_toggle_mode(true);
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_theme_type_variation("FlatButton");
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_node_type_pressed).bind(RuntimeNodeSelect::NODE_TYPE_3D));
|
||||
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_tooltip_text(TTR("Disable game input and allow to select Node3Ds and manipulate the 3D camera."));
|
||||
#endif // _3D_DISABLED
|
||||
|
||||
main_menu_hbox->add_child(memnew(VSeparator));
|
||||
|
||||
hide_selection = memnew(Button);
|
||||
main_menu_hbox->add_child(hide_selection);
|
||||
hide_selection->set_toggle_mode(true);
|
||||
hide_selection->set_theme_type_variation("FlatButton");
|
||||
hide_selection->connect(SceneStringName(toggled), callable_mp(this, &GameView::_hide_selection_toggled));
|
||||
hide_selection->set_tooltip_text(TTR("Toggle Selection Visibility"));
|
||||
|
||||
main_menu_hbox->add_child(memnew(VSeparator));
|
||||
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE] = memnew(Button);
|
||||
main_menu_hbox->add_child(select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]);
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_toggle_mode(true);
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_pressed(true);
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_theme_type_variation("FlatButton");
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_select_mode_pressed).bind(RuntimeNodeSelect::SELECT_MODE_SINGLE));
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), Key::Q));
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_shortcut_context(this);
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Alt+RMB: Show list of all nodes at position clicked."));
|
||||
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST] = memnew(Button);
|
||||
main_menu_hbox->add_child(select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]);
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_toggle_mode(true);
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_theme_type_variation("FlatButton");
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_select_mode_pressed).bind(RuntimeNodeSelect::SELECT_MODE_LIST));
|
||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_tooltip_text(TTR("Show list of selectable nodes at position clicked."));
|
||||
|
||||
main_menu_hbox->add_child(memnew(VSeparator));
|
||||
|
||||
camera_override_button = memnew(Button);
|
||||
main_menu_hbox->add_child(camera_override_button);
|
||||
camera_override_button->set_toggle_mode(true);
|
||||
camera_override_button->set_theme_type_variation("FlatButton");
|
||||
camera_override_button->connect(SceneStringName(toggled), callable_mp(this, &GameView::_camera_override_button_toggled));
|
||||
camera_override_button->set_tooltip_text(TTR("Override the in-game camera."));
|
||||
|
||||
camera_override_menu = memnew(MenuButton);
|
||||
main_menu_hbox->add_child(camera_override_menu);
|
||||
camera_override_menu->set_flat(false);
|
||||
camera_override_menu->set_theme_type_variation("FlatMenuButton");
|
||||
camera_override_menu->set_h_size_flags(SIZE_SHRINK_END);
|
||||
camera_override_menu->set_tooltip_text(TTR("Camera Override Options"));
|
||||
|
||||
PopupMenu *menu = camera_override_menu->get_popup();
|
||||
menu->connect(SceneStringName(id_pressed), callable_mp(this, &GameView::_camera_override_menu_id_pressed));
|
||||
menu->add_item(TTR("Reset 2D Camera"), CAMERA_RESET_2D);
|
||||
menu->add_item(TTR("Reset 3D Camera"), CAMERA_RESET_3D);
|
||||
menu->add_separator();
|
||||
menu->add_radio_check_item(TTR("Manipulate In-Game"), CAMERA_MODE_INGAME);
|
||||
menu->set_item_checked(menu->get_item_index(CAMERA_MODE_INGAME), true);
|
||||
menu->add_radio_check_item(TTR("Manipulate From Editors"), CAMERA_MODE_EDITORS);
|
||||
|
||||
_update_debugger_buttons();
|
||||
|
||||
panel = memnew(Panel);
|
||||
add_child(panel);
|
||||
panel->set_theme_type_variation("GamePanel");
|
||||
panel->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
p_debugger->connect("session_started", callable_mp(this, &GameView::_sessions_changed));
|
||||
p_debugger->connect("session_stopped", callable_mp(this, &GameView::_sessions_changed));
|
||||
}
|
||||
|
||||
///////
|
||||
|
||||
void GameViewPlugin::make_visible(bool p_visible) {
|
||||
game_view->set_visible(p_visible);
|
||||
}
|
||||
|
||||
void GameViewPlugin::set_state(const Dictionary &p_state) {
|
||||
game_view->set_state(p_state);
|
||||
}
|
||||
|
||||
Dictionary GameViewPlugin::get_state() const {
|
||||
return game_view->get_state();
|
||||
}
|
||||
|
||||
void GameViewPlugin::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
add_debugger_plugin(debugger);
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
remove_debugger_plugin(debugger);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
GameViewPlugin::GameViewPlugin() {
|
||||
debugger.instantiate();
|
||||
|
||||
game_view = memnew(GameView(debugger));
|
||||
game_view->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
EditorNode::get_singleton()->get_editor_main_screen()->get_control()->add_child(game_view);
|
||||
game_view->hide();
|
||||
}
|
||||
|
||||
GameViewPlugin::~GameViewPlugin() {
|
||||
}
|
152
editor/plugins/game_view_plugin.h
Normal file
152
editor/plugins/game_view_plugin.h
Normal file
@ -0,0 +1,152 @@
|
||||
/**************************************************************************/
|
||||
/* game_view_plugin.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GAME_VIEW_PLUGIN_H
|
||||
#define GAME_VIEW_PLUGIN_H
|
||||
|
||||
#include "editor/debugger/editor_debugger_node.h"
|
||||
#include "editor/plugins/editor_debugger_plugin.h"
|
||||
#include "editor/plugins/editor_plugin.h"
|
||||
#include "scene/debugger/scene_debugger.h"
|
||||
#include "scene/gui/box_container.h"
|
||||
|
||||
class GameViewDebugger : public EditorDebuggerPlugin {
|
||||
GDCLASS(GameViewDebugger, EditorDebuggerPlugin);
|
||||
|
||||
private:
|
||||
Vector<Ref<EditorDebuggerSession>> sessions;
|
||||
|
||||
int node_type = RuntimeNodeSelect::NODE_TYPE_NONE;
|
||||
bool selection_visible = true;
|
||||
int select_mode = RuntimeNodeSelect::SELECT_MODE_SINGLE;
|
||||
EditorDebuggerNode::CameraOverride camera_override_mode = EditorDebuggerNode::OVERRIDE_INGAME;
|
||||
|
||||
void _session_started(Ref<EditorDebuggerSession> p_session);
|
||||
void _session_stopped();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_suspend(bool p_enabled);
|
||||
void next_frame();
|
||||
|
||||
void set_node_type(int p_type);
|
||||
void set_select_mode(int p_mode);
|
||||
|
||||
void set_selection_visible(bool p_visible);
|
||||
|
||||
void set_camera_override(bool p_enabled);
|
||||
void set_camera_manipulate_mode(EditorDebuggerNode::CameraOverride p_mode);
|
||||
|
||||
void reset_camera_2d_position();
|
||||
void reset_camera_3d_position();
|
||||
|
||||
virtual void setup_session(int p_session_id) override;
|
||||
|
||||
GameViewDebugger() {}
|
||||
};
|
||||
|
||||
class GameView : public VBoxContainer {
|
||||
GDCLASS(GameView, VBoxContainer);
|
||||
|
||||
enum {
|
||||
CAMERA_RESET_2D,
|
||||
CAMERA_RESET_3D,
|
||||
CAMERA_MODE_INGAME,
|
||||
CAMERA_MODE_EDITORS,
|
||||
};
|
||||
|
||||
Ref<GameViewDebugger> debugger;
|
||||
|
||||
int active_sessions = 0;
|
||||
|
||||
Button *suspend_button = nullptr;
|
||||
Button *next_frame_button = nullptr;
|
||||
|
||||
Button *node_type_button[RuntimeNodeSelect::NODE_TYPE_MAX];
|
||||
Button *select_mode_button[RuntimeNodeSelect::SELECT_MODE_MAX];
|
||||
|
||||
Button *hide_selection = nullptr;
|
||||
|
||||
Button *camera_override_button = nullptr;
|
||||
MenuButton *camera_override_menu = nullptr;
|
||||
|
||||
Panel *panel = nullptr;
|
||||
|
||||
void _sessions_changed();
|
||||
|
||||
void _update_debugger_buttons();
|
||||
|
||||
void _suspend_button_toggled(bool p_pressed);
|
||||
|
||||
void _node_type_pressed(int p_option);
|
||||
void _select_mode_pressed(int p_option);
|
||||
|
||||
void _hide_selection_toggled(bool p_pressed);
|
||||
|
||||
void _camera_override_button_toggled(bool p_pressed);
|
||||
void _camera_override_menu_id_pressed(int p_id);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
void set_state(const Dictionary &p_state);
|
||||
Dictionary get_state() const;
|
||||
|
||||
GameView(Ref<GameViewDebugger> p_debugger);
|
||||
};
|
||||
|
||||
class GameViewPlugin : public EditorPlugin {
|
||||
GDCLASS(GameViewPlugin, EditorPlugin);
|
||||
|
||||
GameView *game_view = nullptr;
|
||||
|
||||
Ref<GameViewDebugger> debugger;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
virtual String get_name() const override { return "Game"; }
|
||||
bool has_main_screen() const override { return true; }
|
||||
virtual void edit(Object *p_object) override {}
|
||||
virtual bool handles(Object *p_object) const override { return false; }
|
||||
virtual void make_visible(bool p_visible) override;
|
||||
|
||||
virtual void set_state(const Dictionary &p_state) override;
|
||||
virtual Dictionary get_state() const override;
|
||||
|
||||
GameViewPlugin();
|
||||
~GameViewPlugin();
|
||||
};
|
||||
|
||||
#endif // GAME_VIEW_PLUGIN_H
|
@ -1692,7 +1692,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
||||
Ref<InputEventMouseButton> b = p_event;
|
||||
|
||||
if (b.is_valid()) {
|
||||
emit_signal(SNAME("clicked"), this);
|
||||
emit_signal(SNAME("clicked"));
|
||||
|
||||
ViewportNavMouseButton orbit_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/orbit_mouse_button").operator int();
|
||||
ViewportNavMouseButton pan_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/pan_mouse_button").operator int();
|
||||
@ -4210,7 +4210,7 @@ Dictionary Node3DEditorViewport::get_state() const {
|
||||
|
||||
void Node3DEditorViewport::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
|
||||
ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
|
||||
ADD_SIGNAL(MethodInfo("clicked"));
|
||||
}
|
||||
|
||||
void Node3DEditorViewport::reset() {
|
||||
@ -6572,18 +6572,6 @@ void Node3DEditor::_menu_item_toggled(bool pressed, int p_option) {
|
||||
tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(pressed);
|
||||
snap_enabled = pressed;
|
||||
} break;
|
||||
|
||||
case MENU_TOOL_OVERRIDE_CAMERA: {
|
||||
EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton();
|
||||
|
||||
using Override = EditorDebuggerNode::CameraOverride;
|
||||
if (pressed) {
|
||||
debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
|
||||
} else {
|
||||
debugger->set_camera_override(Override::OVERRIDE_NONE);
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6610,36 +6598,6 @@ void Node3DEditor::_menu_gizmo_toggled(int p_option) {
|
||||
update_all_gizmos();
|
||||
}
|
||||
|
||||
void Node3DEditor::_update_camera_override_button(bool p_game_running) {
|
||||
Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA];
|
||||
|
||||
if (p_game_running) {
|
||||
button->set_disabled(false);
|
||||
button->set_tooltip_text(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
|
||||
} else {
|
||||
button->set_disabled(true);
|
||||
button->set_pressed(false);
|
||||
button->set_tooltip_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
|
||||
}
|
||||
}
|
||||
|
||||
void Node3DEditor::_update_camera_override_viewport(Object *p_viewport) {
|
||||
Node3DEditorViewport *current_viewport = Object::cast_to<Node3DEditorViewport>(p_viewport);
|
||||
|
||||
if (!current_viewport) {
|
||||
return;
|
||||
}
|
||||
|
||||
EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton();
|
||||
|
||||
camera_override_viewport_id = current_viewport->index;
|
||||
if (debugger->get_camera_override() >= EditorDebuggerNode::OVERRIDE_3D_1) {
|
||||
using Override = EditorDebuggerNode::CameraOverride;
|
||||
|
||||
debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
|
||||
}
|
||||
}
|
||||
|
||||
void Node3DEditor::_menu_item_pressed(int p_option) {
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
switch (p_option) {
|
||||
@ -6670,6 +6628,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
|
||||
} break;
|
||||
case MENU_VIEW_USE_1_VIEWPORT: {
|
||||
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_1_VIEWPORT);
|
||||
if (last_used_viewport > 0) {
|
||||
last_used_viewport = 0;
|
||||
}
|
||||
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), true);
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
|
||||
@ -6681,6 +6642,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
|
||||
} break;
|
||||
case MENU_VIEW_USE_2_VIEWPORTS: {
|
||||
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_2_VIEWPORTS);
|
||||
if (last_used_viewport > 1) {
|
||||
last_used_viewport = 0;
|
||||
}
|
||||
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), true);
|
||||
@ -6692,6 +6656,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
|
||||
} break;
|
||||
case MENU_VIEW_USE_2_VIEWPORTS_ALT: {
|
||||
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_2_VIEWPORTS_ALT);
|
||||
if (last_used_viewport > 1) {
|
||||
last_used_viewport = 0;
|
||||
}
|
||||
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
|
||||
@ -6703,6 +6670,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
|
||||
} break;
|
||||
case MENU_VIEW_USE_3_VIEWPORTS: {
|
||||
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_3_VIEWPORTS);
|
||||
if (last_used_viewport > 2) {
|
||||
last_used_viewport = 0;
|
||||
}
|
||||
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
|
||||
@ -6714,6 +6684,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
|
||||
} break;
|
||||
case MENU_VIEW_USE_3_VIEWPORTS_ALT: {
|
||||
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_3_VIEWPORTS_ALT);
|
||||
if (last_used_viewport > 2) {
|
||||
last_used_viewport = 0;
|
||||
}
|
||||
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
|
||||
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
|
||||
@ -8033,7 +8006,6 @@ void Node3DEditor::_update_theme() {
|
||||
|
||||
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_button_icon(get_editor_theme_icon(SNAME("Object")));
|
||||
tool_option_button[TOOL_OPT_USE_SNAP]->set_button_icon(get_editor_theme_icon(SNAME("Snap")));
|
||||
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_button_icon(get_editor_theme_icon(SNAME("Camera3D")));
|
||||
|
||||
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_editor_theme_icon(SNAME("Panels1")));
|
||||
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_editor_theme_icon(SNAME("Panels2")));
|
||||
@ -8068,9 +8040,6 @@ void Node3DEditor::_notification(int p_what) {
|
||||
SceneTreeDock::get_singleton()->get_tree_editor()->connect("node_changed", callable_mp(this, &Node3DEditor::_refresh_menu_icons));
|
||||
editor_selection->connect("selection_changed", callable_mp(this, &Node3DEditor::_selection_changed));
|
||||
|
||||
EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button).bind(false));
|
||||
EditorRunBar::get_singleton()->connect("play_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button).bind(true));
|
||||
|
||||
_update_preview_environment();
|
||||
|
||||
sun_state->set_custom_minimum_size(sun_vb->get_combined_minimum_size());
|
||||
@ -8106,15 +8075,6 @@ void Node3DEditor::_notification(int p_what) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) {
|
||||
EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
|
||||
|
||||
debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
|
||||
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_PHYSICS_PROCESS: {
|
||||
if (do_snap_selected_nodes_to_floor) {
|
||||
_snap_selected_nodes_to_floor();
|
||||
@ -8216,6 +8176,10 @@ VSplitContainer *Node3DEditor::get_shader_split() {
|
||||
return shader_split;
|
||||
}
|
||||
|
||||
Node3DEditorViewport *Node3DEditor::get_last_used_viewport() {
|
||||
return viewports[last_used_viewport];
|
||||
}
|
||||
|
||||
void Node3DEditor::add_control_to_left_panel(Control *p_control) {
|
||||
left_panel_split->add_child(p_control);
|
||||
left_panel_split->move_child(p_control, 0);
|
||||
@ -8393,6 +8357,10 @@ void Node3DEditor::_toggle_maximize_view(Object *p_viewport) {
|
||||
}
|
||||
}
|
||||
|
||||
void Node3DEditor::_viewport_clicked(int p_viewport_idx) {
|
||||
last_used_viewport = p_viewport_idx;
|
||||
}
|
||||
|
||||
void Node3DEditor::_node_added(Node *p_node) {
|
||||
if (EditorNode::get_singleton()->get_scene_root()->is_ancestor_of(p_node)) {
|
||||
if (Object::cast_to<WorldEnvironment>(p_node)) {
|
||||
@ -8684,8 +8652,6 @@ Node3DEditor::Node3DEditor() {
|
||||
snap_key_enabled = false;
|
||||
tool_mode = TOOL_MODE_SELECT;
|
||||
|
||||
camera_override_viewport_id = 0;
|
||||
|
||||
// Add some margin to the sides for better aesthetics.
|
||||
// This prevents the first button's hover/pressed effect from "touching" the panel's border,
|
||||
// which looks ugly.
|
||||
@ -8802,16 +8768,6 @@ Node3DEditor::Node3DEditor() {
|
||||
tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), Key::Y));
|
||||
tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut_context(this);
|
||||
|
||||
main_menu_hbox->add_child(memnew(VSeparator));
|
||||
|
||||
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(Button);
|
||||
main_menu_hbox->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
|
||||
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true);
|
||||
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_theme_type_variation("FlatButton");
|
||||
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true);
|
||||
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect(SceneStringName(toggled), callable_mp(this, &Node3DEditor::_menu_item_toggled).bind(MENU_TOOL_OVERRIDE_CAMERA));
|
||||
_update_camera_override_button(false);
|
||||
|
||||
main_menu_hbox->add_child(memnew(VSeparator));
|
||||
sun_button = memnew(Button);
|
||||
sun_button->set_tooltip_text(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled."));
|
||||
@ -8955,7 +8911,7 @@ Node3DEditor::Node3DEditor() {
|
||||
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
|
||||
viewports[i] = memnew(Node3DEditorViewport(this, i));
|
||||
viewports[i]->connect("toggle_maximize_view", callable_mp(this, &Node3DEditor::_toggle_maximize_view));
|
||||
viewports[i]->connect("clicked", callable_mp(this, &Node3DEditor::_update_camera_override_viewport));
|
||||
viewports[i]->connect("clicked", callable_mp(this, &Node3DEditor::_viewport_clicked).bind(i));
|
||||
viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
|
||||
viewport_base->add_child(viewports[i]);
|
||||
}
|
||||
|
@ -622,7 +622,6 @@ public:
|
||||
enum ToolOptions {
|
||||
TOOL_OPT_LOCAL_COORDS,
|
||||
TOOL_OPT_USE_SNAP,
|
||||
TOOL_OPT_OVERRIDE_CAMERA,
|
||||
TOOL_OPT_MAX
|
||||
|
||||
};
|
||||
@ -632,6 +631,8 @@ private:
|
||||
|
||||
Node3DEditorViewportContainer *viewport_base = nullptr;
|
||||
Node3DEditorViewport *viewports[VIEWPORTS_COUNT];
|
||||
int last_used_viewport = 0;
|
||||
|
||||
VSplitContainer *shader_split = nullptr;
|
||||
HSplitContainer *left_panel_split = nullptr;
|
||||
HSplitContainer *right_panel_split = nullptr;
|
||||
@ -704,7 +705,6 @@ private:
|
||||
MENU_TOOL_LIST_SELECT,
|
||||
MENU_TOOL_LOCAL_COORDS,
|
||||
MENU_TOOL_USE_SNAP,
|
||||
MENU_TOOL_OVERRIDE_CAMERA,
|
||||
MENU_TRANSFORM_CONFIGURE_SNAP,
|
||||
MENU_TRANSFORM_DIALOG,
|
||||
MENU_VIEW_USE_1_VIEWPORT,
|
||||
@ -759,8 +759,6 @@ private:
|
||||
void _menu_item_pressed(int p_option);
|
||||
void _menu_item_toggled(bool pressed, int p_option);
|
||||
void _menu_gizmo_toggled(int p_option);
|
||||
void _update_camera_override_button(bool p_game_running);
|
||||
void _update_camera_override_viewport(Object *p_viewport);
|
||||
// Used for secondary menu items which are displayed depending on the currently selected node
|
||||
// (such as MeshInstance's "Mesh" menu).
|
||||
PanelContainer *context_toolbar_panel = nullptr;
|
||||
@ -771,8 +769,6 @@ private:
|
||||
|
||||
void _generate_selection_boxes();
|
||||
|
||||
int camera_override_viewport_id;
|
||||
|
||||
void _init_indicators();
|
||||
void _update_gizmos_menu();
|
||||
void _update_gizmos_menu_theme();
|
||||
@ -781,6 +777,7 @@ private:
|
||||
void _finish_grid();
|
||||
|
||||
void _toggle_maximize_view(Object *p_viewport);
|
||||
void _viewport_clicked(int p_viewport_idx);
|
||||
|
||||
Node *custom_camera = nullptr;
|
||||
|
||||
@ -967,6 +964,7 @@ public:
|
||||
ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), nullptr);
|
||||
return viewports[p_idx];
|
||||
}
|
||||
Node3DEditorViewport *get_last_used_viewport();
|
||||
|
||||
void add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
|
||||
void remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
|
||||
|
@ -1857,6 +1857,12 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
|
||||
p_theme->set_stylebox("ScriptEditorPanelFloating", EditorStringName(EditorStyles), make_empty_stylebox(0, 0, 0, 0));
|
||||
p_theme->set_stylebox("ScriptEditor", EditorStringName(EditorStyles), make_empty_stylebox(0, 0, 0, 0));
|
||||
|
||||
// Game view.
|
||||
p_theme->set_type_variation("GamePanel", "Panel");
|
||||
Ref<StyleBoxFlat> game_panel = p_theme->get_stylebox(SNAME("panel"), SNAME("Panel"))->duplicate();
|
||||
game_panel->set_corner_radius_all(0);
|
||||
p_theme->set_stylebox(SceneStringName(panel), "GamePanel", game_panel);
|
||||
|
||||
// Main menu.
|
||||
Ref<StyleBoxFlat> menu_transparent_style = p_config.button_style->duplicate();
|
||||
menu_transparent_style->set_bg_color(Color(1, 1, 1, 0));
|
||||
|
@ -7,7 +7,6 @@ should instead be used to justify these changes and describe how users should wo
|
||||
Add new entries at the end of the file.
|
||||
|
||||
## Changes between 4.3-stable and 4.4-stable
|
||||
|
||||
GH-95374
|
||||
--------
|
||||
Validate extension JSON: Error: Field 'classes/ShapeCast2D/properties/collision_result': getter changed value in new API, from "_get_collision_result" to &"get_collision_result".
|
||||
@ -102,3 +101,10 @@ GH-97020
|
||||
Validate extension JSON: Error: Field 'classes/AnimationNode/methods/_process': is_const changed value in new API, from true to false.
|
||||
|
||||
`_process` virtual method fixed to be non const instead.
|
||||
|
||||
|
||||
GH-97257
|
||||
--------
|
||||
Validate extension JSON: Error: Field 'classes/EditorFeatureProfile/enums/Feature/values/FEATURE_MAX': value changed value in new API, from 8.0 to 9.
|
||||
|
||||
New entry to the `EditorFeatureProfile.Feature` enum added. Those need to go before `FEATURE_MAX`, which will always cause a compatibility break.
|
||||
|
@ -302,6 +302,7 @@ void Camera2D::_notification(int p_what) {
|
||||
_interpolation_data.xform_prev = _interpolation_data.xform_curr;
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (is_physics_interpolated_and_enabled()) {
|
||||
_update_scroll();
|
||||
|
@ -696,6 +696,8 @@ void GPUParticles2D::_notification(int p_what) {
|
||||
RS::get_singleton()->particles_set_subemitter(particles, RID());
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_UNSUSPENDED:
|
||||
case NOTIFICATION_PAUSED:
|
||||
case NOTIFICATION_UNPAUSED: {
|
||||
if (is_inside_tree()) {
|
||||
|
@ -253,12 +253,20 @@ void NavigationAgent2D::_notification(int p_what) {
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (agent_parent) {
|
||||
NavigationServer2D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_UNSUSPENDED: {
|
||||
if (get_tree()->is_paused()) {
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case NOTIFICATION_UNPAUSED: {
|
||||
if (agent_parent) {
|
||||
NavigationServer2D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
|
||||
|
@ -104,6 +104,7 @@ void NavigationObstacle2D::_notification(int p_what) {
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (!can_process()) {
|
||||
map_before_pause = map_current;
|
||||
@ -115,6 +116,13 @@ void NavigationObstacle2D::_notification(int p_what) {
|
||||
NavigationServer2D::get_singleton()->obstacle_set_paused(obstacle, !can_process());
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_UNSUSPENDED: {
|
||||
if (get_tree()->is_paused()) {
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case NOTIFICATION_UNPAUSED: {
|
||||
if (!can_process()) {
|
||||
map_before_pause = map_current;
|
||||
|
@ -185,6 +185,7 @@ void TouchScreenButton::_notification(int p_what) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (is_pressed()) {
|
||||
_release();
|
||||
|
@ -234,6 +234,7 @@ void Camera3D::_notification(int p_what) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (is_physics_interpolated_and_enabled() && is_inside_tree() && is_visible_in_tree()) {
|
||||
_physics_interpolation_ensure_transform_calculated(true);
|
||||
|
@ -511,6 +511,8 @@ void GPUParticles3D::_notification(int p_what) {
|
||||
RS::get_singleton()->particles_set_subemitter(particles, RID());
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_UNSUSPENDED:
|
||||
case NOTIFICATION_PAUSED:
|
||||
case NOTIFICATION_UNPAUSED: {
|
||||
if (is_inside_tree()) {
|
||||
|
@ -272,12 +272,20 @@ void NavigationAgent3D::_notification(int p_what) {
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (agent_parent) {
|
||||
NavigationServer3D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_UNSUSPENDED: {
|
||||
if (get_tree()->is_paused()) {
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case NOTIFICATION_UNPAUSED: {
|
||||
if (agent_parent) {
|
||||
NavigationServer3D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
|
||||
|
@ -119,6 +119,7 @@ void NavigationObstacle3D::_notification(int p_what) {
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (!can_process()) {
|
||||
map_before_pause = map_current;
|
||||
@ -130,6 +131,13 @@ void NavigationObstacle3D::_notification(int p_what) {
|
||||
NavigationServer3D::get_singleton()->obstacle_set_paused(obstacle, !can_process());
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_UNSUSPENDED: {
|
||||
if (get_tree()->is_paused()) {
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case NOTIFICATION_UNPAUSED: {
|
||||
if (!can_process()) {
|
||||
map_before_pause = map_current;
|
||||
|
@ -112,6 +112,7 @@ void AudioStreamPlayerInternal::notification(int p_what) {
|
||||
stream_playbacks.clear();
|
||||
} break;
|
||||
|
||||
case Node::NOTIFICATION_SUSPENDED:
|
||||
case Node::NOTIFICATION_PAUSED: {
|
||||
if (!node->can_process()) {
|
||||
// Node can't process so we start fading out to silence
|
||||
@ -119,6 +120,13 @@ void AudioStreamPlayerInternal::notification(int p_what) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case Node::NOTIFICATION_UNSUSPENDED: {
|
||||
if (node->get_tree()->is_paused()) {
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case Node::NOTIFICATION_UNPAUSED: {
|
||||
set_stream_paused(false);
|
||||
} break;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,19 +31,21 @@
|
||||
#ifndef SCENE_DEBUGGER_H
|
||||
#define SCENE_DEBUGGER_H
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/input/shortcut.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/pair.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "scene/gui/view_panner.h"
|
||||
#include "scene/resources/mesh.h"
|
||||
|
||||
class PopupMenu;
|
||||
class Script;
|
||||
class Node;
|
||||
|
||||
class SceneDebugger {
|
||||
public:
|
||||
private:
|
||||
static SceneDebugger *singleton;
|
||||
inline static SceneDebugger *singleton = nullptr;
|
||||
|
||||
SceneDebugger();
|
||||
|
||||
@ -59,6 +61,7 @@ private:
|
||||
static void _set_node_owner_recursive(Node *p_node, Node *p_owner);
|
||||
static void _set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value);
|
||||
static void _send_object_id(ObjectID p_id, int p_max_size = 1 << 20);
|
||||
static void _next_frame();
|
||||
|
||||
public:
|
||||
static Error parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured);
|
||||
@ -160,11 +163,161 @@ private:
|
||||
live_edit_root = NodePath("/root");
|
||||
}
|
||||
|
||||
static LiveEditor *singleton;
|
||||
inline static LiveEditor *singleton = nullptr;
|
||||
|
||||
public:
|
||||
static LiveEditor *get_singleton();
|
||||
};
|
||||
|
||||
class RuntimeNodeSelect : public Object {
|
||||
GDCLASS(RuntimeNodeSelect, Object);
|
||||
|
||||
public:
|
||||
enum NodeType {
|
||||
NODE_TYPE_NONE,
|
||||
NODE_TYPE_2D,
|
||||
NODE_TYPE_3D,
|
||||
NODE_TYPE_MAX
|
||||
};
|
||||
|
||||
enum SelectMode {
|
||||
SELECT_MODE_SINGLE,
|
||||
SELECT_MODE_LIST,
|
||||
SELECT_MODE_MAX
|
||||
};
|
||||
|
||||
private:
|
||||
friend class SceneDebugger;
|
||||
|
||||
struct SelectResult {
|
||||
Node *item = nullptr;
|
||||
real_t order = 0;
|
||||
_FORCE_INLINE_ bool operator<(const SelectResult &p_rr) const { return p_rr.order < order; }
|
||||
};
|
||||
|
||||
bool has_selection = false;
|
||||
Node *selected_node = nullptr;
|
||||
PopupMenu *selection_list = nullptr;
|
||||
bool selection_visible = true;
|
||||
bool selection_update_queued = false;
|
||||
|
||||
bool camera_override = false;
|
||||
|
||||
// Values taken from EditorZoomWidget.
|
||||
const float VIEW_2D_MIN_ZOOM = 1.0 / 128;
|
||||
const float VIEW_2D_MAX_ZOOM = 128;
|
||||
|
||||
Ref<ViewPanner> panner;
|
||||
Vector2 view_2d_offset;
|
||||
real_t view_2d_zoom = 1.0;
|
||||
|
||||
RID sbox_2d_canvas;
|
||||
RID sbox_2d_ci;
|
||||
Transform2D sbox_2d_xform;
|
||||
Rect2 sbox_2d_rect;
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
struct Cursor {
|
||||
Vector3 pos;
|
||||
real_t x_rot, y_rot, distance, fov_scale;
|
||||
Vector3 eye_pos; // Used in freelook mode.
|
||||
|
||||
Cursor() {
|
||||
// These rotations place the camera in +X +Y +Z, aka south east, facing north west.
|
||||
x_rot = 0.5;
|
||||
y_rot = -0.5;
|
||||
distance = 4;
|
||||
fov_scale = 1.0;
|
||||
}
|
||||
};
|
||||
Cursor cursor;
|
||||
|
||||
// Values taken from Node3DEditor.
|
||||
const float VIEW_3D_MIN_ZOOM = 0.01;
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
const double VIEW_3D_MAX_ZOOM = 1'000'000'000'000;
|
||||
#else
|
||||
const float VIEW_3D_MAX_ZOOM = 10'000;
|
||||
#endif
|
||||
const float CAMERA_ZNEAR = 0.05;
|
||||
const float CAMERA_ZFAR = 4'000;
|
||||
|
||||
const float CAMERA_BASE_FOV = 75;
|
||||
const float CAMERA_MIN_FOV_SCALE = 0.1;
|
||||
const float CAMERA_MAX_FOV_SCALE = 2.5;
|
||||
|
||||
const float FREELOOK_BASE_SPEED = 4;
|
||||
const float RADS_PER_PIXEL = 0.004;
|
||||
|
||||
bool camera_first_override = true;
|
||||
bool camera_freelook = false;
|
||||
|
||||
Vector2 previous_mouse_position;
|
||||
|
||||
Ref<ArrayMesh> sbox_3d_mesh;
|
||||
Ref<ArrayMesh> sbox_3d_mesh_xray;
|
||||
RID sbox_3d_instance;
|
||||
RID sbox_3d_instance_ofs;
|
||||
RID sbox_3d_instance_xray;
|
||||
RID sbox_3d_instance_xray_ofs;
|
||||
Transform3D sbox_3d_xform;
|
||||
AABB sbox_3d_bounds;
|
||||
#endif
|
||||
|
||||
Point2 selection_position = Point2(INFINITY, INFINITY);
|
||||
bool list_shortcut_pressed = false;
|
||||
|
||||
NodeType node_select_type = NODE_TYPE_2D;
|
||||
SelectMode node_select_mode = SELECT_MODE_SINGLE;
|
||||
|
||||
void _setup();
|
||||
|
||||
void _node_set_type(NodeType p_type);
|
||||
void _select_set_mode(SelectMode p_mode);
|
||||
|
||||
void _set_camera_override_enabled(bool p_enabled);
|
||||
|
||||
void _root_window_input(const Ref<InputEvent> &p_event);
|
||||
void _items_popup_index_pressed(int p_index, PopupMenu *p_popup);
|
||||
void _update_input_state();
|
||||
|
||||
void _process_frame();
|
||||
void _physics_frame();
|
||||
|
||||
void _click_point();
|
||||
void _select_node(Node *p_node);
|
||||
void _queue_selection_update();
|
||||
void _update_selection();
|
||||
void _clear_selection();
|
||||
void _set_selection_visible(bool p_visible);
|
||||
|
||||
void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
|
||||
void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
|
||||
void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
|
||||
void _reset_camera_2d();
|
||||
void _update_view_2d();
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
void _find_3d_items_at_pos(const Point2 &p_pos, Vector<SelectResult> &r_items);
|
||||
bool _handle_3d_input(const Ref<InputEvent> &p_event);
|
||||
void _set_camera_freelook_enabled(bool p_enabled);
|
||||
void _cursor_scale_distance(real_t p_scale);
|
||||
void _cursor_look(Ref<InputEventWithModifiers> p_event);
|
||||
void _cursor_pan(Ref<InputEventWithModifiers> p_event);
|
||||
void _cursor_orbit(Ref<InputEventWithModifiers> p_event);
|
||||
Transform3D _get_cursor_transform();
|
||||
void _reset_camera_3d();
|
||||
#endif
|
||||
|
||||
RuntimeNodeSelect() { singleton = this; }
|
||||
|
||||
inline static RuntimeNodeSelect *singleton = nullptr;
|
||||
|
||||
public:
|
||||
static RuntimeNodeSelect *get_singleton();
|
||||
|
||||
~RuntimeNodeSelect();
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // SCENE_DEBUGGER_H
|
||||
|
@ -178,6 +178,7 @@ void VideoStreamPlayer::_notification(int p_notification) {
|
||||
draw_texture_rect(texture, Rect2(Point2(), s), false);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (is_playing() && !is_paused()) {
|
||||
paused_from_tree = true;
|
||||
@ -189,6 +190,13 @@ void VideoStreamPlayer::_notification(int p_notification) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_UNSUSPENDED: {
|
||||
if (get_tree()->is_paused()) {
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case NOTIFICATION_UNPAUSED: {
|
||||
if (paused_from_tree) {
|
||||
paused_from_tree = false;
|
||||
|
@ -184,6 +184,7 @@ void Node::_notification(int p_notification) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_SUSPENDED:
|
||||
case NOTIFICATION_PAUSED: {
|
||||
if (is_physics_interpolated_and_enabled() && is_inside_tree()) {
|
||||
reset_physics_interpolation();
|
||||
@ -695,6 +696,16 @@ void Node::_propagate_pause_notification(bool p_enable) {
|
||||
data.blocked--;
|
||||
}
|
||||
|
||||
void Node::_propagate_suspend_notification(bool p_enable) {
|
||||
notification(p_enable ? NOTIFICATION_SUSPENDED : NOTIFICATION_UNSUSPENDED);
|
||||
|
||||
data.blocked++;
|
||||
for (KeyValue<StringName, Node *> &KV : data.children) {
|
||||
KV.value->_propagate_suspend_notification(p_enable);
|
||||
}
|
||||
data.blocked--;
|
||||
}
|
||||
|
||||
Node::ProcessMode Node::get_process_mode() const {
|
||||
return data.process_mode;
|
||||
}
|
||||
@ -850,7 +861,7 @@ bool Node::can_process_notification(int p_what) const {
|
||||
|
||||
bool Node::can_process() const {
|
||||
ERR_FAIL_COND_V(!is_inside_tree(), false);
|
||||
return _can_process(get_tree()->is_paused());
|
||||
return !get_tree()->is_suspended() && _can_process(get_tree()->is_paused());
|
||||
}
|
||||
|
||||
bool Node::_can_process(bool p_paused) const {
|
||||
|
@ -300,6 +300,7 @@ private:
|
||||
|
||||
void _set_tree(SceneTree *p_tree);
|
||||
void _propagate_pause_notification(bool p_enable);
|
||||
void _propagate_suspend_notification(bool p_enable);
|
||||
|
||||
_FORCE_INLINE_ bool _can_process(bool p_paused) const;
|
||||
_FORCE_INLINE_ bool _is_enabled() const;
|
||||
@ -439,6 +440,8 @@ public:
|
||||
// Editor specific node notifications
|
||||
NOTIFICATION_EDITOR_PRE_SAVE = 9001,
|
||||
NOTIFICATION_EDITOR_POST_SAVE = 9002,
|
||||
NOTIFICATION_SUSPENDED = 9003,
|
||||
NOTIFICATION_UNSUSPENDED = 9004
|
||||
};
|
||||
|
||||
/* NODE/TREE */
|
||||
|
@ -954,11 +954,14 @@ Ref<ArrayMesh> SceneTree::get_debug_contact_mesh() {
|
||||
|
||||
void SceneTree::set_pause(bool p_enabled) {
|
||||
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Pause can only be set from the main thread.");
|
||||
ERR_FAIL_COND_MSG(suspended, "Pause state cannot be modified while suspended.");
|
||||
|
||||
if (p_enabled == paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
paused = p_enabled;
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
PhysicsServer3D::get_singleton()->set_active(!p_enabled);
|
||||
#endif // _3D_DISABLED
|
||||
@ -972,6 +975,30 @@ bool SceneTree::is_paused() const {
|
||||
return paused;
|
||||
}
|
||||
|
||||
void SceneTree::set_suspend(bool p_enabled) {
|
||||
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Suspend can only be set from the main thread.");
|
||||
|
||||
if (p_enabled == suspended) {
|
||||
return;
|
||||
}
|
||||
|
||||
suspended = p_enabled;
|
||||
|
||||
Engine::get_singleton()->set_freeze_time_scale(p_enabled);
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
PhysicsServer3D::get_singleton()->set_active(!p_enabled && !paused);
|
||||
#endif // _3D_DISABLED
|
||||
PhysicsServer2D::get_singleton()->set_active(!p_enabled && !paused);
|
||||
if (get_root()) {
|
||||
get_root()->_propagate_suspend_notification(p_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
bool SceneTree::is_suspended() const {
|
||||
return suspended;
|
||||
}
|
||||
|
||||
void SceneTree::_process_group(ProcessGroup *p_group, bool p_physics) {
|
||||
// When reading this function, keep in mind that this code must work in a way where
|
||||
// if any node is removed, this needs to continue working.
|
||||
|
@ -143,6 +143,7 @@ private:
|
||||
bool debug_navigation_hint = false;
|
||||
#endif
|
||||
bool paused = false;
|
||||
bool suspended = false;
|
||||
|
||||
HashMap<StringName, Group> group_map;
|
||||
bool _quit = false;
|
||||
@ -343,6 +344,8 @@ public:
|
||||
|
||||
void set_pause(bool p_enabled);
|
||||
bool is_paused() const;
|
||||
void set_suspend(bool p_enabled);
|
||||
bool is_suspended() const;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void set_debug_collisions_hint(bool p_enabled);
|
||||
|
@ -3123,7 +3123,7 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
|
||||
ERR_FAIL_COND(!is_inside_tree());
|
||||
ERR_FAIL_COND(p_event.is_null());
|
||||
|
||||
if (disable_input) {
|
||||
if (disable_input || disable_input_override) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3195,7 +3195,7 @@ void Viewport::push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local
|
||||
|
||||
local_input_handled = false;
|
||||
|
||||
if (disable_input || !_can_consume_input_events()) {
|
||||
if (disable_input || disable_input_override || !_can_consume_input_events()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3298,7 +3298,7 @@ void Viewport::set_disable_input(bool p_disable) {
|
||||
if (p_disable == disable_input) {
|
||||
return;
|
||||
}
|
||||
if (p_disable) {
|
||||
if (p_disable && !disable_input_override) {
|
||||
_drop_mouse_focus();
|
||||
_mouse_leave_viewport();
|
||||
_gui_cancel_tooltip();
|
||||
@ -3311,6 +3311,19 @@ bool Viewport::is_input_disabled() const {
|
||||
return disable_input;
|
||||
}
|
||||
|
||||
void Viewport::set_disable_input_override(bool p_disable) {
|
||||
ERR_MAIN_THREAD_GUARD;
|
||||
if (p_disable == disable_input_override) {
|
||||
return;
|
||||
}
|
||||
if (p_disable && !disable_input) {
|
||||
_drop_mouse_focus();
|
||||
_mouse_leave_viewport();
|
||||
_gui_cancel_tooltip();
|
||||
}
|
||||
disable_input_override = p_disable;
|
||||
}
|
||||
|
||||
Variant Viewport::gui_get_drag_data() const {
|
||||
ERR_READ_THREAD_GUARD_V(Variant());
|
||||
return get_section_root_viewport()->gui.drag_data;
|
||||
@ -4237,6 +4250,22 @@ void Viewport::set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near,
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<StringName, real_t> Viewport::get_camera_3d_override_properties() const {
|
||||
HashMap<StringName, real_t> props;
|
||||
|
||||
props["size"] = 0;
|
||||
props["fov"] = 0;
|
||||
props["z_near"] = 0;
|
||||
props["z_far"] = 0;
|
||||
ERR_READ_THREAD_GUARD_V(props);
|
||||
|
||||
props["size"] = camera_3d_override.size;
|
||||
props["fov"] = camera_3d_override.fov;
|
||||
props["z_near"] = camera_3d_override.z_near;
|
||||
props["z_far"] = camera_3d_override.z_far;
|
||||
return props;
|
||||
}
|
||||
|
||||
void Viewport::set_disable_3d(bool p_disable) {
|
||||
ERR_MAIN_THREAD_GUARD;
|
||||
disable_3d = p_disable;
|
||||
@ -4270,6 +4299,54 @@ Transform3D Viewport::get_camera_3d_override_transform() const {
|
||||
return Transform3D();
|
||||
}
|
||||
|
||||
Vector3 Viewport::camera_3d_override_project_ray_normal(const Point2 &p_pos) const {
|
||||
ERR_READ_THREAD_GUARD_V(Vector3());
|
||||
Vector3 ray = camera_3d_override_project_local_ray_normal(p_pos);
|
||||
return camera_3d_override.transform.basis.xform(ray).normalized();
|
||||
}
|
||||
|
||||
Vector3 Viewport::camera_3d_override_project_local_ray_normal(const Point2 &p_pos) const {
|
||||
ERR_READ_THREAD_GUARD_V(Vector3());
|
||||
Size2 viewport_size = get_camera_rect_size();
|
||||
Vector2 cpos = get_camera_coords(p_pos);
|
||||
Vector3 ray;
|
||||
|
||||
if (camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) {
|
||||
ray = Vector3(0, 0, -1);
|
||||
} else {
|
||||
Projection cm;
|
||||
cm.set_perspective(camera_3d_override.fov, get_visible_rect().size.aspect(), camera_3d_override.z_near, camera_3d_override.z_far, false);
|
||||
|
||||
Vector2 screen_he = cm.get_viewport_half_extents();
|
||||
ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -camera_3d_override.z_near).normalized();
|
||||
}
|
||||
|
||||
return ray;
|
||||
}
|
||||
|
||||
Vector3 Viewport::camera_3d_override_project_ray_origin(const Point2 &p_pos) const {
|
||||
ERR_READ_THREAD_GUARD_V(Vector3());
|
||||
Size2 viewport_size = get_camera_rect_size();
|
||||
Vector2 cpos = get_camera_coords(p_pos);
|
||||
ERR_FAIL_COND_V(viewport_size.y == 0, Vector3());
|
||||
|
||||
if (camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) {
|
||||
Vector2 pos = cpos / viewport_size;
|
||||
real_t vsize, hsize;
|
||||
hsize = camera_3d_override.size * viewport_size.aspect();
|
||||
vsize = camera_3d_override.size;
|
||||
|
||||
Vector3 ray;
|
||||
ray.x = pos.x * (hsize)-hsize / 2;
|
||||
ray.y = (1.0 - pos.y) * (vsize)-vsize / 2;
|
||||
ray.z = -camera_3d_override.z_near;
|
||||
ray = camera_3d_override.transform.xform(ray);
|
||||
return ray;
|
||||
} else {
|
||||
return camera_3d_override.transform.origin;
|
||||
};
|
||||
}
|
||||
|
||||
Ref<World3D> Viewport::get_world_3d() const {
|
||||
ERR_READ_THREAD_GUARD_V(Ref<World3D>());
|
||||
return world_3d;
|
||||
|
@ -401,6 +401,7 @@ private:
|
||||
DefaultCanvasItemTextureRepeat default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
|
||||
|
||||
bool disable_input = false;
|
||||
bool disable_input_override = false;
|
||||
|
||||
void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input);
|
||||
void _gui_call_notification(Control *p_control, int p_what);
|
||||
@ -580,6 +581,8 @@ public:
|
||||
void set_disable_input(bool p_disable);
|
||||
bool is_input_disabled() const;
|
||||
|
||||
void set_disable_input_override(bool p_disable);
|
||||
|
||||
Vector2 get_mouse_position() const;
|
||||
void warp_mouse(const Vector2 &p_position);
|
||||
virtual void update_mouse_cursor_state();
|
||||
@ -770,6 +773,11 @@ public:
|
||||
|
||||
void set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far);
|
||||
void set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far);
|
||||
HashMap<StringName, real_t> get_camera_3d_override_properties() const;
|
||||
|
||||
Vector3 camera_3d_override_project_ray_normal(const Point2 &p_pos) const;
|
||||
Vector3 camera_3d_override_project_ray_origin(const Point2 &p_pos) const;
|
||||
Vector3 camera_3d_override_project_local_ray_normal(const Point2 &p_pos) const;
|
||||
|
||||
void set_disable_3d(bool p_disable);
|
||||
bool is_3d_disabled() const;
|
||||
|
Loading…
Reference in New Issue
Block a user