From 4db0f51b9aa76cfc7649787fe1970af606ce8dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Sun, 24 Feb 2019 21:44:00 +0100 Subject: Create live view dock [wip] --- editor/editor_node.cpp | 26 ++++-- editor/editor_node.h | 3 + editor/live_view.cpp | 170 ++++++++++++++++++++++++++++++++++++++ editor/live_view.h | 62 ++++++++++++++ editor/script_editor_debugger.cpp | 14 ++++ editor/script_editor_debugger.h | 2 + 6 files changed, 272 insertions(+), 5 deletions(-) create mode 100644 editor/live_view.cpp create mode 100644 editor/live_view.h (limited to 'editor') diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 6140412a32..1ce45c93f1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -56,6 +56,7 @@ #include "editor/editor_properties.h" #include "editor/editor_settings.h" #include "editor/editor_themes.h" +#include "editor/live_view.h" #include "editor/import/editor_import_collada.h" #include "editor/import/editor_scene_importer_gltf.h" #include "editor/import/resource_importer_bitmask.h" @@ -1808,6 +1809,8 @@ void EditorNode::_run(bool p_current, const String &p_custom) { return; } + live_view_dock->start(); + emit_signal("play_pressed"); if (p_current) { play_scene_button->set_pressed(true); @@ -2149,6 +2152,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { break; editor_run.stop(); + live_view_dock->stop(); run_custom_filename.clear(); play_button->set_pressed(false); play_button->set_icon(gui_base->get_icon("MainPlay", "EditorIcons")); @@ -3125,6 +3129,10 @@ InspectorDock *EditorNode::get_inspector_dock() { return inspector_dock; } +LiveViewDock *EditorNode::get_live_view_dock() { + + return live_view_dock; +} void EditorNode::_instance_request(const Vector &p_files) { @@ -3217,6 +3225,7 @@ void EditorNode::notify_child_process_exited() { _menu_option_confirm(RUN_STOP, false); stop_button->set_pressed(false); editor_run.stop(); + live_view_dock->stop(); } void EditorNode::add_io_error(const String &p_error) { @@ -5690,6 +5699,7 @@ EditorNode::EditorNode() { scene_tree_dock = memnew(SceneTreeDock(this, scene_root, editor_selection, editor_data)); inspector_dock = memnew(InspectorDock(this, editor_data)); + live_view_dock = memnew(LiveViewDock); import_dock = memnew(ImportDock); node_dock = memnew(NodeDock); @@ -5710,18 +5720,21 @@ EditorNode::EditorNode() { dock_slot[DOCK_SLOT_LEFT_BR]->add_child(filesystem_dock); dock_slot[DOCK_SLOT_LEFT_BR]->set_tab_title(filesystem_dock->get_index(), TTR("FileSystem")); - // Inspector: Full height right + // Inspector: Right dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(inspector_dock); dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(inspector_dock->get_index(), TTR("Inspector")); - // Node: Full height right, behind Inspector + // Node: Right, behind Inspector dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(node_dock); dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(node_dock->get_index(), TTR("Node")); + // Game preview: Bottom right + dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(live_view_dock); + dock_slot[DOCK_SLOT_RIGHT_BL]->set_tab_title(live_view_dock->get_index(), TTR("LiveView")); + // Hide unused dock slots and vsplits dock_slot[DOCK_SLOT_LEFT_UL]->hide(); dock_slot[DOCK_SLOT_LEFT_BL]->hide(); - dock_slot[DOCK_SLOT_RIGHT_BL]->hide(); dock_slot[DOCK_SLOT_RIGHT_UR]->hide(); dock_slot[DOCK_SLOT_RIGHT_BR]->hide(); left_l_vsplit->hide(); @@ -5740,9 +5753,12 @@ EditorNode::EditorNode() { default_layout->set_value(docks_section, "dock_3", "Scene,Import"); default_layout->set_value(docks_section, "dock_4", "FileSystem"); default_layout->set_value(docks_section, "dock_5", "Inspector,Node"); + default_layout->set_value(docks_section, "dock_6", "LiveView"); - for (int i = 0; i < vsplits.size(); i++) - default_layout->set_value(docks_section, "dock_split_" + itos(i + 1), 0); + default_layout->set_value(docks_section, "dock_split_1", 0); + default_layout->set_value(docks_section, "dock_split_2", 0); + default_layout->set_value(docks_section, "dock_split_3", 160 * EDSCALE); + default_layout->set_value(docks_section, "dock_split_4", 0); default_layout->set_value(docks_section, "dock_hsplit_1", 0); default_layout->set_value(docks_section, "dock_hsplit_2", 70 * EDSCALE); default_layout->set_value(docks_section, "dock_hsplit_3", -70 * EDSCALE); diff --git a/editor/editor_node.h b/editor/editor_node.h index 267c70c773..3fcf20d796 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -94,6 +94,7 @@ typedef void (*EditorPluginInitializeCallback)(); typedef bool (*EditorBuildCallback)(); class EditorPluginList; +class LiveViewDock; class EditorNode : public Node { @@ -271,6 +272,7 @@ private: PopupMenu *recent_scenes; SceneTreeDock *scene_tree_dock; InspectorDock *inspector_dock; + LiveViewDock *live_view_dock; NodeDock *node_dock; ImportDock *import_dock; FileSystemDock *filesystem_dock; @@ -713,6 +715,7 @@ public: ImportDock *get_import_dock(); SceneTreeDock *get_scene_tree_dock(); InspectorDock *get_inspector_dock(); + LiveViewDock *get_live_view_dock(); static UndoRedo *get_undo_redo() { return &singleton->editor_data.get_undo_redo(); } EditorSelection *get_editor_selection() { return editor_selection; } diff --git a/editor/live_view.cpp b/editor/live_view.cpp new file mode 100644 index 0000000000..951d7dd5b6 --- /dev/null +++ b/editor/live_view.cpp @@ -0,0 +1,170 @@ +/*************************************************************************/ +/* live_view.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* 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 "editor/live_view.h" +#include "core/os/shared_mem_access.h" +#include "editor/script_editor_debugger.h" +#include "scene/main/scene_tree.h" +#include "scene/main/viewport.h" + +void LiveViewDock::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_PROCESS: { + + if (!is_visible_in_tree()) { + waiting = false; + break; + } + if (waiting) { + break; + } + + ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); + if (sed) { + Array msg; + msg.push_back("request_framebuffer"); + if (sed->send_message(msg)) { + waiting = true; + } + } + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + + if (!is_visible_in_tree()) { + waiting = false; + } + } break; + } +} + +void LiveViewDock::start() { + + fb_data->open + + set_process(true); + waiting = false; +} + +void LiveViewDock::stop() { + + fb_data->close(); + + set_process(false); + waiting = false; +} + +void LiveViewDock::update() { + + if (!waiting) { + return; + } + + if (!fb_data->is_open()) { + if (fb_data->open() != OK) { + return; + } + } + + const uint32_t *data = (uint32_t *)fb_data->lock(); + if (data) { + + int width = data[0]; + int height = data[1]; + Image::Format format = (Image::Format)data[2]; + + int data_size = data[3]; + PoolByteArray pixel_data; + pixel_data.resize(data_size); + { + PoolByteArray::Write w = pixel_data.write(); + memcpy(w.ptr(), &data[4], data_size); + } + + Ref img = memnew(Image); + img->create(width, height, false, format, pixel_data); + + Ref tex = get_texture(); + // Create if no texture or recreate if size or format changed + if (!tex.is_valid() || + tex->get_width() != width || + tex->get_height() != height || + tex->get_data()->get_format() != format) { + + tex = Ref(memnew(ImageTexture)); + tex->create(width, height, format, Texture::FLAG_FILTER); + set_texture(tex); + } + + tex->set_data(img); + + fb_data->unlock(); + } + + waiting = false; +} + +LiveViewDock::LiveViewDock() : + waiting(false), + fb_data(SharedMemAccess::create("godot_live_view")) { + + fb_data->open(1); + fb_data->close(); + + set_expand(true); + set_stretch_mode(STRETCH_KEEP_ASPECT_CENTERED); + + set_name("LiveView"); +} + +LiveViewDock::~LiveViewDock() { + + memdelete(fb_data); +} + +void LiveViewDebugHelper::_debugger_request_framebuffer(void *user_data) { + + Ref vp_texture = SceneTree::get_singleton()->get_root()->get_texture(); + Ref framebuffer = vp_texture->get_data(); + + SharedMemAccess *fb_data = SharedMemAccess::create("godot_live_view"); + fb_data-> + + uint32_t data_size = framebuffer->get_data().size(); + + Array result; + result.append(framebuffer->get_width()); + result.append(framebuffer->get_height()); + result.append(framebuffer->get_format()); + result.append(framebuffer->get_data().size()); + result.append(framebuffer->get_data()); + + ScriptDebugger::get_singleton()->send_message("framebuffer", result); +} diff --git a/editor/live_view.h b/editor/live_view.h new file mode 100644 index 0000000000..be0b61d087 --- /dev/null +++ b/editor/live_view.h @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* live_view.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* 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 LIVE_VIEW_H +#define LIVE_VIEW_H + +#include "scene/gui/texture_rect.h" + +class SharedMemAccess; + +class LiveViewDock : public TextureRect { + + GDCLASS(LiveViewDock, TextureRect); + + bool waiting; + SharedMemAccess *fb_data; + +protected: + void _notification(int p_what); + +public: + void start(); + void stop(); + void update(); + + LiveViewDock(); + ~LiveViewDock(); +}; + +class LiveViewDebugHelper { +public: + static void _debugger_request_framebuffer(void *user_data); +}; + +#endif // LIVE_VIEW_H diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index dda46d2414..160832305a 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -33,6 +33,7 @@ #include "core/io/marshalls.h" #include "core/project_settings.h" #include "core/ustring.h" +#include "editor/live_view.h" #include "editor_node.h" #include "editor_profiler.h" #include "editor_settings.h" @@ -459,6 +460,10 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da le_clear->set_disabled(false); le_set->set_disabled(false); + } else if (p_msg == "message:framebuffer") { + + EditorNode::get_singleton()->get_live_view_dock()->update(); + } else if (p_msg == "message:inspect_object") { ScriptEditorDebuggerInspectedObject *debugObj = NULL; @@ -1680,6 +1685,15 @@ void ScriptEditorDebugger::live_debug_reparent_node(const NodePath &p_at, const } } +bool ScriptEditorDebugger::send_message(const Array &p_message) { + + if (!connection.is_valid()) { + return false; + } + ppeer->put_var(p_message); + return true; +} + void ScriptEditorDebugger::set_breakpoint(const String &p_path, int p_line, bool p_enabled) { if (connection.is_valid()) { diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index fb1545559c..195462090c 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -230,6 +230,8 @@ public: void set_breakpoint(const String &p_path, int p_line, bool p_enabled); + bool send_message(const Array &p_message); + void update_live_edit_root(); void set_hide_on_stop(bool p_hide); -- cgit v1.2.3