Compare commits

...

7 Commits

Author SHA1 Message Date
fc4cacdc9f Update release name format in build workflow 2025-07-19 23:58:28 +10:00
848361d19b update versioning to be not awful 2025-07-19 23:52:46 +10:00
711865c6a4 update kaiakairos social to bluesky 2025-07-19 23:42:03 +10:00
d231b730f7 Add experimental mic loudness UI toggle to settings 2025-07-19 22:16:40 +10:00
8ba361f3c2 Integrate microphone improvements from k0ffinz repository
- Add experimental microphone loudness detection feature
- Remove microphone restart interval for better stability
- Improve microphone initialization and error handling
- Fix audio delay issues by setting channel_disable_time=0.0
- Update settings UI to include experimental mic loudness toggle
- Add credits to k0ffinz/Ralsi for microphone improvements

These changes improve audio responsiveness and fix various
microphone-related issues including WASAPI errors and growing
audio delay problems.
2025-07-19 22:00:53 +10:00
c74dccf1cf adding mask options 2025-07-19 21:52:49 +10:00
5c51691ba7 Add Windows build automation with GitHub Actions
- Add comprehensive GitHub Actions workflow for Windows builds
- Create local and CI-specific batch files for building
- Configure export templates and build optimization
- Update export presets for proper .pck embedding and git plugin exclusion
- Set up automated releases with proper build artifacts
2025-07-19 20:36:17 +10:00
29 changed files with 887 additions and 114 deletions

View File

@@ -1,5 +1,6 @@
name: Build Windows
on:
push:
branches: [ master, main ]
@@ -14,24 +15,76 @@ env:
jobs:
export-windows:
name: Windows Export
runs-on: ubuntu-20.04
container:
image: barichello/godot-ci:4.4.1
runs-on: self-hosted
steps:
- name: Checkout
uses: actions/checkout@v4
with:
lfs: true
- name: Setup
- name: Debug Environment
run: |
mkdir -v -p ~/.local/share/godot/export_templates/
mv /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable
Write-Host "Current directory: $(Get-Location)"
Write-Host "Godot executable exists: $(Test-Path 'D:\Godot\Godot_v4.4.1-stable_win64.exe')"
Write-Host "Export name: $env:EXPORT_NAME"
Write-Host "Project file exists: $(Test-Path 'project.godot')"
Get-ChildItem -Path . -Filter "*.cfg" | Select-Object Name
- name: Verify Export Templates
run: |
$templateDir = "C:\WINDOWS\ServiceProfiles\NetworkService\AppData\Roaming\Godot\export_templates\4.4.1.stable"
Write-Host "Checking for export templates at: $templateDir"
if (Test-Path $templateDir) {
Write-Host "Export templates found. Contents:"
Get-ChildItem -Path $templateDir | Where-Object {$_.Name -like "*windows*"} | Select-Object Name, Length | Format-Table
# Verify the specific Windows templates we need
$debugTemplate = Join-Path $templateDir "windows_debug_x86_64.exe"
$releaseTemplate = Join-Path $templateDir "windows_release_x86_64.exe"
if ((Test-Path $debugTemplate) -and (Test-Path $releaseTemplate)) {
Write-Host "✅ Required Windows templates found"
} else {
Write-Host "❌ Required Windows templates missing"
exit 1
}
} else {
Write-Host "❌ Export template directory not found!"
exit 1
}
# Check if rcedit is available (it's already in the project)
Write-Host "Checking for rcedit..."
if (Test-Path "rcedit-x64.exe") {
Write-Host "✅ rcedit found in project directory"
} else {
Write-Host "rcedit not found - downloading..."
Invoke-WebRequest -Uri "https://github.com/electron/rcedit/releases/latest/download/rcedit-x64.exe" -OutFile "rcedit-x64.exe"
Write-Host "✅ rcedit downloaded"
}
- name: Windows Build
run: .\build-windows-ci.bat
shell: cmd
- name: Check Build Output
run: |
mkdir -v -p build/windows
godot --headless --verbose --export-release "Windows Desktop" build/windows/$EXPORT_NAME.exe
Write-Host "Build directory contents:"
if (Test-Path "build\windows") {
Get-ChildItem -Path "build\windows" -Recurse | Select-Object Name, Length
} else {
Write-Host "Build directory does not exist!"
}
if (Test-Path "build\windows\PNGTuber-Plus.exe") {
Write-Host "Build SUCCESS: PNGTuber-Plus.exe created"
$fileSize = (Get-Item "build\windows\PNGTuber-Plus.exe").Length
Write-Host "File size: $fileSize bytes"
} else {
Write-Host "Build FAILED: PNGTuber-Plus.exe not found"
exit 1
}
- name: Upload Windows Build
uses: actions/upload-artifact@v4
@@ -43,9 +96,39 @@ jobs:
release:
name: Create Release
needs: export-windows
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
runs-on: self-hosted
if: github.ref == 'refs/heads/master' && github.event_name == 'push' && success()
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate Release Info
id: release_info
run: |
# Get current date and time
$date = Get-Date -Format "yyyy.MM.dd"
$time = Get-Date -Format "HHmm"
# Get short commit hash (first 7 characters)
$shortSha = "${{ github.sha }}".Substring(0, 7)
# Get commit count since last tag (for build number)
$buildNumber = & git rev-list --count HEAD
# Create version-like tag and release name
$tag = "v$date-build$buildNumber"
$releaseName = "PNGTuber+ v$date Build $buildNumber"
Write-Host "Generated tag: $tag"
Write-Host "Generated release name: $releaseName"
# Set outputs for use in next steps
echo "tag=$tag" >> $env:GITHUB_OUTPUT
echo "release_name=$releaseName" >> $env:GITHUB_OUTPUT
echo "short_sha=$shortSha" >> $env:GITHUB_OUTPUT
echo "build_number=$buildNumber" >> $env:GITHUB_OUTPUT
- name: Download Windows Build
uses: actions/download-artifact@v4
with:
@@ -58,21 +141,19 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: build-${{ github.sha }}
release_name: PNGTuber Plus Build ${{ github.sha }}
tag_name: ${{ steps.release_info.outputs.tag }}
release_name: ${{ steps.release_info.outputs.release_name }}
body: |
Automated build of PNGTuber Plus
## Recent Updates by Litruv
- **StreamDeck Integration**: Add buttons to enable the streamdeck plugin that was built in
- **Rotation Wobble**: New sprite rotation effects with frequency and amplitude controls
- **Enhanced Modifier Keys**: Support for complex key combinations (Ctrl+Shift+Alt+Cmd)
- **Godot 4.4.1 Support**: Updated for latest Godot stable release
## Installation
1. Download PNGTuber-Plus.exe from the assets below
2. Run the executable - no installation required!
3. For StreamDeck integration, download the plugin from [here](https://github.com/BoyneGames/streamdeck-godot-plugin/releases/tag/1.0.0)
## Credits
- Original project by [kaiakairos](https://github.com/kaiakairos/PNGTuber-Plus)
- Microphone improvements by [k0ffinz](https://github.com/k0ffinz/PNGTuber-Plus)
draft: false
prerelease: false

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@
.export/
.itchio/
.steam/
build/

33
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch PNGTuber Plus (Godot)",
"type": "godot",
"request": "launch",
"port": 6007,
"address": "127.0.0.1"
},
{
"name": "Attach to Running Godot",
"type": "godot",
"request": "attach",
"port": 6007,
"address": "127.0.0.1"
},
{
"name": "Launch Built Executable",
"type": "PowerShell",
"request": "launch",
"script": "if (Test-Path '${workspaceFolder}\\build\\windows\\PNGTuber-Plus.exe') { Start-Process '${workspaceFolder}\\build\\windows\\PNGTuber-Plus.exe' } else { Write-Host 'Executable not found. Build the project first.' }",
"cwd": "${workspaceFolder}"
},
{
"name": "Build and Launch",
"type": "PowerShell",
"request": "launch",
"script": ".\\build-windows.bat; if (Test-Path '.\\build\\windows\\PNGTuber-Plus.exe') { Start-Process '.\\build\\windows\\PNGTuber-Plus.exe' }",
"cwd": "${workspaceFolder}"
}
]
}

121
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,121 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Windows (Local)",
"type": "shell",
"command": ".\\build-windows.bat",
"group": {
"kind": "build",
"isDefault": true
},
"args": [],
"isBackground": false,
"problemMatcher": [],
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"detail": "Build Windows executable using local build script with template management"
},
{
"label": "Build Windows (CI)",
"type": "shell",
"command": ".\\build-windows-ci.bat",
"group": "build",
"args": [],
"isBackground": false,
"problemMatcher": [],
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"detail": "Build Windows executable using CI build script (no template download)"
},
{
"label": "Export Windows (Godot Direct)",
"type": "shell",
"command": "D:\\Godot\\Godot_v4.4.1-stable_win64.exe",
"group": "build",
"args": [
"--headless",
"--export-release",
"\"Windows Desktop\"",
"\"build/windows/PNGTuber-Plus.exe\""
],
"isBackground": false,
"problemMatcher": [],
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"detail": "Export Windows build directly using Godot (requires templates already installed)"
},
{
"label": "Clean Build Directory",
"type": "shell",
"command": "if (Test-Path 'build') { Remove-Item -Recurse -Force 'build' }; Write-Host 'Build directory cleaned'",
"group": "build",
"args": [],
"isBackground": false,
"problemMatcher": [],
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"detail": "Clean the build output directory"
},
{
"label": "Open Build Directory",
"type": "shell",
"command": "if (Test-Path 'build\\windows') { explorer 'build\\windows' } else { Write-Host 'Build directory does not exist. Run a build first.' }",
"group": "build",
"args": [],
"isBackground": false,
"problemMatcher": [],
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"detail": "Open the Windows build output directory in Explorer"
},
{
"label": "Run Built Executable",
"type": "shell",
"command": "if (Test-Path 'build\\windows\\PNGTuber-Plus.exe') { Start-Process 'build\\windows\\PNGTuber-Plus.exe' } else { Write-Host 'Executable not found. Build the project first.' }",
"group": "test",
"args": [],
"isBackground": true,
"problemMatcher": [],
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"detail": "Run the built Windows executable for testing"
}
]
}

View File

@@ -8,9 +8,10 @@
- **Rotation Wobble**: New sprite rotation effects with frequency and amplitude controls
- **Enhanced Modifier Keys**: Support for complex key combinations (Ctrl+Shift+Alt+Cmd)
- **Godot 4.4.1 Support**: Updated for latest Godot stable release
- **Microphone Improvements**: Audio delay fix & more *from [k0ffinz/PNGTuber-Plus](https://github.com/k0ffinz/PNGTuber-Plus)*
## 🙏 Credits
- **Original Project**: PNGTuber Plus base application
- **Original Project**: [PNGTuber Plus by kaiakairos](https://github.com/kaiakairos/PNGTuber-Plus)
- **StreamDeck Plugin**: Based on [BoyneGames StreamDeck Godot Plugin](https://github.com/BoyneGames/streamdeck-godot-plugin)
- **Enhanced Features**: Max Litruv Boonzaayer
- **Microphone Improvements**: k0ffinz - Experimental mic loudness detection, improved audio initialization, and audio delay fixes from [k0ffinz/PNGTuber-Plus](https://github.com/k0ffinz/PNGTuber-Plus)

View File

@@ -29,13 +29,13 @@ var blink = false
var blinkTick = 0
#Audio Listener
var currentMicrophone = null
var playa:AudioStreamPlayer
var speaking = false
var spectrum
var volume = 0
var volumeSensitivity = 0.0
var experimentalMicLoudness = false
var volumeLimit = 0.0
var senseLimit = 0.0
@@ -44,8 +44,6 @@ var senseLimit = 0.0
signal startSpeaking
signal stopSpeaking
var micResetTime = 180
var updatePusherNode = null
var rand = RandomNumberGenerator.new()
@@ -56,28 +54,23 @@ func _ready():
if !Saving.settings.has("useStreamDeck"):
Saving.settings["useStreamDeck"] = false
if Saving.settings.has("secondsToMicReset"):
Global.micResetTime = Saving.settings["secondsToMicReset"]
if Saving.settings.has("experimentalMicLoudness"):
Global.experimentalMicLoudness = Saving.settings["experimentalMicLoudness"]
else:
Saving.settings["secondsToMicReset"] = 180
Saving.settings["experimentalMicLoudness"] = false
createMicrophone()
func createMicrophone():
var playa = AudioStreamPlayer.new()
var mic = AudioStreamMicrophone.new()
playa.stream = mic
playa.autoplay = true
if playa != null:
remove_child(playa)
playa.free()
playa = AudioStreamPlayer.new()
playa.bus = "MIC"
playa.stream = AudioStreamMicrophone.new()
add_child(playa)
currentMicrophone = playa
await get_tree().create_timer(micResetTime).timeout
if currentMicrophone != playa:
return
deleteAllMics()
currentMicrophone = null
await get_tree().create_timer(0.25).timeout
createMicrophone()
await get_tree().create_timer(0.25).timeout # apparently it works to fix WASAPI "Initialize failed with error 0xffffffff88890002" and "init_input_device" errors
playa.play()
func deleteAllMics():
for child in get_children():
@@ -87,8 +80,9 @@ func deleteAllMics():
func _process(delta):
animationTick += 1
volume = spectrum.get_magnitude_for_frequency_range(20, 20000).length()
if currentMicrophone != null:
volume = (AudioServer.get_bus_peak_volume_left_db(1, 0) + AudioServer.get_bus_peak_volume_right_db(1, 0)) / 1600.0 + 0.25 if experimentalMicLoudness else spectrum.get_magnitude_for_frequency_range(20, 20000).length()
if playa != null:
volumeSensitivity = lerp(volumeSensitivity,0.0,delta*2)
if volume>volumeLimit:

View File

@@ -54,13 +54,13 @@ var settings = {
"bounce":250,
"gravity":1000,
"maxFPS":60,
"secondsToMicReset":180,
"backgroundColor":var_to_str(Color(0.0,0.0,0.0,0.0)),
"filtering":false,
"costumeKeys":["1","2","3","4","5","6","7","8","9","0"],
"blinkSpeed":1.0,
"blinkChance":200,
"bounceOnCostumeChange":false,
"experimentalMicLoudness":false,
}
var settingsPath = "user://settings.pngtp"

40
build-windows-ci.bat Normal file
View File

@@ -0,0 +1,40 @@
@echo off
setlocal
echo Building PNGTuber Plus for Windows (CI Environment)...
rem Create build directory
if not exist "build\windows" mkdir "build\windows"
rem Templates should already be installed by the GitHub Actions workflow
set TEMPLATE_DIR=C:\WINDOWS\ServiceProfiles\NetworkService\AppData\Roaming\Godot\export_templates\4.4.1.stable
echo Checking for export templates at: %TEMPLATE_DIR%
if exist "%TEMPLATE_DIR%" (
echo Export templates found.
dir "%TEMPLATE_DIR%"
) else (
echo ERROR: Export templates not found at %TEMPLATE_DIR%
echo This should have been handled by the GitHub Actions setup step.
exit /b 1
)
rem Build the project
echo Running Godot export...
"D:\Godot\Godot_v4.4.1-stable_win64.exe" --headless --export-release "Windows Desktop" "build\windows\PNGTuber-Plus.exe"
if %ERRORLEVEL% EQU 0 (
echo.
echo Build completed successfully!
echo Output: build\windows\PNGTuber-Plus.exe
if exist "build\windows\PNGTuber-Plus.exe" (
echo File size:
dir "build\windows\PNGTuber-Plus.exe"
)
echo.
) else (
echo.
echo Build failed with error code %ERRORLEVEL%
echo.
exit /b %ERRORLEVEL%
)

View File

@@ -1,22 +1,49 @@
@echo off
setlocal
echo Building PNGTuber Plus for Windows...
:: Create build directory
rem Create build directory
if not exist "build\windows" mkdir "build\windows"
:: Build the project
rem Install export templates if they don't exist
echo Checking for export templates...
set TEMPLATE_DIR=%APPDATA%\Godot\export_templates\4.4.1.stable
if not exist "%TEMPLATE_DIR%" (
echo Export templates not found. Installing...
"D:\Godot\Godot_v4.4.1-stable_win64.exe" --headless --export-pack
timeout /t 5 /nobreak >nul
rem Download templates if the export-pack didn't work
if not exist "%TEMPLATE_DIR%" (
echo Downloading export templates...
powershell -Command "& {Invoke-WebRequest -Uri 'https://github.com/godotengine/godot/releases/download/4.4.1-stable/Godot_v4.4.1-stable_export_templates.tpz' -OutFile 'templates.tpz'}"
rem Rename and extract templates
powershell -Command "& {Rename-Item 'templates.tpz' 'templates.zip'}"
powershell -Command "& {Expand-Archive -Path 'templates.zip' -DestinationPath 'temp_templates' -Force}"
if not exist "%APPDATA%\Godot\export_templates" mkdir "%APPDATA%\Godot\export_templates"
move "temp_templates\templates" "%TEMPLATE_DIR%"
rmdir /s /q "temp_templates"
del "templates.zip"
echo Export templates installed.
)
) else (
echo Export templates found.
)
rem Build the project
echo Running Godot export...
godot --headless --verbose --export-release "Windows Desktop" "build\windows\PNGTuber-Plus.exe"
"D:\Godot\Godot_v4.4.1-stable_win64.exe" --headless --export-release "Windows Desktop" "build\windows\PNGTuber-Plus.exe"
if %ERRORLEVEL% EQU 0 (
echo.
echo Build completed successfully!
echo Build completed successfully!
echo Output: build\windows\PNGTuber-Plus.exe
echo.
pause
) else (
echo.
echo Build failed with error code %ERRORLEVEL%
echo Build failed with error code %ERRORLEVEL%
echo.
pause
)

View File

@@ -3,27 +3,29 @@
name="Windows Desktop"
platform="Windows Desktop"
runnable=true
advanced_options=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=".export/release 1.4.5/steam/PNGTUBER PLUS 1.4.5 STEAM.exe"
exclude_filter="addons/godot-git-plugin/*"
export_path="build/windows/PNGTuber-Plus.exe"
patches=PackedStringArray()
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.0.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=false
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
debug/export_console_wrapper=2
binary_format/embed_pck=true
texture_format/s3tc_bptc=true
texture_format/etc2_astc=false
binary_format/architecture="x86_64"
codesign/enable=false
codesign/timestamp=true
@@ -42,6 +44,9 @@ application/product_name="PNGTuber Plus"
application/file_description=""
application/copyright=""
application/trademarks=""
application/export_angle=0
application/export_d3d12=0
application/d3d12_agility_sdk_multiarch=true
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
@@ -59,22 +64,30 @@ Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorActi
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
[preset.1]
name="Linux/X11"
platform="Linux/X11"
platform="Linux"
runnable=true
advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=".export/release 1.4.5/linux/PNGTUBER PLUS 1.4.5 LINUX.x86_64"
patches=PackedStringArray()
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.1.options]
@@ -82,10 +95,8 @@ custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=false
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
texture_format/s3tc_bptc=true
texture_format/etc2_astc=false
binary_format/architecture="x86_64"
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
@@ -99,22 +110,30 @@ unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
[preset.2]
name="macOS"
platform="macOS"
runnable=true
advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=".export/release 1.4.5/mac/PNGTUBER PLUS 1.4.5 MAC.zip"
patches=PackedStringArray()
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.2.options]
@@ -132,8 +151,11 @@ application/short_version="1.4.5"
application/version="1.4.5"
application/copyright=""
application/copyright_localized={}
application/min_macos_version="10.12"
application/min_macos_version_x86_64="10.12"
application/min_macos_version_arm64="11.00"
application/export_angle=0
display/high_res=true
application/additional_plist_content=""
xcode/platform_build="14C18"
xcode/sdk_version="13.1"
xcode/sdk_build="22C55"
@@ -166,7 +188,9 @@ codesign/entitlements/app_sandbox/files_downloads=0
codesign/entitlements/app_sandbox/files_pictures=0
codesign/entitlements/app_sandbox/files_music=0
codesign/entitlements/app_sandbox/files_movies=0
codesign/entitlements/app_sandbox/files_user_selected=0
codesign/entitlements/app_sandbox/helper_executables=[]
codesign/entitlements/additional=""
codesign/custom_options=PackedStringArray()
notarization/notarization=0
privacy/microphone_usage_description="So the guy can go up and down!"
@@ -191,6 +215,148 @@ privacy/network_volumes_usage_description=""
privacy/network_volumes_usage_description_localized={}
privacy/removable_volumes_usage_description=""
privacy/removable_volumes_usage_description_localized={}
privacy/tracking_enabled=false
privacy/tracking_domains=PackedStringArray()
privacy/collected_data/name/collected=false
privacy/collected_data/name/linked_to_user=false
privacy/collected_data/name/used_for_tracking=false
privacy/collected_data/name/collection_purposes=0
privacy/collected_data/email_address/collected=false
privacy/collected_data/email_address/linked_to_user=false
privacy/collected_data/email_address/used_for_tracking=false
privacy/collected_data/email_address/collection_purposes=0
privacy/collected_data/phone_number/collected=false
privacy/collected_data/phone_number/linked_to_user=false
privacy/collected_data/phone_number/used_for_tracking=false
privacy/collected_data/phone_number/collection_purposes=0
privacy/collected_data/physical_address/collected=false
privacy/collected_data/physical_address/linked_to_user=false
privacy/collected_data/physical_address/used_for_tracking=false
privacy/collected_data/physical_address/collection_purposes=0
privacy/collected_data/other_contact_info/collected=false
privacy/collected_data/other_contact_info/linked_to_user=false
privacy/collected_data/other_contact_info/used_for_tracking=false
privacy/collected_data/other_contact_info/collection_purposes=0
privacy/collected_data/health/collected=false
privacy/collected_data/health/linked_to_user=false
privacy/collected_data/health/used_for_tracking=false
privacy/collected_data/health/collection_purposes=0
privacy/collected_data/fitness/collected=false
privacy/collected_data/fitness/linked_to_user=false
privacy/collected_data/fitness/used_for_tracking=false
privacy/collected_data/fitness/collection_purposes=0
privacy/collected_data/payment_info/collected=false
privacy/collected_data/payment_info/linked_to_user=false
privacy/collected_data/payment_info/used_for_tracking=false
privacy/collected_data/payment_info/collection_purposes=0
privacy/collected_data/credit_info/collected=false
privacy/collected_data/credit_info/linked_to_user=false
privacy/collected_data/credit_info/used_for_tracking=false
privacy/collected_data/credit_info/collection_purposes=0
privacy/collected_data/other_financial_info/collected=false
privacy/collected_data/other_financial_info/linked_to_user=false
privacy/collected_data/other_financial_info/used_for_tracking=false
privacy/collected_data/other_financial_info/collection_purposes=0
privacy/collected_data/precise_location/collected=false
privacy/collected_data/precise_location/linked_to_user=false
privacy/collected_data/precise_location/used_for_tracking=false
privacy/collected_data/precise_location/collection_purposes=0
privacy/collected_data/coarse_location/collected=false
privacy/collected_data/coarse_location/linked_to_user=false
privacy/collected_data/coarse_location/used_for_tracking=false
privacy/collected_data/coarse_location/collection_purposes=0
privacy/collected_data/sensitive_info/collected=false
privacy/collected_data/sensitive_info/linked_to_user=false
privacy/collected_data/sensitive_info/used_for_tracking=false
privacy/collected_data/sensitive_info/collection_purposes=0
privacy/collected_data/contacts/collected=false
privacy/collected_data/contacts/linked_to_user=false
privacy/collected_data/contacts/used_for_tracking=false
privacy/collected_data/contacts/collection_purposes=0
privacy/collected_data/emails_or_text_messages/collected=false
privacy/collected_data/emails_or_text_messages/linked_to_user=false
privacy/collected_data/emails_or_text_messages/used_for_tracking=false
privacy/collected_data/emails_or_text_messages/collection_purposes=0
privacy/collected_data/photos_or_videos/collected=false
privacy/collected_data/photos_or_videos/linked_to_user=false
privacy/collected_data/photos_or_videos/used_for_tracking=false
privacy/collected_data/photos_or_videos/collection_purposes=0
privacy/collected_data/audio_data/collected=false
privacy/collected_data/audio_data/linked_to_user=false
privacy/collected_data/audio_data/used_for_tracking=false
privacy/collected_data/audio_data/collection_purposes=0
privacy/collected_data/gameplay_content/collected=false
privacy/collected_data/gameplay_content/linked_to_user=false
privacy/collected_data/gameplay_content/used_for_tracking=false
privacy/collected_data/gameplay_content/collection_purposes=0
privacy/collected_data/customer_support/collected=false
privacy/collected_data/customer_support/linked_to_user=false
privacy/collected_data/customer_support/used_for_tracking=false
privacy/collected_data/customer_support/collection_purposes=0
privacy/collected_data/other_user_content/collected=false
privacy/collected_data/other_user_content/linked_to_user=false
privacy/collected_data/other_user_content/used_for_tracking=false
privacy/collected_data/other_user_content/collection_purposes=0
privacy/collected_data/browsing_history/collected=false
privacy/collected_data/browsing_history/linked_to_user=false
privacy/collected_data/browsing_history/used_for_tracking=false
privacy/collected_data/browsing_history/collection_purposes=0
privacy/collected_data/search_hhistory/collected=false
privacy/collected_data/search_hhistory/linked_to_user=false
privacy/collected_data/search_hhistory/used_for_tracking=false
privacy/collected_data/search_hhistory/collection_purposes=0
privacy/collected_data/user_id/collected=false
privacy/collected_data/user_id/linked_to_user=false
privacy/collected_data/user_id/used_for_tracking=false
privacy/collected_data/user_id/collection_purposes=0
privacy/collected_data/device_id/collected=false
privacy/collected_data/device_id/linked_to_user=false
privacy/collected_data/device_id/used_for_tracking=false
privacy/collected_data/device_id/collection_purposes=0
privacy/collected_data/purchase_history/collected=false
privacy/collected_data/purchase_history/linked_to_user=false
privacy/collected_data/purchase_history/used_for_tracking=false
privacy/collected_data/purchase_history/collection_purposes=0
privacy/collected_data/product_interaction/collected=false
privacy/collected_data/product_interaction/linked_to_user=false
privacy/collected_data/product_interaction/used_for_tracking=false
privacy/collected_data/product_interaction/collection_purposes=0
privacy/collected_data/advertising_data/collected=false
privacy/collected_data/advertising_data/linked_to_user=false
privacy/collected_data/advertising_data/used_for_tracking=false
privacy/collected_data/advertising_data/collection_purposes=0
privacy/collected_data/other_usage_data/collected=false
privacy/collected_data/other_usage_data/linked_to_user=false
privacy/collected_data/other_usage_data/used_for_tracking=false
privacy/collected_data/other_usage_data/collection_purposes=0
privacy/collected_data/crash_data/collected=false
privacy/collected_data/crash_data/linked_to_user=false
privacy/collected_data/crash_data/used_for_tracking=false
privacy/collected_data/crash_data/collection_purposes=0
privacy/collected_data/performance_data/collected=false
privacy/collected_data/performance_data/linked_to_user=false
privacy/collected_data/performance_data/used_for_tracking=false
privacy/collected_data/performance_data/collection_purposes=0
privacy/collected_data/other_diagnostic_data/collected=false
privacy/collected_data/other_diagnostic_data/linked_to_user=false
privacy/collected_data/other_diagnostic_data/used_for_tracking=false
privacy/collected_data/other_diagnostic_data/collection_purposes=0
privacy/collected_data/environment_scanning/collected=false
privacy/collected_data/environment_scanning/linked_to_user=false
privacy/collected_data/environment_scanning/used_for_tracking=false
privacy/collected_data/environment_scanning/collection_purposes=0
privacy/collected_data/hands/collected=false
privacy/collected_data/hands/linked_to_user=false
privacy/collected_data/hands/used_for_tracking=false
privacy/collected_data/hands/collection_purposes=0
privacy/collected_data/head/collected=false
privacy/collected_data/head/linked_to_user=false
privacy/collected_data/head/used_for_tracking=false
privacy/collected_data/head/collection_purposes=0
privacy/collected_data/other_data_types/collected=false
privacy/collected_data/other_data_types/linked_to_user=false
privacy/collected_data/other_data_types/used_for_tracking=false
privacy/collected_data/other_data_types/collection_purposes=0
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
@@ -202,3 +368,71 @@ open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}"
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""
application/min_macos_version="10.12"
[preset.3]
name="Windows Desktop 2"
platform="Windows Desktop"
runnable=false
advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
patches=PackedStringArray()
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.3.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=false
texture_format/s3tc_bptc=true
texture_format/etc2_astc=false
binary_format/architecture="x86_64"
codesign/enable=false
codesign/timestamp=true
codesign/timestamp_server_url=""
codesign/digest_algorithm=1
codesign/description=""
codesign/custom_options=PackedStringArray()
application/modify_resources=true
application/icon=""
application/console_wrapper_icon=""
application/icon_interpolation=4
application/file_version=""
application/product_version=""
application/company_name=""
application/product_name=""
application/file_description=""
application/copyright=""
application/trademarks=""
application/export_angle=0
application/export_d3d12=0
application/d3d12_agility_sdk_multiarch=true
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
$trigger = New-ScheduledTaskTrigger -Once -At 00:00
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
Start-ScheduledTask -TaskName godot_remote_debug
while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"

View File

@@ -30,6 +30,7 @@ var editMode = true
@onready var spriteObject = preload("res://ui_scenes/selectedSprite/spriteObject.tscn")
var saveLoaded = false
var isSelectingMask = false
#Motion
var yVel = 0
@@ -62,7 +63,9 @@ func _ready():
Global.connect("startSpeaking",onSpeak)
ElgatoStreamDeck.on_key_down.connect(changeCostumeStreamDeck)
var streamdeck_node = get_node_or_null("/root/ElgatoStreamDeck")
if streamdeck_node:
streamdeck_node.on_key_down.connect(changeCostumeStreamDeck)
if Saving.settings["newUser"]:
_on_load_dialog_file_selected("default")
@@ -153,6 +156,9 @@ func _process(delta):
followShadow()
func followShadow():
shadow.visible = false # Disabled drop shadow
return
shadow.visible = is_instance_valid(Global.heldSprite)
if !shadow.visible:
return
@@ -171,6 +177,9 @@ func isFileSystemOpen():
if obj.visible:
if obj == replaceDialog:
return true
# Don't clear held sprite when selecting mask
if obj == fileDialog and isSelectingMask:
return true
Global.heldSprite = null
return true
return false
@@ -288,7 +297,20 @@ func _on_add_button_pressed():
#Runs when selecting image in File Dialog
func _on_file_dialog_file_selected(path):
add_image(path)
if isSelectingMask:
# Handle mask selection
if Global.heldSprite != null:
Global.heldSprite.setMaskTexture(path)
Global.spriteEdit.updateMaskDisplay(path)
isSelectingMask = false
else:
# Handle normal sprite addition
add_image(path)
#Opens File Dialog for mask selection
func openMaskSelection():
isSelectingMask = true
fileDialog.visible = true
func _on_save_button_pressed():
$SaveDialog.visible = true
@@ -363,6 +385,14 @@ func _on_load_dialog_file_selected(path):
if data[item].has("toggle"):
sprite.toggle = data[item]["toggle"]
# Load mask properties
if data[item].has("mask_texture_path"):
sprite.mask_texture_path = data[item]["mask_texture_path"]
if data[item].has("use_mask"):
sprite.use_mask = data[item]["use_mask"]
if data[item].has("mask_opacity"):
sprite.mask_opacity = data[item]["mask_opacity"]
origin.add_child(sprite)
sprite.position = str_to_var(data[item]["pos"])
@@ -424,6 +454,11 @@ func _on_save_dialog_file_selected(path):
data[id]["toggle"] = child.toggle
# Save mask properties
data[id]["mask_texture_path"] = child.mask_texture_path
data[id]["use_mask"] = child.use_mask
data[id]["mask_opacity"] = child.mask_opacity
id += 1
Saving.settings["lastAvatar"] = path
@@ -445,9 +480,9 @@ func _on_kofi_pressed():
Global.pushUpdate("Support me on ko-fi!")
func _on_twitter_pressed():
OS.shell_open("https://twitter.com/kaiakairos")
Global.pushUpdate("Follow me on twitter!")
func _on_bluesky_pressed():
OS.shell_open("https://bsky.app/profile/kaiakairos.net")
Global.pushUpdate("Follow me on bluesky!")
func _on_replace_button_pressed():
@@ -547,7 +582,7 @@ func moveSpriteMenu(delta):
var size = get_viewport().get_visible_rect().size
var windowLength = 1400
var windowLength = 1800
$ViewerArrows/Arrows.position.y = size.y - 25
@@ -604,7 +639,7 @@ func _on_background_input_capture_bg_key_pressed(node, keys_pressed):
var has_ctrl = keys_pressed.has(KEY_CTRL) and keys_pressed[KEY_CTRL]
var has_shift = keys_pressed.has(KEY_SHIFT) and keys_pressed[KEY_SHIFT]
var has_alt = keys_pressed.has(KEY_ALT) and keys_pressed[KEY_ALT]
var has_meta = keys_pressed.has(KEY_META) and keys_pressed[KEY_META] # Command key on macOS
var meta_pressed = keys_pressed.has(KEY_META) and keys_pressed[KEY_META] # Command key on macOS
# Build modifier prefix once
if has_ctrl:
@@ -613,7 +648,7 @@ func _on_background_input_capture_bg_key_pressed(node, keys_pressed):
modifiers.append("Shift")
if has_alt:
modifiers.append("Alt")
if has_meta:
if meta_pressed:
modifiers.append("Cmd") # Command key on macOS
var modifier_prefix = ""

View File

@@ -14341,7 +14341,7 @@ offset_bottom = 27.0
theme = SubResource("Theme_rv56a")
flat = true
[node name="twitter" type="Button" parent="ControlPanel/Links"]
[node name="bluesky" type="Button" parent="ControlPanel/Links"]
offset_left = -5.0
offset_top = -29.0
offset_right = 61.0
@@ -14730,7 +14730,7 @@ z_index = -4096
[connection signal="pressed" from="ControlPanel/SettingsButton/settingsButtons" to="." method="_on_settings_buttons_pressed"]
[connection signal="pressed" from="ControlPanel/Edit/Button" to="." method="swapMode"]
[connection signal="pressed" from="ControlPanel/Links/kofi" to="." method="_on_kofi_pressed"]
[connection signal="pressed" from="ControlPanel/Links/twitter" to="." method="_on_twitter_pressed"]
[connection signal="pressed" from="ControlPanel/Links/bluesky" to="." method="_on_bluesky_pressed"]
[connection signal="pressed" from="EditControls/Add/addButton" to="." method="_on_add_button_pressed"]
[connection signal="pressed" from="EditControls/Link/linkButton" to="." method="_on_link_button_pressed"]
[connection signal="pressed" from="EditControls/Exit/Button2" to="." method="swapMode"]

View File

@@ -23,6 +23,7 @@ config/icon="res://icon.png"
[audio]
driver/enable_input=true
buses/channel_disable_time=0.0
[autoload]
@@ -147,4 +148,6 @@ textures/canvas_textures/default_texture_filter=0
textures/canvas_textures/default_texture_repeat=1
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"
shading/overrides/force_vertex_shading=true
shading/overrides/force_lambert_over_burley=true
environment/defaults/default_clear_color=Color(0.376471, 0.376471, 0.376471, 1)

View File

@@ -1,11 +1,21 @@
shader_type canvas_item;
uniform sampler2D noise_texture:repeat_enable;
uniform float distortion_strengh: hint_range(0, 0.1) = 1.0;
uniform sampler2D noise_texture: source_color, repeat_enable;
uniform float distortion_strengh: hint_range(0, 0.1) = 0.01;
uniform float speed: hint_range(0.1, 10) = 1.0;
uniform bool use_noise_texture: hint_default_true = false;
void fragment() {
vec4 noise_pixel = texture(noise_texture, UV + floor(TIME*speed)/3.0);
vec2 uv_offset = (noise_pixel.rg * 2.0 - 1.0) * distortion_strengh;
vec2 uv_offset = vec2(0.0);
if (use_noise_texture) {
vec4 noise_pixel = texture(noise_texture, UV + floor(TIME * speed) / 3.0);
uv_offset = (noise_pixel.rg * 2.0 - 1.0) * distortion_strengh;
} else {
// Fallback procedural noise when no texture is provided
float noise = sin(UV.x * 20.0 + TIME * speed) * cos(UV.y * 20.0 + TIME * speed * 0.7);
uv_offset = vec2(noise) * distortion_strengh;
}
COLOR = texture(TEXTURE, UV + uv_offset);
}

View File

@@ -1 +1 @@
uid://b342og0l0k1p
uid://4a1uhohwy43l

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -7,17 +7,11 @@ func _ready():
func _on_button_pressed():
if !get_parent().get_parent().get_parent().visible:
return
AudioServer.input_device = micName
Global.deleteAllMics()
Global.currentMicrophone = null
Global.createMicrophone()
get_parent().get_parent().get_parent().visible = false
await get_tree().create_timer(1.0).timeout
Global.createMicrophone()

View File

@@ -0,0 +1,23 @@
shader_type canvas_item;
uniform sampler2D mask_texture : source_color;
uniform bool use_mask = false;
uniform float mask_opacity : hint_range(0.0, 1.0) = 1.0;
void fragment() {
// Get the original sprite color
vec4 sprite_color = texture(TEXTURE, UV);
if (use_mask) {
// Sample the mask texture
vec4 mask_sample = texture(mask_texture, UV);
// Use the mask's alpha channel to determine visibility
float mask_alpha = mask_sample.a * mask_opacity;
// Apply the mask by multiplying the sprite's alpha with the mask alpha
sprite_color.a *= mask_alpha;
}
COLOR = sprite_color;
}

View File

@@ -0,0 +1 @@
uid://btd72itp0cy6b

View File

@@ -1,17 +1,8 @@
shader_type canvas_item;
uniform float speed;
uniform sampler2D backImg: repeat_enable;
uniform sampler2D palette;
uniform float palette_speed = 0.1;
uniform vec4 outline_color : source_color = vec4(1.0, 0.0, 0.0, 0.3);
void fragment(){
vec2 scroll = vec2(1.0,0.0) * TIME * speed;
vec4 tex = texture(TEXTURE, (UV));
float palette_swap = mod(tex.r - TIME * palette_speed, 1.0);
COLOR = vec4(texture(palette, vec2(palette_swap, 0)).rgb, tex.a);
vec4 tex = texture(TEXTURE, UV);
COLOR = vec4(outline_color.rgb, tex.a * outline_color.a);
}

View File

@@ -77,6 +77,12 @@ var ignoreBounce = false
var frames = 1
var animSpeed = 0
#Masking
var mask_texture_path = ""
var mask_texture = null
var use_mask = false
var mask_opacity = 1.0
var remadePolygon = false
var clipped = false
@@ -119,6 +125,9 @@ func _ready():
sprite.texture = tex
# Initialize masking
setupMasking()
var bitmap = BitMap.new()
bitmap.create_from_image_alpha(imageData)
@@ -409,3 +418,53 @@ func visToggle(keys):
func makeVis():
$WobbleOrigin/DragOrigin.visible = true
## Setup masking system
func setupMasking():
if use_mask and mask_texture_path != "":
loadMaskTexture()
updateMaskShader()
## Load mask texture from file path
func loadMaskTexture():
if mask_texture_path == "":
return
var img = Image.new()
var err = img.load(mask_texture_path)
if err != OK:
print_debug("Failed to load mask texture: " + mask_texture_path)
return
mask_texture = ImageTexture.create_from_image(img)
## Apply or remove mask shader
func updateMaskShader():
if use_mask and mask_texture != null:
# Create mask material with shader
var mask_shader = load("res://ui_scenes/selectedSprite/mask.gdshader")
var mask_material = ShaderMaterial.new()
mask_material.shader = mask_shader
mask_material.set_shader_parameter("mask_texture", mask_texture)
mask_material.set_shader_parameter("use_mask", true)
mask_material.set_shader_parameter("mask_opacity", mask_opacity)
sprite.material = mask_material
else:
# Remove mask material
sprite.material = null
## Set mask texture from external source
func setMaskTexture(texture_path: String, opacity: float = 1.0):
mask_texture_path = texture_path
mask_opacity = opacity
use_mask = true
loadMaskTexture()
updateMaskShader()
## Remove masking
func removeMask():
use_mask = false
mask_texture = null
mask_texture_path = ""
updateMaskShader()

View File

@@ -46,6 +46,8 @@ func setvalues():
label.text = "costume " + str(tag) + " key: \"" + Global.main.costumeKeys[tag-1] + "\""
tag += 1
$experimentalMicLoudness/checkmark.button_pressed = Global.experimentalMicLoudness
func _on_color_picker_button_color_changed(color):
get_viewport().transparent_bg = false
RenderingServer.set_default_clear_color(color)
@@ -202,10 +204,17 @@ func _on_costume_check_toggled(button_pressed):
## @param button_pressed: bool - Whether StreamDeck should be enabled
func _on_stream_deck_check_toggled(button_pressed):
Saving.settings["useStreamDeck"] = button_pressed
if ElgatoStreamDeck:
ElgatoStreamDeck.refresh_connection()
if get_node_or_null("/root/ElgatoStreamDeck"):
get_node("/root/ElgatoStreamDeck").refresh_connection()
Global.pushUpdate("StreamDeck integration " + ("enabled" if button_pressed else "disabled") + ".")
## Handle experimental microphone loudness toggle
## @param checked: bool - Whether experimental mic loudness should be enabled
func _on_experimental_mic_loudness_toggle(checked):
Global.experimentalMicLoudness = checked
Saving.settings["experimentalMicLoudness"] = checked
print("Experimental mic loudness: ", checked)
func _process(delta):
var g = to_local(get_global_mouse_position())

View File

@@ -14289,46 +14289,67 @@ offset_bottom = 28.0
text = "confirm"
[node name="StreamDeck" type="Node2D" parent="."]
position = Vector2(16, 373)
position = Vector2(16, 337)
[node name="Label" type="Label" parent="StreamDeck"]
offset_right = 138.0
offset_bottom = 34.0
text = "use streamdeck"
metadata/_edit_use_anchors_ = true
[node name="streamDeckCheck" type="CheckBox" parent="StreamDeck"]
offset_left = 130.0
offset_top = 1.0
offset_right = 154.0
offset_bottom = 25.0
metadata/_edit_use_anchors_ = true
[node name="experimentalMicLoudness" type="Node2D" parent="."]
position = Vector2(16, 369)
[node name="Label" type="Label" parent="experimentalMicLoudness"]
offset_right = 200.0
offset_bottom = 34.0
text = "mic loudness"
[node name="checkmark" type="CheckBox" parent="experimentalMicLoudness"]
offset_left = 130.0
offset_top = 1.0
offset_right = 154.0
offset_bottom = 25.0
metadata/_edit_use_anchors_ = true
[node name="AntiAliasing" type="Node2D" parent="."]
position = Vector2(16, 405)
position = Vector2(16, 401)
[node name="Label" type="Label" parent="AntiAliasing"]
offset_right = 138.0
offset_bottom = 34.0
text = "texture filtering"
metadata/_edit_use_anchors_ = true
[node name="CheckBox" type="CheckBox" parent="AntiAliasing"]
offset_left = 130.0
offset_top = 1.0
offset_right = 154.0
offset_bottom = 25.0
metadata/_edit_use_anchors_ = true
[node name="bounceOnCostume" type="Node2D" parent="."]
position = Vector2(17, 341)
position = Vector2(17, 305)
[node name="Label" type="Label" parent="bounceOnCostume"]
offset_right = 138.0
offset_bottom = 34.0
text = "costume bounce"
metadata/_edit_use_anchors_ = true
[node name="costumeCheck" type="CheckBox" parent="bounceOnCostume"]
offset_left = 130.0
offset_top = 1.0
offset_right = 154.0
offset_bottom = 25.0
metadata/_edit_use_anchors_ = true
[node name="BounceForce" type="Node2D" parent="."]
position = Vector2(22, 115)
@@ -14832,7 +14853,7 @@ offset_bottom = -75.0
text = "costume hotkeys"
[node name="BlinkSpeed" type="Node2D" parent="."]
position = Vector2(17, 283)
position = Vector2(17, 253)
[node name="Label" type="Label" parent="BlinkSpeed"]
offset_left = -10.0
@@ -14841,6 +14862,7 @@ offset_right = 158.0
offset_bottom = 27.0
text = "blink speed: 1"
horizontal_alignment = 1
metadata/_edit_use_anchors_ = true
[node name="blinkSpeed" type="HSlider" parent="BlinkSpeed"]
offset_left = -9.0
@@ -14851,9 +14873,10 @@ theme = SubResource("Theme_e6tc4")
max_value = 20.0
value = 1.0
scrollable = false
metadata/_edit_use_anchors_ = true
[node name="BlinkChance" type="Node2D" parent="."]
position = Vector2(17, 235)
position = Vector2(17, 205)
[node name="Label" type="Label" parent="BlinkChance"]
offset_left = -10.0
@@ -14862,6 +14885,7 @@ offset_right = 160.0
offset_bottom = 27.0
text = "blink chance: 1 in 200"
horizontal_alignment = 1
metadata/_edit_use_anchors_ = true
[node name="blinkChance" type="HSlider" parent="BlinkChance"]
offset_left = -8.0
@@ -14873,6 +14897,7 @@ min_value = 1.0
max_value = 300.0
value = 200.0
scrollable = false
metadata/_edit_use_anchors_ = true
[connection signal="pressed" from="Background/Transparent/Button" to="." method="_on_button_pressed"]
[connection signal="pressed" from="Background/Green/greenButton" to="." method="_on_green_button_pressed"]
@@ -14883,6 +14908,7 @@ scrollable = false
[connection signal="value_changed" from="MaxFPS/fpsDrag" to="." method="_on_fps_drag_value_changed"]
[connection signal="pressed" from="MaxFPS/confirm" to="." method="_on_confirm_pressed"]
[connection signal="toggled" from="StreamDeck/streamDeckCheck" to="." method="_on_stream_deck_check_toggled"]
[connection signal="toggled" from="experimentalMicLoudness/checkmark" to="." method="_on_experimental_mic_loudness_toggle"]
[connection signal="toggled" from="AntiAliasing/CheckBox" to="." method="_on_check_box_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"]

View File

@@ -75,6 +75,15 @@ func setImage():
$VisToggle/setToggle/Label.text = "toggle: \"" + Global.heldSprite.toggle + "\""
# Update masking controls
$Masking/useMaskCheckbox.button_pressed = Global.heldSprite.use_mask
$Masking/maskOpacityLabel.text = "mask opacity: " + str(Global.heldSprite.mask_opacity)
$Masking/maskOpacity.value = Global.heldSprite.mask_opacity
if Global.heldSprite.mask_texture_path.is_empty():
$Masking/maskPathLabel.text = "mask: (none)"
else:
$Masking/maskPathLabel.text = "mask: " + Global.heldSprite.mask_texture_path.get_file()
changeRotLimit()
setLayerButtons()
@@ -364,8 +373,25 @@ func _on_delete_pressed():
func _on_set_toggle_pressed():
$VisToggle/setToggle/Label.text = "toggle: AWAITING INPUT"
await Global.main.fatfuckingballs
var keys = await Global.main.spriteVisToggles
var key = keys[0]
Global.heldSprite.toggle = key
$VisToggle/setToggle/Label.text = "toggle: \"" + Global.heldSprite.toggle + "\""
## Masking signal handlers
func _on_use_mask_checkbox_toggled(button_pressed):
Global.heldSprite.use_mask = button_pressed
Global.heldSprite.updateMaskShader()
func _on_mask_opacity_value_changed(value):
Global.heldSprite.mask_opacity = value
$Masking/maskOpacityLabel.text = "mask opacity: " + str(value)
Global.heldSprite.updateMaskShader()
func _on_select_mask_pressed():
Global.main.openMaskSelection()
func updateMaskDisplay(path: String):
$Masking/maskPathLabel.text = "mask: " + path.get_file()
$Masking/useMaskCheckbox.button_pressed = true
func _on_clear_mask_pressed():
Global.heldSprite.removeMask()
$Masking/maskPathLabel.text = "mask: (none)"
$Masking/useMaskCheckbox.button_pressed = false

View File

@@ -29,7 +29,7 @@
[ext_resource type="Texture2D" uid="uid://gflmeocxfnrq" path="res://ui_scenes/settings/deleteHotkey.png" id="27_fgu6g"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_21kva"]
size = Vector2(245, 1341)
size = Vector2(245, 1596.5)
[sub_resource type="ShaderMaterial" id="ShaderMaterial_hxmah"]
shader = ExtResource("3_ky0lu")
@@ -14285,7 +14285,7 @@ script = ExtResource("1_hp0e3")
z_index = -2
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
position = Vector2(122.5, 670.5)
position = Vector2(122.5, 725)
shape = SubResource("RectangleShape2D_21kva")
[node name="Border" type="Sprite2D" parent="."]
@@ -14910,6 +14910,66 @@ position = Vector2(-2, -2)
texture = ExtResource("27_fgu6g")
centered = false
[node name="Masking" type="Node2D" parent="."]
position = Vector2(0, 1360.83)
[node name="animationBox" type="Sprite2D" parent="Masking"]
position = Vector2(125, 92.4052)
scale = Vector2(1, 0.905768)
texture = ExtResource("15_wqi8b")
[node name="maskingLabel" type="Label" parent="Masking"]
offset_left = 20.0
offset_right = 120.0
offset_bottom = 26.0
text = "MASKING"
horizontal_alignment = 1
[node name="useMaskCheckbox" type="CheckBox" parent="Masking"]
offset_left = 20.0
offset_top = 30.0
offset_right = 200.0
offset_bottom = 54.0
text = "Use Mask"
[node name="maskOpacityLabel" type="Label" parent="Masking"]
offset_left = 20.0
offset_top = 60.0
offset_right = 200.0
offset_bottom = 86.0
text = "mask opacity: 1.0"
[node name="maskOpacity" type="HSlider" parent="Masking"]
offset_left = 20.0
offset_top = 90.0
offset_right = 200.0
offset_bottom = 106.0
max_value = 1.0
step = 0.01
value = 1.0
[node name="maskPathLabel" type="Label" parent="Masking"]
offset_left = 20.0
offset_top = 120.0
offset_right = 400.0
offset_bottom = 146.0
text = "mask: (none)"
autowrap_mode = 2
[node name="selectMask" type="Button" parent="Masking"]
offset_left = 20.0
offset_top = 150.0
offset_right = 120.0
offset_bottom = 181.0
text = "Select Mask"
[node name="clearMask" type="Button" parent="Masking"]
offset_left = 130.0
offset_top = 150.0
offset_right = 220.0
offset_bottom = 181.0
text = "Clear Mask"
[connection signal="pressed" from="Buttons/Speaking/speaking" to="." method="_on_speaking_pressed"]
[connection signal="pressed" from="Buttons/Blinking/blinking" to="." method="_on_blinking_pressed"]
[connection signal="pressed" from="Buttons/Trash/trash" to="." method="_on_trash_pressed"]
@@ -14941,3 +15001,7 @@ centered = false
[connection signal="pressed" from="Layers/Layer10/layerButton10" to="." method="_on_layer_button_10_pressed"]
[connection signal="pressed" from="VisToggle/setToggle" to="." method="_on_set_toggle_pressed"]
[connection signal="pressed" from="VisToggle/setToggle/delete" to="." method="_on_delete_pressed"]
[connection signal="toggled" from="Masking/useMaskCheckbox" to="." method="_on_use_mask_checkbox_toggled"]
[connection signal="value_changed" from="Masking/maskOpacity" to="." method="_on_mask_opacity_value_changed"]
[connection signal="pressed" from="Masking/selectMask" to="." method="_on_select_mask_pressed"]
[connection signal="pressed" from="Masking/clearMask" to="." method="_on_clear_mask_pressed"]