mirror of
				https://github.com/nefrace/godot-camera-preview.git
				synced 2025-11-04 07:49:19 +03:00 
			
		
		
		
	Initial commit
This commit is contained in:
		
							
								
								
									
										26
									
								
								cam_preview.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								cam_preview.gd
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
tool
 | 
			
		||||
extends Control
 | 
			
		||||
 | 
			
		||||
onready var window: Panel = $window
 | 
			
		||||
onready var vp: Viewport = $window/container/vp
 | 
			
		||||
onready var container: ViewportContainer = $window/container
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _ready():
 | 
			
		||||
	resize_vp()
 | 
			
		||||
 | 
			
		||||
func get_vp() -> Viewport:
 | 
			
		||||
	return vp
 | 
			
		||||
	
 | 
			
		||||
func toggle_window(toggle):
 | 
			
		||||
	window.visible = toggle
 | 
			
		||||
	
 | 
			
		||||
func toggle_vp(toggle):
 | 
			
		||||
	container.visible = toggle
 | 
			
		||||
 | 
			
		||||
func _on_window_resized():
 | 
			
		||||
	resize_vp()
 | 
			
		||||
	
 | 
			
		||||
func resize_vp():
 | 
			
		||||
	vp.size = window.rect_size
 | 
			
		||||
	
 | 
			
		||||
							
								
								
									
										67
									
								
								cam_preview.tscn
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								cam_preview.tscn
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
			
		||||
[gd_scene load_steps=4 format=2]
 | 
			
		||||
 | 
			
		||||
[ext_resource path="res://addons/camera_preview/cam_preview.gd" type="Script" id=1]
 | 
			
		||||
[ext_resource path="res://addons/camera_preview/window.gd" type="Script" id=2]
 | 
			
		||||
 | 
			
		||||
[sub_resource type="StyleBoxFlat" id=1]
 | 
			
		||||
bg_color = Color( 0, 0, 0, 0.164706 )
 | 
			
		||||
border_width_left = 2
 | 
			
		||||
border_width_top = 2
 | 
			
		||||
border_width_right = 2
 | 
			
		||||
border_width_bottom = 2
 | 
			
		||||
border_color = Color( 0.290196, 0.290196, 0.290196, 0.396078 )
 | 
			
		||||
corner_radius_top_left = 5
 | 
			
		||||
corner_radius_top_right = 5
 | 
			
		||||
corner_radius_bottom_right = 5
 | 
			
		||||
corner_radius_bottom_left = 5
 | 
			
		||||
 | 
			
		||||
[node name="cam_preview" type="Control"]
 | 
			
		||||
anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
mouse_filter = 1
 | 
			
		||||
script = ExtResource( 1 )
 | 
			
		||||
 | 
			
		||||
[node name="window" type="Panel" parent="."]
 | 
			
		||||
anchor_left = 1.0
 | 
			
		||||
anchor_top = 1.0
 | 
			
		||||
anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
margin_left = -316.0
 | 
			
		||||
margin_top = -250.0
 | 
			
		||||
rect_min_size = Vector2( 300, 250 )
 | 
			
		||||
mouse_default_cursor_shape = 6
 | 
			
		||||
custom_styles/panel = SubResource( 1 )
 | 
			
		||||
script = ExtResource( 2 )
 | 
			
		||||
 | 
			
		||||
[node name="Label" type="Label" parent="window"]
 | 
			
		||||
anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
text = "no signal"
 | 
			
		||||
align = 1
 | 
			
		||||
valign = 1
 | 
			
		||||
 | 
			
		||||
[node name="container" type="ViewportContainer" parent="window"]
 | 
			
		||||
visible = false
 | 
			
		||||
anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
mouse_filter = 1
 | 
			
		||||
 | 
			
		||||
[node name="vp" type="Viewport" parent="window/container"]
 | 
			
		||||
size = Vector2( 316, 250 )
 | 
			
		||||
handle_input_locally = false
 | 
			
		||||
render_target_update_mode = 0
 | 
			
		||||
shadow_atlas_size = 512
 | 
			
		||||
 | 
			
		||||
[node name="resize" type="Control" parent="window"]
 | 
			
		||||
anchor_left = 1.0
 | 
			
		||||
anchor_top = 1.0
 | 
			
		||||
anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
margin_left = -20.0
 | 
			
		||||
margin_top = -20.0
 | 
			
		||||
rect_min_size = Vector2( 20, 20 )
 | 
			
		||||
mouse_default_cursor_shape = 12
 | 
			
		||||
 | 
			
		||||
[connection signal="gui_input" from="window" to="window" method="_on_window_gui_input"]
 | 
			
		||||
[connection signal="resized" from="window" to="." method="_on_window_resized"]
 | 
			
		||||
[connection signal="gui_input" from="window/resize" to="window" method="_on_resize_gui_input"]
 | 
			
		||||
							
								
								
									
										7
									
								
								plugin.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								plugin.cfg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
[plugin]
 | 
			
		||||
 | 
			
		||||
name="CameraPreview"
 | 
			
		||||
description="Allows user to create a small window inside the main editor view to preview selected Camera in 3d scene"
 | 
			
		||||
author="Nefrace"
 | 
			
		||||
version="0.4"
 | 
			
		||||
script="plugin.gd"
 | 
			
		||||
							
								
								
									
										107
									
								
								plugin.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								plugin.gd
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
			
		||||
tool
 | 
			
		||||
extends EditorPlugin 
 | 
			
		||||
 | 
			
		||||
const CamPreview = preload("./cam_preview.tscn")
 | 
			
		||||
const PreviewButton = preload("./preview_button.tscn")
 | 
			
		||||
var cam_preview_instance
 | 
			
		||||
var button_instance
 | 
			
		||||
 | 
			
		||||
var cam_selected: Camera
 | 
			
		||||
var pcam: Camera
 | 
			
		||||
var rt: RemoteTransform
 | 
			
		||||
 | 
			
		||||
var eds = get_editor_interface().get_selection()
 | 
			
		||||
 | 
			
		||||
func _enter_tree():
 | 
			
		||||
	connect("main_screen_changed", self, "main_screen_changed")
 | 
			
		||||
	cam_preview_instance = CamPreview.instance()
 | 
			
		||||
	get_editor_interface().get_editor_viewport().add_child(cam_preview_instance)
 | 
			
		||||
	cam_preview_instance.toggle_window(false)
 | 
			
		||||
	
 | 
			
		||||
	button_instance = PreviewButton.instance()
 | 
			
		||||
	add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, button_instance)
 | 
			
		||||
#	button_instance.connect("toggled", self, "preview_pressed")
 | 
			
		||||
	button_instance.connect("preview_toggled", self, "preview_pressed")
 | 
			
		||||
	button_instance.connect("preview_clear", self, "preview_free")
 | 
			
		||||
	
 | 
			
		||||
	eds.connect("selection_changed", self, "selection_changed")
 | 
			
		||||
	
 | 
			
		||||
func _exit_tree():
 | 
			
		||||
	disconnect("main_screen_changed", self, "main_screen_changed")
 | 
			
		||||
	button_instance.disconnect("preview_clear", self, "preview_free")
 | 
			
		||||
	button_instance.disconnect("preview_toggled", self, "preview_pressed")
 | 
			
		||||
	preview_free()
 | 
			
		||||
	if cam_preview_instance:
 | 
			
		||||
		cam_preview_instance.queue_free()
 | 
			
		||||
	if button_instance:
 | 
			
		||||
		button_instance.queue_free()
 | 
			
		||||
		
 | 
			
		||||
func find_a_camera(root) -> Camera:
 | 
			
		||||
	if root is Camera:
 | 
			
		||||
		return root
 | 
			
		||||
	match button_instance.search_mode:
 | 
			
		||||
		1:
 | 
			
		||||
			return root.find_node(button_instance.search_name, true, false) as Camera
 | 
			
		||||
		2:
 | 
			
		||||
			return get_cam_recursive(root)
 | 
			
		||||
	return null 
 | 
			
		||||
	
 | 
			
		||||
func get_cam_recursive(root):
 | 
			
		||||
	var cam: Camera
 | 
			
		||||
	for child in root.get_children():
 | 
			
		||||
		if child is Camera:
 | 
			
		||||
			return child
 | 
			
		||||
		cam = get_cam_recursive(child)
 | 
			
		||||
	return cam
 | 
			
		||||
		
 | 
			
		||||
func selection_changed():
 | 
			
		||||
	var selected = eds.get_selected_nodes()
 | 
			
		||||
	if not selected.empty():
 | 
			
		||||
		var cam = find_a_camera(selected[0])
 | 
			
		||||
		if cam:
 | 
			
		||||
			if cam_selected:
 | 
			
		||||
				cam_selected.disconnect("tree_exiting", self, "cam_deleted")
 | 
			
		||||
			cam_selected = cam
 | 
			
		||||
			#remove old camera and remote transform
 | 
			
		||||
			preview_free()
 | 
			
		||||
			pcam = Camera.new()
 | 
			
		||||
			rt = RemoteTransform.new()
 | 
			
		||||
			cam_preview_instance.get_vp().add_child(pcam)
 | 
			
		||||
			cam_preview_instance.toggle_vp(true)
 | 
			
		||||
			cam.add_child(rt)
 | 
			
		||||
			cam.connect("tree_exiting", self, "cam_deleted")
 | 
			
		||||
			rt.remote_path = pcam.get_path()
 | 
			
		||||
			rt.use_global_coordinates = true
 | 
			
		||||
 | 
			
		||||
func cam_deleted():
 | 
			
		||||
	preview_free()
 | 
			
		||||
	cam_preview_instance.toggle_vp(false)
 | 
			
		||||
	cam_selected.disconnect("tree_exiting", self, "cam_deleted")
 | 
			
		||||
 | 
			
		||||
func preview_free():
 | 
			
		||||
	if pcam:
 | 
			
		||||
		pcam.queue_free()
 | 
			
		||||
	if rt:
 | 
			
		||||
		rt.queue_free()
 | 
			
		||||
	cam_preview_instance.toggle_vp(false)
 | 
			
		||||
 | 
			
		||||
func show_all():
 | 
			
		||||
	if cam_preview_instance:
 | 
			
		||||
		cam_preview_instance.show()
 | 
			
		||||
	if button_instance:
 | 
			
		||||
		button_instance.show()
 | 
			
		||||
 | 
			
		||||
func hide_all():
 | 
			
		||||
	if cam_preview_instance:
 | 
			
		||||
		cam_preview_instance.hide()
 | 
			
		||||
	if button_instance:
 | 
			
		||||
		button_instance.hide()
 | 
			
		||||
		
 | 
			
		||||
func main_screen_changed(screen):
 | 
			
		||||
	if screen == "3D":
 | 
			
		||||
		show_all()
 | 
			
		||||
	else:
 | 
			
		||||
		hide_all()
 | 
			
		||||
 | 
			
		||||
func preview_pressed(toggle):
 | 
			
		||||
	cam_preview_instance.toggle_window(toggle)
 | 
			
		||||
							
								
								
									
										45
									
								
								preview_button.tscn
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								preview_button.tscn
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
[gd_scene load_steps=2 format=2]
 | 
			
		||||
 | 
			
		||||
[ext_resource path="res://addons/camera_preview/toggle_button.gd" type="Script" id=1]
 | 
			
		||||
 | 
			
		||||
[node name="ToolButton" type="MenuButton"]
 | 
			
		||||
margin_right = 114.0
 | 
			
		||||
margin_bottom = 22.0
 | 
			
		||||
toggle_mode = false
 | 
			
		||||
shortcut_in_tooltip = false
 | 
			
		||||
text = "Camera preview"
 | 
			
		||||
items = [ "Visible", null, 1, false, false, 0, 0, null, "", false, "Search node", null, 0, false, false, -1, 0, null, "", true, "Disabled", null, 2, true, false, 2, 0, null, "", false, "By name", null, 2, false, false, 3, 0, null, "", false, "By class", null, 2, false, false, 4, 0, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Change search pattern", null, 0, false, false, 6, 0, null, "", false, "Clear preview", null, 0, false, false, 7, 0, null, "", false ]
 | 
			
		||||
switch_on_hover = true
 | 
			
		||||
script = ExtResource( 1 )
 | 
			
		||||
 | 
			
		||||
[node name="WindowDialog" type="WindowDialog" parent="."]
 | 
			
		||||
margin_right = 255.0
 | 
			
		||||
margin_bottom = 151.0
 | 
			
		||||
rect_min_size = Vector2( 255, 150 )
 | 
			
		||||
window_title = "Change search pattern"
 | 
			
		||||
 | 
			
		||||
[node name="VBoxContainer" type="VBoxContainer" parent="WindowDialog"]
 | 
			
		||||
anchor_left = 0.5
 | 
			
		||||
anchor_top = 0.5
 | 
			
		||||
anchor_right = 0.5
 | 
			
		||||
anchor_bottom = 0.5
 | 
			
		||||
margin_left = -80.0
 | 
			
		||||
margin_top = -24.0
 | 
			
		||||
margin_right = 80.0
 | 
			
		||||
margin_bottom = 37.0
 | 
			
		||||
 | 
			
		||||
[node name="TextEdit" type="LineEdit" parent="WindowDialog/VBoxContainer"]
 | 
			
		||||
margin_right = 160.0
 | 
			
		||||
margin_bottom = 30.0
 | 
			
		||||
rect_min_size = Vector2( 0, 30 )
 | 
			
		||||
text = "asdasd"
 | 
			
		||||
align = 1
 | 
			
		||||
 | 
			
		||||
[node name="Button" type="Button" parent="WindowDialog/VBoxContainer"]
 | 
			
		||||
margin_top = 34.0
 | 
			
		||||
margin_right = 160.0
 | 
			
		||||
margin_bottom = 54.0
 | 
			
		||||
text = "Ok"
 | 
			
		||||
 | 
			
		||||
[connection signal="text_entered" from="WindowDialog/VBoxContainer/TextEdit" to="." method="_on_TextEdit_text_entered"]
 | 
			
		||||
[connection signal="pressed" from="WindowDialog/VBoxContainer/Button" to="." method="_on_change_search_pressed"]
 | 
			
		||||
							
								
								
									
										66
									
								
								toggle_button.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								toggle_button.gd
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
tool
 | 
			
		||||
 | 
			
		||||
extends MenuButton
 | 
			
		||||
 | 
			
		||||
var search_mode = 0
 | 
			
		||||
var search_mode_offset = 2
 | 
			
		||||
var pop : PopupMenu
 | 
			
		||||
var is_visible: bool = false
 | 
			
		||||
var search_name: String = "Camera*"
 | 
			
		||||
 | 
			
		||||
signal preview_toggled(visible)
 | 
			
		||||
signal preview_clear()
 | 
			
		||||
 | 
			
		||||
func _enter_tree():
 | 
			
		||||
	pop = get_popup()
 | 
			
		||||
	pop.clear()
 | 
			
		||||
	pop.add_check_item("Visible")
 | 
			
		||||
	pop.add_separator("Search node")
 | 
			
		||||
	pop.add_radio_check_item("Disabled")
 | 
			
		||||
	pop.add_radio_check_item("By name")
 | 
			
		||||
	pop.add_radio_check_item("By class")
 | 
			
		||||
	pop.add_separator()
 | 
			
		||||
	pop.add_item("Change search pattern")
 | 
			
		||||
	pop.add_item("Clear preview")
 | 
			
		||||
	pop.connect('id_pressed', self, 'item_pressed')
 | 
			
		||||
	pop.set_item_checked(2, true)
 | 
			
		||||
	
 | 
			
		||||
func _exit_tree():
 | 
			
		||||
	pop.disconnect('id_pressed', self, 'item_pressed')
 | 
			
		||||
	
 | 
			
		||||
func select_search_mode(id):
 | 
			
		||||
	pop.set_item_checked(search_mode + search_mode_offset, false)
 | 
			
		||||
	search_mode = id - search_mode_offset
 | 
			
		||||
	pop.set_item_checked(id, true)
 | 
			
		||||
	
 | 
			
		||||
func toggle_visibility():
 | 
			
		||||
	is_visible = !is_visible
 | 
			
		||||
	pop.set_item_checked(0, is_visible)
 | 
			
		||||
	emit_signal("preview_toggled", is_visible)
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
func item_pressed(id):
 | 
			
		||||
	if id == 0:
 | 
			
		||||
		toggle_visibility()
 | 
			
		||||
		return
 | 
			
		||||
	if id >= 2 and id <= 4:
 | 
			
		||||
		select_search_mode(id)
 | 
			
		||||
		return
 | 
			
		||||
	if id == 6:
 | 
			
		||||
		$WindowDialog.popup_centered()
 | 
			
		||||
		$WindowDialog/VBoxContainer/TextEdit.text = search_name
 | 
			
		||||
		return
 | 
			
		||||
	if id == 7:
 | 
			
		||||
		emit_signal("preview_clear")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func set_search_text():
 | 
			
		||||
	search_name = $WindowDialog/VBoxContainer/TextEdit.text
 | 
			
		||||
	$WindowDialog.hide()
 | 
			
		||||
 | 
			
		||||
func _on_change_search_pressed():
 | 
			
		||||
	set_search_text()
 | 
			
		||||
 | 
			
		||||
func _on_TextEdit_text_entered(new_text):
 | 
			
		||||
	set_search_text()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								window.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								window.gd
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
tool
 | 
			
		||||
extends Panel
 | 
			
		||||
 | 
			
		||||
var dragging = false
 | 
			
		||||
var resizing = false
 | 
			
		||||
var mouse_offset : Vector2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _process(_delta) -> void:
 | 
			
		||||
	if dragging:
 | 
			
		||||
		var movement = get_local_mouse_position() - mouse_offset
 | 
			
		||||
		set_position(rect_position + movement)
 | 
			
		||||
	if resizing:
 | 
			
		||||
		var new_size = get_local_mouse_position()
 | 
			
		||||
		set_size(new_size)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _on_window_gui_input(event):
 | 
			
		||||
	if event is InputEventMouseButton:
 | 
			
		||||
		if event.button_index == BUTTON_LEFT:
 | 
			
		||||
			dragging = event.pressed
 | 
			
		||||
			mouse_offset = get_local_mouse_position()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _on_resize_gui_input(event):
 | 
			
		||||
	if event is InputEventMouseButton:
 | 
			
		||||
		if event.button_index == BUTTON_LEFT:
 | 
			
		||||
			resizing = event.pressed
 | 
			
		||||
			mouse_offset = get_local_mouse_position()
 | 
			
		||||
		Reference in New Issue
	
	Block a user