Browse Source

Create live view dock [wip]

Pedro J. Estébanez 6 years ago
parent
commit
4db0f51b9a

+ 16 - 0
core/script_debugger_remote.cpp

@@ -282,6 +282,11 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue)
 				if (request_scene_tree)
 					request_scene_tree(request_scene_tree_ud);
 
+			} else if (command == "request_framebuffer") {
+
+				if (request_framebuffer)
+					request_framebuffer(request_framebuffer_ud);
+
 			} else if (command == "request_video_mem") {
 
 				_send_video_memory();
@@ -708,6 +713,10 @@ void ScriptDebuggerRemote::_poll_events() {
 
 			if (request_scene_tree)
 				request_scene_tree(request_scene_tree_ud);
+		} else if (command == "request_framebuffer") {
+
+			if (request_framebuffer)
+				request_framebuffer(request_framebuffer_ud);
 		} else if (command == "request_video_mem") {
 
 			_send_video_memory();
@@ -1009,6 +1018,12 @@ void ScriptDebuggerRemote::set_request_scene_tree_message_func(RequestSceneTreeM
 	request_scene_tree_ud = p_udata;
 }
 
+void ScriptDebuggerRemote::set_request_framebuffer_message_func(RequestFramebufferMessageFunc p_func, void *p_udata) {
+
+	request_framebuffer = p_func;
+	request_framebuffer_ud = p_udata;
+}
+
 void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) {
 
 	live_edit_funcs = p_funcs;
@@ -1079,6 +1094,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() :
 		locking(false),
 		poll_every(0),
 		request_scene_tree(NULL),
+		request_framebuffer(NULL),
 		live_edit_funcs(NULL) {
 
 	packet_peer_stream->set_stream_peer(tcp_client);

+ 5 - 0
core/script_debugger_remote.h

@@ -113,6 +113,9 @@ class ScriptDebuggerRemote : public ScriptDebugger {
 	RequestSceneTreeMessageFunc request_scene_tree;
 	void *request_scene_tree_ud;
 
+	RequestFramebufferMessageFunc request_framebuffer;
+	void *request_framebuffer_ud;
+
 	void _set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value);
 
 	void _send_object_id(ObjectID p_id);
@@ -165,6 +168,8 @@ public:
 	virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata);
 	virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs);
 
+	virtual void set_request_framebuffer_message_func(RequestFramebufferMessageFunc p_func, void *p_udata);
+
 	virtual bool is_profiling() const;
 	virtual void add_profiling_frame_data(const StringName &p_name, const Array &p_data);
 

+ 3 - 0
core/script_language.h

@@ -390,6 +390,7 @@ class ScriptDebugger {
 
 public:
 	typedef void (*RequestSceneTreeMessageFunc)(void *);
+	typedef void (*RequestFramebufferMessageFunc)(void *);
 
 	struct LiveEditFuncs {
 
@@ -445,6 +446,8 @@ public:
 	virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {}
 	virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs) {}
 
+	virtual void set_request_framebuffer_message_func(RequestFramebufferMessageFunc p_func, void *p_udata) {}
+
 	virtual bool is_profiling() const = 0;
 	virtual void add_profiling_frame_data(const StringName &p_name, const Array &p_data) = 0;
 	virtual void profiling_start() = 0;

+ 21 - 5
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<String> &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);

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

+ 170 - 0
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<Image> img = memnew(Image);
+		img->create(width, height, false, format, pixel_data);
+
+		Ref<ImageTexture> 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<ImageTexture>(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<ViewportTexture> vp_texture = SceneTree::get_singleton()->get_root()->get_texture();
+	Ref<Image> 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);
+}

+ 62 - 0
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

+ 14 - 0
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()) {

+ 2 - 0
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);

+ 5 - 0
main/main.cpp

@@ -75,6 +75,7 @@
 #include "editor/doc/doc_data_class_path.gen.h"
 #include "editor/editor_node.h"
 #include "editor/editor_settings.h"
+#include "editor/live_view.h"
 #include "editor/project_manager.h"
 #endif
 
@@ -811,6 +812,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 	}
 
 #ifdef TOOLS_ENABLED
+	if (script_debugger) {
+		script_debugger->set_request_framebuffer_message_func(LiveViewDebugHelper::_debugger_request_framebuffer, NULL);
+	}
+
 	if (editor) {
 		packed_data->set_disabled(true);
 		globals->set_disable_feature_overrides(true);