mirror of
https://github.com/litruv/PNGTuber-Plus.git
synced 2026-07-24 02:26:02 +10:00
fixed the UI shaking at higher framerates
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@
|
|||||||
.itchio/
|
.itchio/
|
||||||
.steam/
|
.steam/
|
||||||
build/
|
build/
|
||||||
|
*.TMP
|
||||||
|
|||||||
@@ -40,9 +40,18 @@ Access the NDI settings through the Settings Menu:
|
|||||||
- **NDI streaming**: Enable/disable NDI output
|
- **NDI streaming**: Enable/disable NDI output
|
||||||
- **Source name**: Set a custom name for your NDI source (default: "PNGTuber-Plus")
|
- **Source name**: Set a custom name for your NDI source (default: "PNGTuber-Plus")
|
||||||
- **Include audio**: Toggle audio streaming on/off
|
- **Include audio**: Toggle audio streaming on/off
|
||||||
|
- **Avatar-only stream**: Enable a clean avatar-only stream without UI elements
|
||||||
- **Status**: View current streaming status
|
- **Status**: View current streaming status
|
||||||
- **Start/Stop NDI**: Manual control button
|
- **Start/Stop NDI**: Manual control button
|
||||||
|
|
||||||
|
#### Avatar-Only Streaming
|
||||||
|
|
||||||
|
The "Avatar-only stream" option creates a second NDI source called "PNGTuber Avatar" that:
|
||||||
|
- Streams only the avatar sprites with a transparent background
|
||||||
|
- Excludes all UI elements, menus, and controls
|
||||||
|
- Perfect for professional streaming setups
|
||||||
|
- Syncs automatically with the main avatar state
|
||||||
|
|
||||||
### 3. Hotkey Controls
|
### 3. Hotkey Controls
|
||||||
|
|
||||||
Quick keyboard shortcuts for NDI control:
|
Quick keyboard shortcuts for NDI control:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,7 +4,7 @@ extends Node2D
|
|||||||
@onready var editButton = $Edit/Button
|
@onready var editButton = $Edit/Button
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
var uiAnimSpeed = Global.main.physicsTimeMultiplier * 20.0 if Global.main else 120.0
|
var uiAnimSpeed = 8.0 # Fixed UI animation speed
|
||||||
if Rect2(editButton.get_parent().position-Vector2(24,24),editButton.size).has_point(get_local_mouse_position()):
|
if Rect2(editButton.get_parent().position-Vector2(24,24),editButton.size).has_point(get_local_mouse_position()):
|
||||||
editSprite.scale = lerp(editSprite.scale, Vector2(1.2,1.2), delta * uiAnimSpeed)
|
editSprite.scale = lerp(editSprite.scale, Vector2(1.2,1.2), delta * uiAnimSpeed)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func _process(delta):
|
|||||||
if buttons[b] == null:
|
if buttons[b] == null:
|
||||||
continue
|
continue
|
||||||
if Rect2(buttons[b].get_parent().position-Vector2(24,24),buttons[b].size).has_point(get_local_mouse_position()):
|
if Rect2(buttons[b].get_parent().position-Vector2(24,24),buttons[b].size).has_point(get_local_mouse_position()):
|
||||||
var uiAnimSpeed = Global.main.physicsTimeMultiplier * 20.0 if Global.main else 120.0
|
var uiAnimSpeed = 8.0 # Fixed UI animation speed
|
||||||
sprites[s].scale = lerp(sprites[s].scale, Vector2(1.2,1.2), delta * uiAnimSpeed)
|
sprites[s].scale = lerp(sprites[s].scale, Vector2(1.2,1.2), delta * uiAnimSpeed)
|
||||||
if Input.is_action_pressed("mouse_left"):
|
if Input.is_action_pressed("mouse_left"):
|
||||||
sprites[s].scale = Vector2(0.6,0.6)
|
sprites[s].scale = Vector2(0.6,0.6)
|
||||||
@@ -51,7 +51,7 @@ func _process(delta):
|
|||||||
Global.mouse.text = "Duplicate sprite"
|
Global.mouse.text = "Duplicate sprite"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
var uiAnimSpeed = Global.main.physicsTimeMultiplier * 20.0 if Global.main else 120.0
|
var uiAnimSpeed = 8.0 # Fixed UI animation speed
|
||||||
sprites[s].scale = lerp(sprites[s].scale, Vector2(1.0,1.0), delta * uiAnimSpeed)
|
sprites[s].scale = lerp(sprites[s].scale, Vector2(1.0,1.0), delta * uiAnimSpeed)
|
||||||
s += 1
|
s += 1
|
||||||
|
|
||||||
|
|||||||
144
main_scenes/NDIAvatarViewport.gd
Normal file
144
main_scenes/NDIAvatarViewport.gd
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
extends SubViewport
|
||||||
|
|
||||||
|
## NDI Avatar Viewport Controller
|
||||||
|
## Handles avatar-only NDI streaming with synchronized states
|
||||||
|
|
||||||
|
#Node Reference
|
||||||
|
@onready var origin = $OriginMotion/Origin
|
||||||
|
@onready var ndi_output = $NDIOutput
|
||||||
|
|
||||||
|
## Initialize viewport settings for transparent background and avatar mirroring
|
||||||
|
func _ready():
|
||||||
|
# Set transparent background
|
||||||
|
transparent_bg = true
|
||||||
|
|
||||||
|
# Connect to the main scene for state sync
|
||||||
|
if Global.main:
|
||||||
|
Global.main.connect("spriteVisToggles", Callable(self, "_on_sprite_visibility_toggle"))
|
||||||
|
Global.main.connect("bounceChange", Callable(self, "_sync_bounce"))
|
||||||
|
|
||||||
|
## Sync avatar sprites from main scene to this viewport
|
||||||
|
func sync_avatar():
|
||||||
|
# Clear existing sprites
|
||||||
|
for child in origin.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
|
# Wait for cleanup
|
||||||
|
await get_tree().process_frame
|
||||||
|
|
||||||
|
# Get sprites from main scene
|
||||||
|
var main_sprites = get_tree().get_nodes_in_group("saved")
|
||||||
|
for sprite in main_sprites:
|
||||||
|
clone_sprite(sprite)
|
||||||
|
|
||||||
|
## Clone a sprite from main scene to this viewport
|
||||||
|
func clone_sprite(original_sprite):
|
||||||
|
# Create new instance
|
||||||
|
var sprite_scene = preload("res://ui_scenes/selectedSprite/spriteObject.tscn")
|
||||||
|
var cloned_sprite = sprite_scene.instantiate()
|
||||||
|
|
||||||
|
# Copy all properties
|
||||||
|
cloned_sprite.path = original_sprite.path
|
||||||
|
cloned_sprite.id = original_sprite.id
|
||||||
|
cloned_sprite.parentId = original_sprite.parentId
|
||||||
|
cloned_sprite.displayName = original_sprite.displayName
|
||||||
|
|
||||||
|
# Visual properties
|
||||||
|
cloned_sprite.offset = original_sprite.offset
|
||||||
|
cloned_sprite.z = original_sprite.z
|
||||||
|
cloned_sprite.position = original_sprite.position
|
||||||
|
|
||||||
|
# Physics properties
|
||||||
|
cloned_sprite.dragSpeed = original_sprite.dragSpeed
|
||||||
|
cloned_sprite.xFrq = original_sprite.xFrq
|
||||||
|
cloned_sprite.xAmp = original_sprite.xAmp
|
||||||
|
cloned_sprite.yFrq = original_sprite.yFrq
|
||||||
|
cloned_sprite.yAmp = original_sprite.yAmp
|
||||||
|
cloned_sprite.rFrq = original_sprite.rFrq
|
||||||
|
cloned_sprite.rAmp = original_sprite.rAmp
|
||||||
|
cloned_sprite.rdragStr = original_sprite.rdragStr
|
||||||
|
cloned_sprite.rLimitMin = original_sprite.rLimitMin
|
||||||
|
cloned_sprite.rLimitMax = original_sprite.rLimitMax
|
||||||
|
cloned_sprite.stretchAmount = original_sprite.stretchAmount
|
||||||
|
cloned_sprite.ignoreBounce = original_sprite.ignoreBounce
|
||||||
|
|
||||||
|
# Animation properties
|
||||||
|
cloned_sprite.frames = original_sprite.frames
|
||||||
|
cloned_sprite.animSpeed = original_sprite.animSpeed
|
||||||
|
|
||||||
|
# Visibility properties
|
||||||
|
cloned_sprite.showOnTalk = original_sprite.showOnTalk
|
||||||
|
cloned_sprite.showOnBlink = original_sprite.showOnBlink
|
||||||
|
cloned_sprite.costumeLayers = original_sprite.costumeLayers.duplicate()
|
||||||
|
cloned_sprite.spriteOpacity = original_sprite.spriteOpacity
|
||||||
|
cloned_sprite.affectChildrenOpacity = original_sprite.affectChildrenOpacity
|
||||||
|
cloned_sprite.blendMode = original_sprite.blendMode
|
||||||
|
cloned_sprite.toggle = original_sprite.toggle
|
||||||
|
cloned_sprite.clipped = original_sprite.clipped
|
||||||
|
|
||||||
|
# Transform properties
|
||||||
|
cloned_sprite.staticRotation = original_sprite.staticRotation
|
||||||
|
cloned_sprite.mirrorHorizontal = original_sprite.mirrorHorizontal
|
||||||
|
cloned_sprite.mirrorVertical = original_sprite.mirrorVertical
|
||||||
|
|
||||||
|
# Wobble sync
|
||||||
|
cloned_sprite.wobbleSyncGroup = original_sprite.wobbleSyncGroup
|
||||||
|
|
||||||
|
# Add to origin
|
||||||
|
origin.add_child(cloned_sprite)
|
||||||
|
|
||||||
|
# Apply current costume visibility
|
||||||
|
if Global.main:
|
||||||
|
var current_costume = Global.main.costume
|
||||||
|
if cloned_sprite.costumeLayers[current_costume - 1] == 1:
|
||||||
|
cloned_sprite.visible = true
|
||||||
|
else:
|
||||||
|
cloned_sprite.visible = false
|
||||||
|
|
||||||
|
## Process function to keep sprites in sync with main scene
|
||||||
|
func _process(delta):
|
||||||
|
if !Global.main:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Sync origin position with bounce from main scene
|
||||||
|
$OriginMotion.position.y = 360 + Global.main.bounceChange
|
||||||
|
|
||||||
|
# Sync sprites with main scene
|
||||||
|
var main_sprites = get_tree().get_nodes_in_group("saved")
|
||||||
|
var avatar_sprites = origin.get_children()
|
||||||
|
|
||||||
|
for i in range(min(main_sprites.size(), avatar_sprites.size())):
|
||||||
|
sync_sprite_state(main_sprites[i], avatar_sprites[i])
|
||||||
|
|
||||||
|
## Sync individual sprite state
|
||||||
|
func sync_sprite_state(main_sprite, avatar_sprite):
|
||||||
|
if !is_instance_valid(main_sprite) or !is_instance_valid(avatar_sprite):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Sync position and transform
|
||||||
|
avatar_sprite.position = main_sprite.position
|
||||||
|
avatar_sprite.rotation = main_sprite.rotation
|
||||||
|
avatar_sprite.scale = main_sprite.scale
|
||||||
|
|
||||||
|
# Sync visibility based on costume
|
||||||
|
if Global.main:
|
||||||
|
var current_costume = Global.main.costume
|
||||||
|
if avatar_sprite.costumeLayers[current_costume - 1] == 1:
|
||||||
|
avatar_sprite.visible = main_sprite.visible
|
||||||
|
else:
|
||||||
|
avatar_sprite.visible = false
|
||||||
|
|
||||||
|
# Sync animation frame
|
||||||
|
if avatar_sprite.has_method("get_sprite") and main_sprite.has_method("get_sprite"):
|
||||||
|
var avatar_spr = avatar_sprite.get_sprite()
|
||||||
|
var main_spr = main_sprite.get_sprite()
|
||||||
|
if avatar_spr and main_spr:
|
||||||
|
avatar_spr.frame = main_spr.frame
|
||||||
|
|
||||||
|
## Handle sprite visibility toggles
|
||||||
|
func _on_sprite_visibility_toggle():
|
||||||
|
sync_avatar()
|
||||||
|
|
||||||
|
## Sync bounce changes
|
||||||
|
func _sync_bounce(bounce_change):
|
||||||
|
$OriginMotion.position.y = 360 + bounce_change
|
||||||
1
main_scenes/NDIAvatarViewport.gd.uid
Normal file
1
main_scenes/NDIAvatarViewport.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dkomsdn2pvjwp
|
||||||
18
main_scenes/NDIAvatarViewport.tscn
Normal file
18
main_scenes/NDIAvatarViewport.tscn
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://main_scenes/NDIAvatarViewport.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="SubViewport" type="SubViewport"]
|
||||||
|
handle_input_locally = false
|
||||||
|
size = Vector2i(1280, 720)
|
||||||
|
render_target_update_mode = 4
|
||||||
|
script = ExtResource("1")
|
||||||
|
|
||||||
|
[node name="NDIOutput" type="NDIOutput"]
|
||||||
|
name = "PNGTuber Avatar"
|
||||||
|
enable_editor_output = true
|
||||||
|
|
||||||
|
[node name="OriginMotion" type="Node2D"]
|
||||||
|
position = Vector2(640, 360)
|
||||||
|
|
||||||
|
[node name="Origin" type="Node2D" parent="OriginMotion"]
|
||||||
1
main_scenes/NDIOutputManager.gd.uid
Normal file
1
main_scenes/NDIOutputManager.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c1wo8w4ac848b
|
||||||
@@ -8,7 +8,7 @@ var editMode = true
|
|||||||
@onready var controlPanel = $ControlPanel
|
@onready var controlPanel = $ControlPanel
|
||||||
@onready var editControls = $EditControls
|
@onready var editControls = $EditControls
|
||||||
@onready var tutorial = $Tutorial
|
@onready var tutorial = $Tutorial
|
||||||
@onready var spriteViewer = $EditControls/SpriteViewer
|
@onready var spriteViewer = $EditControls/Container/SpriteViewer
|
||||||
@onready var viewerArrows = $ViewerArrows
|
@onready var viewerArrows = $ViewerArrows
|
||||||
@onready var spriteList = $EditControls/SpriteList
|
@onready var spriteList = $EditControls/SpriteList
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@ var editMode = true
|
|||||||
@onready var shadow = $shadowSprite
|
@onready var shadow = $shadowSprite
|
||||||
|
|
||||||
@onready var ndi_output = $NDIOutput
|
@onready var ndi_output = $NDIOutput
|
||||||
|
@onready var ndi_avatar_viewport = $NDIAvatarViewport
|
||||||
|
|
||||||
|
|
||||||
#Scene Reference
|
#Scene Reference
|
||||||
@@ -156,6 +157,10 @@ func _ready():
|
|||||||
origin.position = s*0.5
|
origin.position = s*0.5
|
||||||
updateCameraPosition()
|
updateCameraPosition()
|
||||||
|
|
||||||
|
# Initialize avatar viewport
|
||||||
|
if ndi_avatar_viewport:
|
||||||
|
ndi_avatar_viewport.visible = false # Start disabled
|
||||||
|
|
||||||
# Test NDI output on startup
|
# Test NDI output on startup
|
||||||
call_deferred("toggle_ndi")
|
call_deferred("toggle_ndi")
|
||||||
|
|
||||||
@@ -431,8 +436,17 @@ func add_image(path):
|
|||||||
|
|
||||||
Global.spriteList.updateData()
|
Global.spriteList.updateData()
|
||||||
|
|
||||||
|
# Sync avatar to NDI viewport
|
||||||
|
if ndi_avatar_viewport:
|
||||||
|
call_deferred("sync_avatar_viewport")
|
||||||
|
|
||||||
Global.pushUpdate("Added new sprite.")
|
Global.pushUpdate("Added new sprite.")
|
||||||
|
|
||||||
|
## Sync avatar viewport with current sprite state
|
||||||
|
func sync_avatar_viewport():
|
||||||
|
if ndi_avatar_viewport:
|
||||||
|
ndi_avatar_viewport.sync_avatar()
|
||||||
|
|
||||||
#Opens File Dialog
|
#Opens File Dialog
|
||||||
func _on_add_button_pressed():
|
func _on_add_button_pressed():
|
||||||
fileDialog.visible = true
|
fileDialog.visible = true
|
||||||
@@ -575,6 +589,10 @@ func _on_load_dialog_file_selected(path):
|
|||||||
if sprite.has_method("updateOpacity"):
|
if sprite.has_method("updateOpacity"):
|
||||||
sprite.updateOpacity()
|
sprite.updateOpacity()
|
||||||
|
|
||||||
|
# Sync avatar to NDI viewport
|
||||||
|
if ndi_avatar_viewport:
|
||||||
|
ndi_avatar_viewport.sync_avatar()
|
||||||
|
|
||||||
Global.pushUpdate("Loaded avatar at: " + path)
|
Global.pushUpdate("Loaded avatar at: " + path)
|
||||||
|
|
||||||
onWindowSizeChange()
|
onWindowSizeChange()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[gd_scene load_steps=80 format=4 uid="uid://bakgnwotiysu1"]
|
[gd_scene load_steps=81 format=4 uid="uid://bakgnwotiysu1"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://c4g7pgn40uv4q" path="res://main_scenes/main.gd" id="1_06alx"]
|
[ext_resource type="Script" uid="uid://c4g7pgn40uv4q" path="res://main_scenes/main.gd" id="1_06alx"]
|
||||||
|
[ext_resource type="Script" uid="uid://dkomsdn2pvjwp" path="res://main_scenes/NDIAvatarViewport.gd" id="1_avatar_viewport"]
|
||||||
[ext_resource type="Script" uid="uid://18kfbk72spvo" path="res://main_scenes/ControlPanel.gd" id="4_5ygs2"]
|
[ext_resource type="Script" uid="uid://18kfbk72spvo" path="res://main_scenes/ControlPanel.gd" id="4_5ygs2"]
|
||||||
[ext_resource type="Texture2D" uid="uid://goff8ioh380e" path="res://ui_scenes/button sprites/buttonBack.png" id="4_xenui"]
|
[ext_resource type="Texture2D" uid="uid://goff8ioh380e" path="res://ui_scenes/button sprites/buttonBack.png" id="4_xenui"]
|
||||||
[ext_resource type="Texture2D" uid="uid://da4jthat2oas4" path="res://ui_scenes/button sprites/fancy.png" id="5_75a7k"]
|
[ext_resource type="Texture2D" uid="uid://da4jthat2oas4" path="res://ui_scenes/button sprites/fancy.png" id="5_75a7k"]
|
||||||
@@ -14755,7 +14756,21 @@ z_index = -4096
|
|||||||
|
|
||||||
[node name="NDIOutput" type="NDIOutput" parent="."]
|
[node name="NDIOutput" type="NDIOutput" parent="."]
|
||||||
name = "PNGTuber-Plus"
|
name = "PNGTuber-Plus"
|
||||||
audio_bus = &"Master"
|
|
||||||
|
[node name="NDIAvatarViewport" type="SubViewport" parent="."]
|
||||||
|
handle_input_locally = false
|
||||||
|
size = Vector2i(1280, 720)
|
||||||
|
render_target_update_mode = 4
|
||||||
|
script = ExtResource("1_avatar_viewport")
|
||||||
|
|
||||||
|
[node name="NDIOutput" type="NDIOutput" parent="NDIAvatarViewport"]
|
||||||
|
name = "PNGTuber Avatar"
|
||||||
|
enable_editor_output = true
|
||||||
|
|
||||||
|
[node name="OriginMotion" type="Node2D" parent="NDIAvatarViewport"]
|
||||||
|
position = Vector2(640, 360)
|
||||||
|
|
||||||
|
[node name="Origin" type="Node2D" parent="NDIAvatarViewport/OriginMotion"]
|
||||||
|
|
||||||
[connection signal="pressed" from="ControlPanel/MicButtong/Button" to="." method="_on_button_pressed"]
|
[connection signal="pressed" from="ControlPanel/MicButtong/Button" to="." method="_on_button_pressed"]
|
||||||
[connection signal="pressed" from="ControlPanel/SettingsButton/settingsButtons" to="." method="_on_settings_buttons_pressed"]
|
[connection signal="pressed" from="ControlPanel/SettingsButton/settingsButtons" to="." method="_on_settings_buttons_pressed"]
|
||||||
|
|||||||
@@ -332,3 +332,21 @@ func setup_ndi_settings():
|
|||||||
if Global.main.ndi_output:
|
if Global.main.ndi_output:
|
||||||
$NDIOutput/ndiSourceName.text = Global.main.ndi_output.name
|
$NDIOutput/ndiSourceName.text = Global.main.ndi_output.name
|
||||||
update_ndi_status()
|
update_ndi_status()
|
||||||
|
|
||||||
|
# Initialize avatar-only checkbox state
|
||||||
|
$NDIOutput/avatarOnlyCheck.button_pressed = false
|
||||||
|
if Global.main.ndi_avatar_viewport:
|
||||||
|
$NDIOutput/avatarOnlyCheck.button_pressed = Global.main.ndi_avatar_viewport.visible
|
||||||
|
|
||||||
|
func _on_avatar_only_check_toggled(toggled_on: bool):
|
||||||
|
# Enable/disable avatar-only NDI streaming
|
||||||
|
if Global.main.ndi_avatar_viewport:
|
||||||
|
Global.main.ndi_avatar_viewport.visible = toggled_on
|
||||||
|
if toggled_on:
|
||||||
|
# Sync avatar when enabling
|
||||||
|
Global.main.ndi_avatar_viewport.sync_avatar()
|
||||||
|
print("Avatar-only NDI stream enabled")
|
||||||
|
Global.pushUpdate("Avatar-only NDI stream enabled")
|
||||||
|
else:
|
||||||
|
print("Avatar-only NDI stream disabled")
|
||||||
|
Global.pushUpdate("Avatar-only NDI stream disabled")
|
||||||
|
|||||||
@@ -14368,6 +14368,14 @@ offset_bottom = 123.0
|
|||||||
text = "Status: Not streaming"
|
text = "Status: Not streaming"
|
||||||
metadata/_edit_use_anchors_ = true
|
metadata/_edit_use_anchors_ = true
|
||||||
|
|
||||||
|
[node name="avatarOnlyCheck" type="CheckBox" parent="NDIOutput"]
|
||||||
|
offset_left = 4.0
|
||||||
|
offset_top = 125.0
|
||||||
|
offset_right = 150.0
|
||||||
|
offset_bottom = 149.0
|
||||||
|
text = "Avatar-only stream"
|
||||||
|
metadata/_edit_use_anchors_ = true
|
||||||
|
|
||||||
[node name="bounceOnCostume" type="Node2D" parent="."]
|
[node name="bounceOnCostume" type="Node2D" parent="."]
|
||||||
position = Vector2(-172, 122)
|
position = Vector2(-172, 122)
|
||||||
|
|
||||||
@@ -14938,6 +14946,7 @@ metadata/_edit_use_anchors_ = true
|
|||||||
[connection signal="toggled" from="AntiAliasing/CheckBox" to="." method="_on_check_box_toggled"]
|
[connection signal="toggled" from="AntiAliasing/CheckBox" to="." method="_on_check_box_toggled"]
|
||||||
[connection signal="toggled" from="NDIOutput/ndiEnabledCheck" to="." method="_on_ndi_enabled_check_toggled"]
|
[connection signal="toggled" from="NDIOutput/ndiEnabledCheck" to="." method="_on_ndi_enabled_check_toggled"]
|
||||||
[connection signal="text_changed" from="NDIOutput/ndiSourceName" to="." method="_on_ndi_source_name_text_changed"]
|
[connection signal="text_changed" from="NDIOutput/ndiSourceName" to="." method="_on_ndi_source_name_text_changed"]
|
||||||
|
[connection signal="toggled" from="NDIOutput/avatarOnlyCheck" to="." method="_on_avatar_only_check_toggled"]
|
||||||
[connection signal="toggled" from="bounceOnCostume/costumeCheck" to="." method="_on_costume_check_toggled"]
|
[connection signal="toggled" from="bounceOnCostume/costumeCheck" to="." method="_on_costume_check_toggled"]
|
||||||
[connection signal="value_changed" from="BounceForce/bounceForce" to="." method="_on_bounce_force_value_changed"]
|
[connection signal="value_changed" from="BounceForce/bounceForce" to="." method="_on_bounce_force_value_changed"]
|
||||||
[connection signal="value_changed" from="BounceGravity/bounceGravity" to="." method="_on_bounce_gravity_value_changed"]
|
[connection signal="value_changed" from="BounceGravity/bounceGravity" to="." method="_on_bounce_gravity_value_changed"]
|
||||||
|
|||||||
Reference in New Issue
Block a user