-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document Method for outputting entire Editor Window #14
Comments
Yes. Just check |
Make sure to enable |
Again, goblins in the computer.. it's finally working! |
Yes, only the Editor Viewport showing the Game is transmitted. Not the Editor Viewport showing the Editor. Perhaps a misleading name. |
You can transmit the Editor directly by injecting the NDI node in Godot to transmit the Editor himself. But it's the same as capturing the windows, you don't get the tooltips, context menu or pop-up |
Damn O: That's so cool! How did you do it? |
With this little plugin I made to test it; @tool
extends EditorPlugin
var ndi: NDIOutput
func _enter_tree() -> void:
ndi = NDIOutput.new()
ndi.name = "Godot Editor"
ndi.enable_editor_output = true
add_child(ndi)
func _exit_tree() -> void:
if is_instance_valid(ndi):
ndi.queue_free()
[plugin]
name="godot-ndi-editor"
description="Inject NDI Output node to Godot Editor"
author="Zehir"
version="1.0.0"
script="godot-ndi-editor.gd" Feel free to add this example somewhere more visible than this issue. The toolbox, popup, and other things are displayed in new windows. Maybe there is a way to inject the NDI node into them too, or have a viewport node that captures the content of another node in a transparent window to capture that and push it to an NDI Output 'popup' node. With the correct tooltip position. Most of the time the popup content is inside the area of the main windows but sometime it's overflowing. But for streaming it's still better than not displaying it at all. |
I love seeing this work because not once did it cross my mind and it just works anyway. It's like a emergent feature. Thanks for sharing in such detail. I only have the class docs right now and I'm not sure if I can add a freeform section to those. It will definitly be included once I get a docs page up and running. |
About the tooltip thingy problem the easy way to work with it it's to enable the Single Window Mode; But sadly its not compatible with the new Embed game editor. Maybe there is a way to look for all windows and create a virtual desktop of all viewports and add them on top of each other and output that to NDI. But performance may be not great |
Maybe I'm missing something but what would be the advantage over doing a Window Capture in OBS? |
I am already using NDI to get the transparency of one window; And I was hoping that the tooltip would show. I just discovered the Single Window Mode 10 minutes ago. But yes, in my case, with just the main window, there are no advantages. But you could also inject the output node into the 2D viewport to always display it, even if you opened another tab. I suppose it's working. |
Did some more testing. There are 1906 window nodes that could be shown. You could listen for the about_to_popup signal, then get the rendered texture of the Viewport, and use that texture to display it in a big viewport. Add the NDI node to that viewport. You also need to listen for added nodes because some of them, like tooltips, are instantiated only when shown. |
Did some more tests, but I think we could integrate this into your addon. So this code does these things:
There are still things that need to be improved:
About the embedded window: it consists of two windows. One of them has the buttons and is in the tree of the Godot editor, while the second one is the game window, which has no border and moves when you move the main window. So, I suppose there is a reference to that window somewhere in the tree—we may be able to access it and capture the video. Regarding performance, it's working quite well. Another possible idea is to just use the "capture window" with the main editor as the background and not use NDI at all. @tool
extends EditorPlugin
var ndi: NDIOutput
var test_button: Button
var main_windows: Window
var poped_windows: Array[Window] = []
var popup_stuff: Window
var sprites_pool: Array[Sprite2D] = []
func _enter_tree() -> void:
main_windows = get_tree().root
ndi = NDIOutput.new()
ndi.name = "Godot Editor"
ndi.enable_editor_output = true
add_child(ndi)
test_button = Button.new()
test_button.text = "Click me"
test_button.pressed.connect(test)
add_control_to_container(EditorPlugin.CONTAINER_TOOLBAR, test_button)
for child in get_tree().root.find_children("*", "Window", true, false):
connect_signals(child)
popup_stuff = Window.new()
popup_stuff.initial_position = Window.WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN
popup_stuff.size = Vector2(1920, 1080)
popup_stuff.title = "Popup Stuff"
popup_stuff.name = "Popup Stuff"
popup_stuff.transparent = true
popup_stuff.transparent_bg = true
var ndi = NDIOutput.new()
ndi.name = "Godot Editor Overlay"
ndi.enable_editor_output = true
popup_stuff.add_child(ndi)
for i in 10:
var sprite_2d = Sprite2D.new()
sprite_2d.centered = false
sprite_2d.visible = false
sprite_2d.name = "popup_stuff_%d" %i
sprites_pool.append(sprite_2d)
popup_stuff.add_child(sprite_2d)
add_child(popup_stuff)
get_tree().node_added.connect(connect_signals)
func _exit_tree() -> void:
if is_instance_valid(ndi):
ndi.queue_free()
if is_instance_valid(test_button):
test_button.queue_free()
func test() -> void:
print("Hello world")
#await get_tree().create_timer(2.0).timeout
func connect_signals(node: Node):
if node is Window:
if node.is_embedded():
return
var callback:= on_visibility_changed.bind(node)
if not node.visibility_changed.is_connected(callback):
node.visibility_changed.connect(callback)
func on_visibility_changed(window: Window):
if window.visible:
add_poped_windows.call(window)
else:
remove_poped_windows(window)
func add_poped_windows(window: Window):
#print("add_poped_windows", window.name, window.borderless)
poped_windows.append(window)
on_focus_entered(window)
var callback:= remove_poped_windows.bind(window)
if not window.tree_exiting.is_connected(callback):
window.tree_exiting.connect(callback, CONNECT_ONE_SHOT)
#if not window.focus_entered.is_connected(on_focus_entered.bind(window)):
# window.focus_entered.connect(on_focus_entered.bind(window))
#if not window.focus_exited.is_connected(on_focus_exited.bind(window)):
# window.focus_exited.connect(on_focus_exited.bind(window))
func remove_poped_windows(window: Window):
#print("remove_poped_windows", window.name)
on_focus_exited(window)
var index = poped_windows.find(window)
if index > -1:
sprites_pool[index].texture = null
sprites_pool[index].visible = false
poped_windows.remove_at(index)
func _process(delta: float) -> void:
var poped_count = poped_windows.size()
var borderless_count: int = 0
var latest_borderless_index: int = -1
for i in range(0, poped_count):
var window: Window = poped_windows[i]
if not window.borderless:
borderless_count += 1
latest_borderless_index = i
var sprite: Sprite2D = sprites_pool[i]
#prints(window.name, window.get_visible_rect())
sprite.texture = window.get_texture()
sprite.position = window.position - main_windows.position
sprite.centered = false
if borderless_count == 1:
var window: Window = poped_windows[latest_borderless_index]
var sprite: Sprite2D = sprites_pool[latest_borderless_index]
sprite.centered = true
sprite.position = popup_stuff.get_visible_rect().size / 2
func on_focus_entered(window: Window):
var index = poped_windows.find(window)
sprites_pool[index].visible = true
func on_focus_exited(window: Window):
var index = poped_windows.find(window)
sprites_pool[index].visible = false |
Porting this to C++ and maintaining it's functionality in the future feels like too much work, for what can mostly be recreated with a OBS Window Capture. I'd prefer documenting a small guide on how to do it for people who need it but I reccon most expect the Output Editor feature to work as it does. Edit: Guess it doesn't work with the Embedded Game Window. |
Hello,
I was wondering if this add-on could be used to stream the Godot Editor over NDI?
I’m already using NDI with other software in OBS, and since the Godot Editor itself is made with Godot, I assume this should be possible.
The text was updated successfully, but these errors were encountered: