pax_global_header 0000666 0000000 0000000 00000000064 14177464325 0014527 g ustar 00root root 0000000 0000000 52 comment=c64ec84fae7a5aef063ea6565b167525f89b93ba
obs-move-transition-2.5.7/ 0000775 0000000 0000000 00000000000 14177464325 0015461 5 ustar 00root root 0000000 0000000 obs-move-transition-2.5.7/.github/ 0000775 0000000 0000000 00000000000 14177464325 0017021 5 ustar 00root root 0000000 0000000 obs-move-transition-2.5.7/.github/FUNDING.yml 0000664 0000000 0000000 00000000111 14177464325 0020627 0 ustar 00root root 0000000 0000000 github: exeldro
custom: "https://www.paypal.me/exeldro"
patreon: Exeldro
obs-move-transition-2.5.7/.github/workflows/ 0000775 0000000 0000000 00000000000 14177464325 0021056 5 ustar 00root root 0000000 0000000 obs-move-transition-2.5.7/.github/workflows/build.yml 0000664 0000000 0000000 00000032242 14177464325 0022703 0 ustar 00root root 0000000 0000000 name: build obs plugin
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
PLUGIN_NAME: move-transition
OBS_VERSION: 27.0.0
jobs:
macos64:
name: "macOS 64-bit"
runs-on: [macos-latest]
env:
QT_VERSION: '5.15.2'
MACOS_DEPS_VERSION: '2021-02-28'
steps:
- name: Checkout
uses: actions/checkout@v2.3.3
with:
repository: obsproject/obs-studio
ref: ${{ env.OBS_VERSION }}
submodules: 'recursive'
- name: "Checkout plugin"
uses: actions/checkout@v2.3.3
with:
path: plugins/${{ env.PLUGIN_NAME }}
- name: Fetch Git Tags
run: |
cd plugins/${{ env.PLUGIN_NAME }}
git fetch --prune --tags --unshallow
- name: 'Install prerequisites (Homebrew)'
shell: bash
run: |
if [ -d /usr/local/opt/openssl@1.0.2t ]; then
brew uninstall openssl@1.0.2t
brew untap local/openssl
fi
if [ -d /usr/local/opt/python@2.7.17 ]; then
brew uninstall python@2.7.17
brew untap local/python2
fi
brew bundle --file ./CI/scripts/macos/Brewfile
- name: 'Install prerequisite: Pre-built dependencies'
if: steps.deps-cache.outputs.cache-hit != 'true'
shell: bash
run: |
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-deps-${{ env.MACOS_DEPS_VERSION }}.tar.gz
tar -xf ./macos-deps-${{ env.MACOS_DEPS_VERSION }}.tar.gz -C "/tmp"
- name: 'Install prerequisite: Pre-built dependency Qt'
if: steps.deps-qt-cache.outputs.cache-hit != 'true'
shell: bash
run: |
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-qt-${{ env.QT_VERSION }}-${{ env.MACOS_DEPS_VERSION }}.tar.gz
tar -xf ./macos-qt-${{ env.QT_VERSION }}-${{ env.MACOS_DEPS_VERSION }}.tar.gz -C "/tmp"
xattr -r -d com.apple.quarantine /tmp/obsdeps
- name: Configure
shell: bash
run: |
echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> plugins/CMakeLists.txt
mkdir ./build
cd ./build
cmake -DDISABLE_PYTHON=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DQTDIR="/tmp/obsdeps" -DSWIGDIR="/tmp/obsdeps" -DDepsPath="/tmp/obsdeps" -DBUILD_BROWSER=OFF -DENABLE_PIPEWIRE=OFF -DBUILD_VST=OFF -DBUILD_VIRTUALCAM=OFF -DENABLE_SCRIPTING=OFF ..
cd -
- name: Build
shell: bash
run: |
set -e
cd ./build
make -j4
cd -
- name: 'Install prerequisite: Packages app'
if: success()
shell: bash
run: |
curl -L -O http://s.sudre.free.fr/Software/files/Packages.dmg
sudo hdiutil attach ./Packages.dmg
sudo installer -pkg /Volumes/Packages\ 1.2.9/Install\ Packages.pkg -target /
- name: Package
if: success()
shell: bash
run: |
cd plugins/${{ env.PLUGIN_NAME }}
FILE_DATE=$(date +%Y-%m-%d)
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg
echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV
packagesbuild ./CI/macos/${{ env.PLUGIN_NAME }}.pkgproj
cd -
mkdir ./nightly
mv plugins/${{ env.PLUGIN_NAME }}/${{ env.PLUGIN_NAME }}.pkg ./nightly/${FILE_NAME}
- name: Publish
if: success()
uses: actions/upload-artifact@v2.2.0
with:
name: '${{ env.FILE_NAME }}'
path: ./nightly/*.pkg
ubuntu64:
name: 'Linux/Ubuntu 64-bit'
runs-on: [ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v2.3.3
with:
repository: obsproject/obs-studio
ref: ${{ env.OBS_VERSION }}
submodules: 'recursive'
- name: "Checkout plugin"
uses: actions/checkout@v2.3.3
with:
path: plugins/${{ env.PLUGIN_NAME }}
- name: Add plugin to obs cmake
shell: bash
run: echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> plugins/CMakeLists.txt
- name: Fetch Git Tags
run: git fetch --prune --tags --unshallow
- name: Install prerequisites (Apt)
shell: bash
run: |
sudo dpkg --add-architecture amd64
sudo apt-get -qq update
sudo apt-get install -y \
build-essential \
checkinstall \
cmake \
libasound2-dev \
libavcodec-dev \
libavdevice-dev \
libavfilter-dev \
libavformat-dev \
libavutil-dev \
libcurl4-openssl-dev \
libfdk-aac-dev \
libfontconfig-dev \
libfreetype6-dev \
libgl1-mesa-dev \
libjack-jackd2-dev \
libjansson-dev \
libluajit-5.1-dev \
libpulse-dev \
libqt5x11extras5-dev \
libsndio-dev \
libspeexdsp-dev \
libswresample-dev \
libswscale-dev \
libudev-dev \
libv4l-dev \
libva-dev \
libvlc-dev \
libx11-dev \
libx11-xcb-dev \
libx264-dev \
libxcb-randr0-dev \
libxcb-shm0-dev \
libxcb-xfixes0-dev \
libxcb-xinerama0-dev \
libxcomposite-dev \
libxinerama-dev \
libmbedtls-dev \
pkg-config \
python3-dev \
qtbase5-dev \
qtbase5-private-dev \
libqt5svg5-dev \
swig \
linux-generic
- name: 'Configure'
shell: bash
run: |
mkdir ./build
cd ./build
cmake -DUNIX_STRUCTURE=0 -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/obs-studio-portable" -DBUILD_CAPTIONS=OFF -DWITH_RTMPS=OFF -DBUILD_BROWSER=OFF -DBUILD_VIRTUALCAM=OFF -DBUILD_VST=OFF -DENABLE_PIPEWIRE=OFF -DENABLE_SCRIPTING=OFF ..
- name: 'Build'
shell: bash
working-directory: ${{ github.workspace }}/build
run: make -j4
- name: 'Package'
shell: bash
run: |
FILE_DATE=$(date +%Y-%m-%d)
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-linux64.tar.gz
echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV
mkdir -p ./${{ env.PLUGIN_NAME }}/bin/64bit/
mv ./build/plugins/${{ env.PLUGIN_NAME }}/${{ env.PLUGIN_NAME }}.so ./${{ env.PLUGIN_NAME }}/bin/64bit/${{ env.PLUGIN_NAME }}.so
mv ./plugins/${{ env.PLUGIN_NAME }}/data ./${{ env.PLUGIN_NAME }}/data
tar -cvzf "${FILE_NAME}" ${{ env.PLUGIN_NAME }}
- name: 'Publish'
uses: actions/upload-artifact@v2.2.0
with:
name: '${{ env.FILE_NAME }}'
path: '*.tar.gz'
windows:
name: Windows
runs-on: [windows-latest]
env:
QT_VERSION: '5.15.2'
CMAKE_GENERATOR: "Visual Studio 17 2022"
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
WINDOWS_DEPS_VERSION: '2019'
steps:
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.0.2
- name: Checkout obs
uses: actions/checkout@v2.3.3
with:
repository: obsproject/obs-studio
ref: ${{ env.OBS_VERSION }}
submodules: 'recursive'
- name: Checkout plugin
uses: actions/checkout@v2.3.3
with:
path: plugins/${{ env.PLUGIN_NAME}}
- name: Add plugin to obs cmake
shell: cmd
run: echo add_subdirectory(${{ env.PLUGIN_NAME }}) >> plugins/CMakeLists.txt
- name: Fetch Git Tags
run: git fetch --prune --tags --unshallow
- name: 'Restore QT dependency from cache'
id: qt-cache
uses: actions/cache@v2.1.2
env:
CACHE_NAME: 'qt-cache'
with:
path: ${{ github.workspace }}/cmbuild/QT
key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.QT_VERSION }}
- name: 'Restore pre-built dependencies from cache'
id: deps-cache
uses: actions/cache@v2.1.2
env:
CACHE_NAME: 'deps-cache'
with:
path: ${{ github.workspace }}/cmbuild/deps
key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.WINDOWS_DEPS_VERSION }}
- name: 'Install prerequisite: QT'
if: steps.qt-cache.outputs.cache-hit != 'true'
run: |
curl -kLO https://cdn-fastly.obsproject.com/downloads/Qt_${{ env.QT_VERSION }}.7z -f --retry 5 -C -
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
- name: 'Install prerequisite: Pre-built dependencies'
if: steps.deps-cache.outputs.cache-hit != 'true'
run: |
curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -f --retry 5 -C -
7z x dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -o"${{ github.workspace }}/cmbuild/deps"
- name: Configure
run: |
mkdir ./package
mkdir ./build32
cd ./build32
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_VST=false -DBUILD_VIRTUALCAM=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DENABLE_SCRIPTING=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2019" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
cd ..
mkdir ./build64
cd ./build64
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_VST=false -DBUILD_VIRTUALCAM=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DENABLE_SCRIPTING=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2019_64" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
- name: 'Build 32'
run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln
- name: 'Build 64'
run: msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-studio.sln
- name: Package
if: success()
run: |
$env:FILE_DATE=(Get-Date -UFormat "%F")
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-windows"
echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV}
robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\package\obs-plugins\32bit ${{ env.PLUGIN_NAME }}.* /E /XF .gitignore
robocopy .\build64\rundir\RelWithDebInfo\obs-plugins\64bit\ .\package\obs-plugins\64bit ${{ env.PLUGIN_NAME }}.* /E /XF .gitignore
robocopy .\build64\rundir\RelWithDebInfo\data\obs-plugins\${{ env.PLUGIN_NAME }}\ .\package\data\obs-plugins\${{ env.PLUGIN_NAME }}\ /E /XF .gitignore
exit 0
- name: Create Code Signing Certificate
if: success() && github.event_name != 'pull_request'
run: |
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate\certificate.txt -Value '${{ secrets.CERTIFICATE }}'
certutil -decode certificate\certificate.txt certificate\certificate.pfx
- name: Code Sign 32
if: success() && github.event_name != 'pull_request'
run: |
& 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.20348.0/x86/signtool.exe' sign /fd SHA256 /f certificate\certificate.pfx /p '${{ secrets.CERTIFICATE_PASS }}' /t http://timestamp.comodoca.com/authenticode .\package\obs-plugins\32bit\${{ env.PLUGIN_NAME }}.dll
- name: Code Sign 64
if: success() && github.event_name != 'pull_request'
run: |
& 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.20348.0/x64/signtool.exe' sign /fd SHA256 /f certificate\certificate.pfx /p '${{ secrets.CERTIFICATE_PASS }}' /t http://timestamp.comodoca.com/authenticode .\package\obs-plugins\64bit\${{ env.PLUGIN_NAME }}.dll
- name: Publish zip
if: success()
uses: actions/upload-artifact@v2.2.0
with:
name: '${{ env.FILE_NAME }}'
path: package/*
- name: "Package Installer (Prereqs)"
run: |
curl "-kL" "https://github.com/Xaymar/msvc-redist-helper/releases/download/0.1/msvc-redist-helper-64.exe" "-f" "--retry" "5" "-o" "msvc-redist-helper.exe"
curl "-kL" "https://files.jrsoftware.org/is/6/innosetup-6.0.3.exe" "-f" "--retry" "5" "-o" "inno.exe"
.\inno.exe /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART
- name: "Package Installer (Compile)"
run: |
& 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe' /Qp ".\build64\plugins\${{ env.PLUGIN_NAME }}\installer.iss"
- name: Code Sign Installer
if: success() && github.event_name != 'pull_request'
run: |
& 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.20348.0/x64/signtool.exe' sign /fd SHA256 /f certificate\certificate.pfx /p '${{ secrets.CERTIFICATE_PASS }}' /t http://timestamp.comodoca.com/authenticode .\package\${{ env.PLUGIN_NAME }}-installer.exe
- name: Publish installer
if: success()
uses: actions/upload-artifact@v2.2.0
with:
name: '${{ env.FILE_NAME }}-installer'
path: package/*.exe
obs-move-transition-2.5.7/CI/ 0000775 0000000 0000000 00000000000 14177464325 0015754 5 ustar 00root root 0000000 0000000 obs-move-transition-2.5.7/CI/macos/ 0000775 0000000 0000000 00000000000 14177464325 0017056 5 ustar 00root root 0000000 0000000 obs-move-transition-2.5.7/CI/macos/move-transition.pkgproj 0000664 0000000 0000000 00000047270 14177464325 0023624 0 ustar 00root root 0000000 0000000
PROJECT
PACKAGE_FILES
DEFAULT_INSTALL_LOCATION
/
HIERARCHY
CHILDREN
CHILDREN
CHILDREN
CHILDREN
CHILDREN
CHILDREN
CHILDREN
CHILDREN
GID
80
PATH
../../../../build/plugins/move-transition/move-transition.so
PATH_TYPE
3
PERMISSIONS
493
TYPE
3
UID
0
GID
80
PATH
bin
PATH_TYPE
0
PERMISSIONS
493
TYPE
2
UID
0
CHILDREN
GID
80
PATH
../../data
PATH_TYPE
1
PERMISSIONS
493
TYPE
3
UID
0
GID
80
PATH
move-transition
PATH_TYPE
0
PERMISSIONS
493
TYPE
2
UID
0
GID
80
PATH
plugins
PATH_TYPE
0
PERMISSIONS
493
TYPE
2
UID
0
GID
80
PATH
obs-studio
PATH_TYPE
0
PERMISSIONS
493
TYPE
2
UID
0
GID
80
PATH
Application Support
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Automator
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Documentation
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Extensions
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Filesystems
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Frameworks
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Input Methods
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Internet Plug-Ins
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
LaunchAgents
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
LaunchDaemons
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
PreferencePanes
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Preferences
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
80
PATH
Printers
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
PrivilegedHelperTools
PATH_TYPE
0
PERMISSIONS
1005
TYPE
1
UID
0
CHILDREN
GID
0
PATH
QuickLook
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
QuickTime
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Screen Savers
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Scripts
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Services
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
0
PATH
Widgets
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
GID
0
PATH
Library
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
CHILDREN
GID
0
PATH
Shared
PATH_TYPE
0
PERMISSIONS
1023
TYPE
1
UID
0
GID
80
PATH
Users
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
CHILDREN
GID
80
PATH
Applications
PATH_TYPE
0
PERMISSIONS
509
TYPE
1
UID
0
GID
0
PATH
/
PATH_TYPE
0
PERMISSIONS
493
TYPE
1
UID
0
PAYLOAD_TYPE
0
PRESERVE_EXTENDED_ATTRIBUTES
SHOW_INVISIBLE
SPLIT_FORKS
TREAT_MISSING_FILES_AS_WARNING
VERSION
5
PACKAGE_SCRIPTS
POSTINSTALL_PATH
PATH_TYPE
0
PREINSTALL_PATH
PATH_TYPE
0
RESOURCES
PACKAGE_SETTINGS
AUTHENTICATION
1
CONCLUSION_ACTION
0
FOLLOW_SYMBOLIC_LINKS
IDENTIFIER
com.exeldro.move-transition
LOCATION
0
NAME
OVERWRITE_PERMISSIONS
PAYLOAD_SIZE
-1
REFERENCE_PATH
RELOCATABLE
USE_HFS+_COMPRESSION
VERSION
0.0.2
PROJECT_COMMENTS
NOTES
PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1M
IDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQv
c3RyaWN0LmR0ZCI+CjxodG1sPgo8aGVhZD4KPG1ldGEgaHR0cC1l
cXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7
IGNoYXJzZXQ9VVRGLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJDb250
ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp
dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u
dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD
b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjE0MDQuMTMiPgo8c3R5bGUg
dHlwZT0idGV4dC9jc3MiPgo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5
Pgo8L2JvZHk+CjwvaHRtbD4K
PROJECT_SETTINGS
BUILD_PATH
PATH
../..
PATH_TYPE
1
EXCLUDED_FILES
PATTERNS_ARRAY
REGULAR_EXPRESSION
STRING
.DS_Store
TYPE
0
PROTECTED
PROXY_NAME
Remove .DS_Store files
PROXY_TOOLTIP
Remove ".DS_Store" files created by the Finder.
STATE
PATTERNS_ARRAY
REGULAR_EXPRESSION
STRING
.pbdevelopment
TYPE
0
PROTECTED
PROXY_NAME
Remove .pbdevelopment files
PROXY_TOOLTIP
Remove ".pbdevelopment" files created by ProjectBuilder or Xcode.
STATE
PATTERNS_ARRAY
REGULAR_EXPRESSION
STRING
CVS
TYPE
1
REGULAR_EXPRESSION
STRING
.cvsignore
TYPE
0
REGULAR_EXPRESSION
STRING
.cvspass
TYPE
0
REGULAR_EXPRESSION
STRING
.svn
TYPE
1
REGULAR_EXPRESSION
STRING
.git
TYPE
1
REGULAR_EXPRESSION
STRING
.gitignore
TYPE
0
PROTECTED
PROXY_NAME
Remove SCM metadata
PROXY_TOOLTIP
Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems.
STATE
PATTERNS_ARRAY
REGULAR_EXPRESSION
STRING
classes.nib
TYPE
0
REGULAR_EXPRESSION
STRING
designable.db
TYPE
0
REGULAR_EXPRESSION
STRING
info.nib
TYPE
0
PROTECTED
PROXY_NAME
Optimize nib files
PROXY_TOOLTIP
Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles.
STATE
PATTERNS_ARRAY
REGULAR_EXPRESSION
STRING
Resources Disabled
TYPE
1
PROTECTED
PROXY_NAME
Remove Resources Disabled folders
PROXY_TOOLTIP
Remove "Resources Disabled" folders.
STATE
SEPARATOR
NAME
move-transition
PAYLOAD_ONLY
TYPE
1
VERSION
2
obs-move-transition-2.5.7/CMakeLists.txt 0000664 0000000 0000000 00000003723 14177464325 0020226 0 ustar 00root root 0000000 0000000 cmake_minimum_required(VERSION 3.12..4.0)
project(move-transition VERSION 2.5.7)
set(PROJECT_FULL_NAME "Move Transition")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/version.h)
set(move-transition_HEADERS
move-transition.h
easing.h
version.h)
set(move-transition_SOURCES
move-transition.c
move-transition-override-filter.c
move-source-filter.c
move-value-filter.c
audio-move.c
easing.c)
if(WIN32)
get_filename_component(ISS_FILES_DIR "${CMAKE_BINARY_DIR}\\..\\package" ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_FILES_DIR}" ISS_FILES_DIR)
get_filename_component(ISS_PACKAGE_DIR "${CMAKE_PACKAGE_PREFIX}\\.." ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_PACKAGE_DIR}" ISS_PACKAGE_DIR)
get_filename_component(ISS_SOURCE_DIR "${PROJECT_SOURCE_DIR}" ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_SOURCE_DIR}" ISS_SOURCE_DIR)
configure_file("installer.iss.in"
"${PROJECT_BINARY_DIR}/installer.iss"
)
configure_file(resource.rc.in move-transition.rc)
list(APPEND move-transition_SOURCES
move-transition.rc)
endif()
if(BUILD_OUT_OF_TREE)
find_package(LibObs REQUIRED)
endif()
add_library(move-transition MODULE
${move-transition_HEADERS}
${move-transition_SOURCES})
target_link_libraries(move-transition
obs-frontend-api
libobs)
if(BUILD_OUT_OF_TREE)
if(NOT LIB_OUT_DIR)
set(LIB_OUT_DIR "/lib/obs-plugins")
endif()
if(NOT DATA_OUT_DIR)
set(DATA_OUT_DIR "/share/obs/obs-plugins/move-transition")
endif()
set_target_properties(move-transition PROPERTIES PREFIX "")
install(TARGETS move-transition
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${LIB_OUT_DIR})
install(DIRECTORY data/locale
DESTINATION ${CMAKE_INSTALL_PREFIX}/${DATA_OUT_DIR})
else()
target_include_directories(move-transition PRIVATE
"${CMAKE_SOURCE_DIR}/UI/obs-frontend-api")
set_target_properties(move-transition PROPERTIES FOLDER "plugins/exeldro")
install_obs_plugin_with_data(move-transition data)
endif()
obs-move-transition-2.5.7/LICENSE 0000664 0000000 0000000 00000043254 14177464325 0016476 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
obs-move-transition-2.5.7/README.md 0000664 0000000 0000000 00000001264 14177464325 0016743 0 ustar 00root root 0000000 0000000 # Move transition for OBS Studio
Plugin for OBS Studio to move source to a new position during scene transition
# Download
https://obsproject.com/forum/resources/move-transition.913/
# Build
1. In-tree build
- Build OBS Studio: https://obsproject.com/wiki/Install-Instructions
- Check out this repository to plugins/move-transition
- Add `add_subdirectory(move-transition)` to plugins/CMakeLists.txt
- Rebuild OBS Studio
1. Stand-alone build (Linux only)
- Verify that you have package with development files for OBS
- Check out this repository and run `cmake -S . -B build -DBUILD_OUT_OF_TREE=On && cmake --build build`
# Donations
https://www.paypal.me/exeldro
obs-move-transition-2.5.7/audio-move.c 0000664 0000000 0000000 00000077661 14177464325 0017713 0 ustar 00root root 0000000 0000000 #include "move-transition.h"
#include
#include
#include
#define METER_TYPE_MAGNITUDE 0
#define METER_TYPE_PEAK_SAMPLE 1
#define METER_TYPE_PEAK_TRUE 2
#define METER_TYPE_INPUT_PEAK_SAMPLE 3
#define METER_TYPE_INPUT_PEAK_TRUE 4
#define VALUE_ACTION_TRANSFORM 0
#define VALUE_ACTION_SETTING 1
#define VALUE_ACTION_SOURCE_VISIBILITY 2
#define VALUE_ACTION_FILTER_ENABLE 3
#define THRESHOLD_NONE 0
#define THRESHOLD_ENABLE_OVER 1
#define THRESHOLD_ENABLE_UNDER 2
#define THRESHOLD_DISABLE_OVER 3
#define THRESHOLD_DISABLE_UNDER 4
#define THRESHOLD_ENABLE_OVER_DISABLE_UNDER 5
#define THRESHOLD_ENABLE_UNDER_DISABLE_OVER 6
#define TRANSFORM_NONE 0
#define TRANSFORM_POS_X 1
#define TRANSFORM_POS_Y 2
#define TRANSFORM_ROT 3
#define TRANSFORM_SCALE 4
#define TRANSFORM_SCALE_X 4
#define TRANSFORM_SCALE_Y 5
#define TRANSFORM_BOUNDS_X 6
#define TRANSFORM_BOUNDS_Y 7
#define TRANSFORM_CROP_LEFT 8
#define TRANSFORM_CROP_TOP 9
#define TRANSFORM_CROP_RIGHT 10
#define TRANSFORM_CROP_BOTTOM 11
#define TRANSFORM_CROP_HORIZONTAL 12
#define TRANSFORM_CROP_VERTICAL 13
struct audio_move_info {
obs_source_t *source;
double easing;
double audio_value;
double base_value;
double factor;
long long action;
long long threshold_action;
double threshold;
obs_sceneitem_t *sceneitem;
obs_weak_source_t *target_source;
char *setting_name;
obs_volmeter_t *volmeter;
long long meter_type;
long long transform;
};
static const char *audio_move_get_name(void *type_data)
{
UNUSED_PARAMETER(type_data);
return obs_module_text("AudioMoveFilter");
}
void audio_move_volmeter_updated(void *data,
const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS],
const float input_peak[MAX_AUDIO_CHANNELS])
{
struct audio_move_info *audio_move = data;
float v = 0.0f;
if (audio_move->meter_type == METER_TYPE_MAGNITUDE) {
v = magnitude[0];
} else if (audio_move->meter_type == METER_TYPE_INPUT_PEAK_SAMPLE ||
audio_move->meter_type == METER_TYPE_INPUT_PEAK_TRUE) {
v = input_peak[0];
} else if (audio_move->meter_type == METER_TYPE_PEAK_SAMPLE ||
audio_move->meter_type == METER_TYPE_PEAK_TRUE) {
v = peak[0];
}
v = obs_db_to_mul(v);
audio_move->audio_value = audio_move->easing * audio_move->audio_value +
(1.0 - audio_move->easing) * v;
}
void audio_move_source_destroy(void *data, calldata_t *call_data)
{
struct audio_move_info *audio_move = data;
audio_move->target_source = NULL;
audio_move->sceneitem = NULL;
}
void audio_move_item_remove(void *data, calldata_t *call_data);
void audio_move_source_remove(void *data, calldata_t *call_data)
{
struct audio_move_info *audio_move = data;
if (audio_move->target_source) {
obs_source_t *source =
obs_weak_source_get_source(audio_move->target_source);
signal_handler_t *sh = obs_source_get_signal_handler(source);
signal_handler_disconnect(sh, "remove",
audio_move_source_remove, audio_move);
signal_handler_disconnect(
sh, "destroy", audio_move_source_destroy, audio_move);
obs_source_release(source);
obs_weak_source_release(audio_move->target_source);
}
audio_move->target_source = NULL;
if (audio_move->sceneitem) {
obs_scene_t *scene =
obs_sceneitem_get_scene(audio_move->sceneitem);
signal_handler_t *sh = obs_source_get_signal_handler(
obs_scene_get_source(scene));
if (sh) {
signal_handler_disconnect(sh, "item_remove",
audio_move_item_remove,
audio_move);
signal_handler_disconnect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_disconnect(sh, "destroy",
audio_move_source_destroy,
audio_move);
}
obs_source_t *item_source =
obs_sceneitem_get_source(audio_move->sceneitem);
if (item_source) {
sh = obs_source_get_signal_handler(item_source);
signal_handler_disconnect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_disconnect(sh, "destroy",
audio_move_source_destroy,
audio_move);
}
}
audio_move->sceneitem = NULL;
}
void audio_move_item_remove(void *data, calldata_t *call_data)
{
struct audio_move_info *audio_move = data;
obs_scene_t *scene = NULL;
calldata_get_ptr(call_data, "scene", &scene);
obs_sceneitem_t *item = NULL;
calldata_get_ptr(call_data, "item", &item);
if (item == audio_move->sceneitem) {
audio_move->sceneitem = NULL;
obs_source_t *parent = obs_scene_get_source(scene);
if (parent) {
signal_handler_t *sh =
obs_source_get_signal_handler(parent);
if (sh) {
signal_handler_disconnect(
sh, "item_remove",
audio_move_item_remove, audio_move);
signal_handler_disconnect(
sh, "remove", audio_move_source_remove,
audio_move);
signal_handler_disconnect(
sh, "destroy",
audio_move_source_destroy, audio_move);
}
}
}
}
void audio_move_update(void *data, obs_data_t *settings)
{
struct audio_move_info *audio_move = data;
obs_source_t *parent = obs_filter_get_parent(audio_move->source);
if (parent)
obs_volmeter_attach_source(audio_move->volmeter, parent);
const long long meter_type = obs_data_get_int(settings, "meter_type");
if (meter_type != audio_move->meter_type) {
audio_move->meter_type = meter_type;
if (meter_type == METER_TYPE_INPUT_PEAK_SAMPLE ||
meter_type == METER_TYPE_PEAK_SAMPLE) {
obs_volmeter_set_peak_meter_type(audio_move->volmeter,
SAMPLE_PEAK_METER);
} else if (meter_type == METER_TYPE_INPUT_PEAK_TRUE ||
meter_type == METER_TYPE_PEAK_TRUE) {
obs_volmeter_set_peak_meter_type(audio_move->volmeter,
TRUE_PEAK_METER);
}
}
audio_move->easing = obs_data_get_double(settings, "easing") / 100.0;
audio_move->action = obs_data_get_int(settings, "value_action");
audio_move->transform = obs_data_get_int(settings, "transform");
audio_move->base_value = obs_data_get_double(settings, "base_value");
audio_move->factor = obs_data_get_double(settings, "factor");
const char *scene_name = obs_data_get_string(settings, "scene");
const char *sceneitem_name = obs_data_get_string(settings, "sceneitem");
obs_source_t *source = obs_get_source_by_name(scene_name);
obs_source_release(source);
if (source && obs_source_removed(source))
source = NULL;
obs_scene_t *scene = obs_scene_from_source(source);
if (audio_move->sceneitem) {
signal_handler_t *sh = obs_source_get_signal_handler(source);
if (sh) {
signal_handler_disconnect(sh, "item_remove",
audio_move_item_remove,
audio_move);
signal_handler_disconnect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_disconnect(sh, "destroy",
audio_move_source_destroy,
audio_move);
}
obs_source_t *item_source =
obs_sceneitem_get_source(audio_move->sceneitem);
if (item_source) {
sh = obs_source_get_signal_handler(item_source);
signal_handler_disconnect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_disconnect(sh, "destroy",
audio_move_source_destroy,
audio_move);
}
}
audio_move->sceneitem =
scene ? obs_scene_find_source(scene, sceneitem_name) : NULL;
if (audio_move->sceneitem &&
obs_source_removed(
obs_sceneitem_get_source(audio_move->sceneitem))) {
audio_move->sceneitem = NULL;
}
if (audio_move->sceneitem && source) {
signal_handler_t *sh = obs_source_get_signal_handler(source);
if (sh) {
signal_handler_connect(sh, "item_remove",
audio_move_item_remove,
audio_move);
signal_handler_connect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_connect(sh, "destroy",
audio_move_source_destroy,
audio_move);
}
obs_source_t *item_source =
obs_sceneitem_get_source(audio_move->sceneitem);
if (item_source) {
sh = obs_source_get_signal_handler(item_source);
signal_handler_connect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_connect(sh, "destroy",
audio_move_source_destroy,
audio_move);
}
}
if (audio_move->target_source) {
source = obs_weak_source_get_source(audio_move->target_source);
if (source) {
signal_handler_t *sh =
obs_source_get_signal_handler(source);
signal_handler_disconnect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_disconnect(sh, "destroy",
audio_move_source_destroy,
audio_move);
obs_source_release(source);
}
obs_weak_source_release(audio_move->target_source);
}
audio_move->target_source = NULL;
obs_source_t *target_source = NULL;
if (audio_move->action == VALUE_ACTION_FILTER_ENABLE) {
source = obs_get_source_by_name(
obs_data_get_string(settings, "source"));
if (source) {
obs_source_t *filter = obs_source_get_filter_by_name(
source,
obs_data_get_string(settings, "filter"));
if (filter) {
target_source = filter;
}
obs_source_release(source);
}
} else if (audio_move->action == VALUE_ACTION_SETTING) {
source = obs_get_source_by_name(
obs_data_get_string(settings, "source"));
if (source) {
const char *filter_name =
obs_data_get_string(settings, "filter");
obs_source_t *filter =
filter_name && strlen(filter_name)
? obs_source_get_filter_by_name(
source, filter_name)
: NULL;
if (filter) {
target_source = filter;
obs_source_release(source);
} else {
target_source = source;
}
}
}
if (target_source && obs_source_removed(target_source)) {
target_source = NULL;
}
if (target_source) {
audio_move->target_source =
obs_source_get_weak_source(target_source);
signal_handler_t *sh =
obs_source_get_signal_handler(target_source);
signal_handler_connect(sh, "remove", audio_move_source_remove,
audio_move);
signal_handler_connect(sh, "destroy", audio_move_source_destroy,
audio_move);
obs_source_release(target_source);
}
audio_move->threshold_action =
obs_data_get_int(settings, "threshold_action");
audio_move->threshold =
obs_data_get_double(settings, "threshold") / 100.0;
const char *setting_name = obs_data_get_string(settings, "setting");
if (!audio_move->setting_name ||
strcmp(audio_move->setting_name, setting_name) != 0) {
bfree(audio_move->setting_name);
audio_move->setting_name = bstrdup(setting_name);
}
}
static void *audio_move_create(obs_data_t *settings, obs_source_t *source)
{
struct audio_move_info *audio_move =
bzalloc(sizeof(struct audio_move_info));
audio_move->source = source;
audio_move->volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(audio_move->volmeter,
audio_move_volmeter_updated, audio_move);
audio_move_update(audio_move, settings);
return audio_move;
}
static void audio_move_destroy(void *data)
{
struct audio_move_info *audio_move = data;
obs_volmeter_detach_source(audio_move->volmeter);
obs_volmeter_remove_callback(audio_move->volmeter,
audio_move_volmeter_updated, audio_move);
obs_volmeter_destroy(audio_move->volmeter);
audio_move->volmeter = NULL;
if (audio_move->target_source) {
obs_source_t *source =
obs_weak_source_get_source(audio_move->target_source);
if (source) {
signal_handler_t *sh =
obs_source_get_signal_handler(source);
signal_handler_disconnect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_disconnect(sh, "destroy",
audio_move_source_destroy,
audio_move);
obs_source_release(source);
}
obs_weak_source_release(audio_move->target_source);
}
audio_move->target_source = NULL;
if (audio_move->sceneitem) {
obs_scene_t *scene =
obs_sceneitem_get_scene(audio_move->sceneitem);
signal_handler_t *sh = obs_source_get_signal_handler(
obs_scene_get_source(scene));
if (sh) {
signal_handler_disconnect(sh, "item_remove",
audio_move_item_remove,
audio_move);
signal_handler_disconnect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_disconnect(sh, "destroy",
audio_move_source_destroy,
audio_move);
}
obs_source_t *item_source =
obs_sceneitem_get_source(audio_move->sceneitem);
if (item_source) {
sh = obs_source_get_signal_handler(item_source);
signal_handler_disconnect(sh, "remove",
audio_move_source_remove,
audio_move);
signal_handler_disconnect(sh, "destroy",
audio_move_source_destroy,
audio_move);
}
}
audio_move->sceneitem = NULL;
bfree(audio_move->setting_name);
bfree(audio_move);
}
static bool add_source_to_prop_list(void *data, obs_source_t *source)
{
obs_property_t *p = (obs_property_t *)data;
const char *name = obs_source_get_name(source);
if (name && strlen(name))
obs_property_list_add_string(p, name, name);
return true;
}
static bool audio_move_action_changed(obs_properties_t *props,
obs_property_t *property,
obs_data_t *settings)
{
UNUSED_PARAMETER(property);
long long action = obs_data_get_int(settings, "value_action");
obs_property_t *scene = obs_properties_get(props, "scene");
obs_property_t *sceneitem = obs_properties_get(props, "sceneitem");
if (action == VALUE_ACTION_TRANSFORM ||
action == VALUE_ACTION_SOURCE_VISIBILITY) {
obs_property_list_clear(scene);
obs_enum_scenes(add_source_to_prop_list, scene);
obs_property_set_visible(scene, true);
obs_property_set_visible(sceneitem, true);
} else {
obs_property_set_visible(scene, false);
obs_property_set_visible(sceneitem, false);
}
obs_property_t *source = obs_properties_get(props, "source");
obs_property_t *filter = obs_properties_get(props, "filter");
if (action == VALUE_ACTION_SETTING ||
action == VALUE_ACTION_FILTER_ENABLE) {
obs_property_list_clear(source);
obs_enum_sources(add_source_to_prop_list, source);
obs_enum_scenes(add_source_to_prop_list, source);
obs_property_set_visible(source, true);
obs_property_set_visible(filter, true);
} else {
obs_property_set_visible(source, false);
obs_property_set_visible(filter, false);
}
obs_property_t *base_value = obs_properties_get(props, "base_value");
obs_property_t *factor = obs_properties_get(props, "factor");
if (action == VALUE_ACTION_SETTING ||
action == VALUE_ACTION_TRANSFORM) {
obs_property_set_visible(base_value, true);
obs_property_set_visible(factor, true);
} else {
obs_property_set_visible(base_value, false);
obs_property_set_visible(factor, false);
}
obs_property_t *threshold_action =
obs_properties_get(props, "threshold_action");
obs_property_t *threshold = obs_properties_get(props, "threshold");
if (action == VALUE_ACTION_SOURCE_VISIBILITY ||
action == VALUE_ACTION_FILTER_ENABLE) {
obs_property_set_visible(threshold_action, true);
obs_property_set_visible(threshold, true);
} else {
obs_property_set_visible(threshold_action, false);
obs_property_set_visible(threshold, false);
}
obs_property_t *transform = obs_properties_get(props, "transform");
if (action == VALUE_ACTION_TRANSFORM) {
obs_property_set_visible(transform, true);
} else {
obs_property_set_visible(transform, false);
}
obs_property_t *setting = obs_properties_get(props, "setting");
if (action == VALUE_ACTION_SETTING) {
obs_property_set_visible(setting, true);
} else {
obs_property_set_visible(setting, false);
}
return true;
}
static bool add_sceneitem_to_prop_list(obs_scene_t *scene,
obs_sceneitem_t *item, void *data)
{
UNUSED_PARAMETER(scene);
obs_property_t *p = (obs_property_t *)data;
const obs_source_t *source = obs_sceneitem_get_source(item);
const char *name = obs_source_get_name(source);
if (name && strlen(name))
obs_property_list_add_string(p, name, name);
return true;
}
static bool audio_move_scene_changed(void *data, obs_properties_t *props,
obs_property_t *property,
obs_data_t *settings)
{
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(property);
const char *scene_name = obs_data_get_string(settings, "scene");
obs_property_t *sceneitem = obs_properties_get(props, "sceneitem");
obs_property_list_clear(sceneitem);
obs_source_t *source = obs_get_source_by_name(scene_name);
obs_source_release(source);
obs_scene_t *scene = obs_scene_from_source(source);
if (!scene)
return true;
obs_scene_enum_items(scene, add_sceneitem_to_prop_list, sceneitem);
return true;
}
static void add_filter_to_prop_list(obs_source_t *parent, obs_source_t *child,
void *data)
{
UNUSED_PARAMETER(parent);
obs_property_t *p = (obs_property_t *)data;
const char *name = obs_source_get_name(child);
const char *src_id = obs_source_get_id(child);
if (name && strlen(name) && strcmp(src_id, AUDIO_MOVE_FILTER_ID) != 0)
obs_property_list_add_string(p, name, name);
}
static void load_properties(obs_properties_t *props_from,
obs_property_t *setting_list)
{
obs_property_t *prop_from = obs_properties_first(props_from);
for (; prop_from != NULL; obs_property_next(&prop_from)) {
const char *name = obs_property_name(prop_from);
const char *description = obs_property_description(prop_from);
if (!obs_property_visible(prop_from))
continue;
const enum obs_property_type prop_type =
obs_property_get_type(prop_from);
if (prop_type == OBS_PROPERTY_GROUP) {
load_properties(obs_property_group_content(prop_from),
setting_list);
} else if (prop_type == OBS_PROPERTY_FLOAT ||
prop_type == OBS_PROPERTY_INT) {
obs_property_list_add_string(setting_list, description,
name);
}
}
}
static bool audio_move_source_changed(void *data, obs_properties_t *props,
obs_property_t *property,
obs_data_t *settings)
{
UNUSED_PARAMETER(property);
UNUSED_PARAMETER(data);
const char *source_name = obs_data_get_string(settings, "source");
const char *filter_name = obs_data_get_string(settings, "filter");
obs_property_t *filter = obs_properties_get(props, "filter");
obs_property_list_clear(filter);
obs_source_t *source = obs_get_source_by_name(source_name);
obs_source_release(source);
obs_source_enum_filters(source, add_filter_to_prop_list, filter);
obs_property_t *setting = obs_properties_get(props, "setting");
obs_property_list_clear(setting);
obs_properties_t *properties = NULL;
if (filter_name && strlen(filter_name)) {
obs_source_t *f =
obs_source_get_filter_by_name(source, filter_name);
if (f) {
properties = obs_source_properties(f);
}
} else {
properties = obs_source_properties(source);
}
if (properties) {
load_properties(properties, setting);
obs_properties_destroy(properties);
}
return true;
}
static obs_properties_t *audio_move_properties(void *data)
{
UNUSED_PARAMETER(data);
obs_properties_t *ppts = obs_properties_create();
obs_property_t *p = obs_properties_add_list(
ppts, "meter_type", obs_module_text("MeterType"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("MeterType.Magnitude"),
METER_TYPE_MAGNITUDE);
obs_property_list_add_int(p, obs_module_text("MeterType.PeakSample"),
METER_TYPE_PEAK_SAMPLE);
obs_property_list_add_int(p, obs_module_text("MeterType.PeakTrue"),
METER_TYPE_PEAK_TRUE);
obs_property_list_add_int(p,
obs_module_text("MeterType.InputPeakSample"),
METER_TYPE_INPUT_PEAK_SAMPLE);
obs_property_list_add_int(p, obs_module_text("MeterType.InputPeakTrue"),
METER_TYPE_INPUT_PEAK_TRUE);
p = obs_properties_add_float_slider(
ppts, "easing", obs_module_text("Easing"), 0.0, 99.99, 0.01);
p = obs_properties_add_list(ppts, "value_action",
obs_module_text("ValueAction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("ValueAction.Transform"),
VALUE_ACTION_TRANSFORM);
obs_property_list_add_int(p, obs_module_text("ValueAction.Setting"),
VALUE_ACTION_SETTING);
obs_property_list_add_int(
p, obs_module_text("ValueAction.SourceVisibility"),
VALUE_ACTION_SOURCE_VISIBILITY);
obs_property_list_add_int(p,
obs_module_text("ValueAction.FilterEnable"),
VALUE_ACTION_FILTER_ENABLE);
obs_property_set_modified_callback(p, audio_move_action_changed);
p = obs_properties_add_list(ppts, "scene", obs_module_text("Scene"),
OBS_COMBO_TYPE_EDITABLE,
OBS_COMBO_FORMAT_STRING);
obs_property_set_modified_callback2(p, audio_move_scene_changed, data);
p = obs_properties_add_list(ppts, "sceneitem",
obs_module_text("Source"),
OBS_COMBO_TYPE_EDITABLE,
OBS_COMBO_FORMAT_STRING);
p = obs_properties_add_list(ppts, "source", obs_module_text("Source"),
OBS_COMBO_TYPE_EDITABLE,
OBS_COMBO_FORMAT_STRING);
obs_property_set_modified_callback2(p, audio_move_source_changed, data);
p = obs_properties_add_list(ppts, "filter", obs_module_text("Filter"),
OBS_COMBO_TYPE_EDITABLE,
OBS_COMBO_FORMAT_STRING);
obs_property_set_modified_callback2(p, audio_move_source_changed, data);
p = obs_properties_add_list(ppts, "transform",
obs_module_text("Transform"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("Transform.PosX"),
TRANSFORM_POS_X);
obs_property_list_add_int(p, obs_module_text("Transform.PosY"),
TRANSFORM_POS_Y);
obs_property_list_add_int(p, obs_module_text("Transform.Rotation"),
TRANSFORM_ROT);
obs_property_list_add_int(p, obs_module_text("Transform.Scale"),
TRANSFORM_SCALE);
obs_property_list_add_int(p, obs_module_text("Transform.ScaleX"),
TRANSFORM_SCALE_X);
obs_property_list_add_int(p, obs_module_text("Transform.ScaleY"),
TRANSFORM_SCALE_Y);
obs_property_list_add_int(p, obs_module_text("Transform.BoundsX"),
TRANSFORM_BOUNDS_X);
obs_property_list_add_int(p, obs_module_text("Transform.BoundsY"),
TRANSFORM_BOUNDS_Y);
obs_property_list_add_int(p, obs_module_text("Transform.CropLeft"),
TRANSFORM_CROP_LEFT);
obs_property_list_add_int(p, obs_module_text("Transform.CropTop"),
TRANSFORM_CROP_TOP);
obs_property_list_add_int(p, obs_module_text("Transform.CropRight"),
TRANSFORM_CROP_RIGHT);
obs_property_list_add_int(p, obs_module_text("Transform.CropBottom"),
TRANSFORM_CROP_BOTTOM);
obs_property_list_add_int(p,
obs_module_text("Transform.CropHorizontal"),
TRANSFORM_CROP_HORIZONTAL);
obs_property_list_add_int(p, obs_module_text("Transform.CropVertical"),
TRANSFORM_CROP_VERTICAL);
p = obs_properties_add_list(ppts, "setting", obs_module_text("Setting"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
p = obs_properties_add_float(ppts, "base_value",
obs_module_text("BaseValue"), -DBL_MAX,
DBL_MAX, 0.01);
p = obs_properties_add_float(ppts, "factor", obs_module_text("Factor"),
-DBL_MAX, DBL_MAX, 0.01);
p = obs_properties_add_list(ppts, "threshold_action",
obs_module_text("ThresholdAction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("ThresholdAction.None"),
THRESHOLD_NONE);
obs_property_list_add_int(p,
obs_module_text("ThresholdAction.EnableOver"),
THRESHOLD_ENABLE_OVER);
obs_property_list_add_int(
p, obs_module_text("ThresholdAction.EnableUnder"),
THRESHOLD_ENABLE_UNDER);
obs_property_list_add_int(
p, obs_module_text("ThresholdAction.DisableOver"),
THRESHOLD_DISABLE_OVER);
obs_property_list_add_int(
p, obs_module_text("ThresholdAction.DisableUnder"),
THRESHOLD_DISABLE_UNDER);
obs_property_list_add_int(
p, obs_module_text("ThresholdAction.EnableOverDisableUnder"),
THRESHOLD_ENABLE_OVER_DISABLE_UNDER);
obs_property_list_add_int(
p, obs_module_text("ThresholdAction.EnableUnderDisableOver"),
THRESHOLD_ENABLE_UNDER_DISABLE_OVER);
p = obs_properties_add_float_slider(ppts, "threshold",
obs_module_text("Threshold"), 0.0,
100.0, 0.01);
return ppts;
}
void audio_move_defaults(obs_data_t *settings)
{
obs_data_set_default_double(settings, "factor", 1000.0);
}
void audio_move_tick(void *data, float seconds)
{
UNUSED_PARAMETER(seconds);
struct audio_move_info *filter = data;
if (!obs_source_enabled(filter->source))
return;
if (filter->action == VALUE_ACTION_TRANSFORM) {
if (!filter->sceneitem) {
obs_data_t *settings =
obs_source_get_settings(filter->source);
audio_move_update(filter, settings);
obs_data_release(settings);
}
if (!filter->sceneitem)
return;
if (filter->transform == TRANSFORM_POS_X) {
struct vec2 pos;
obs_sceneitem_get_pos(filter->sceneitem, &pos);
pos.x = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_pos(filter->sceneitem, &pos);
} else if (filter->transform == TRANSFORM_POS_Y) {
struct vec2 pos;
obs_sceneitem_get_pos(filter->sceneitem, &pos);
pos.y = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_pos(filter->sceneitem, &pos);
} else if (filter->transform == TRANSFORM_ROT) {
obs_sceneitem_set_rot(
filter->sceneitem,
filter->factor * filter->audio_value +
filter->base_value);
} else if (filter->transform == TRANSFORM_SCALE) {
struct vec2 scale;
scale.x = filter->factor * filter->audio_value +
filter->base_value;
scale.y = scale.x;
obs_sceneitem_set_scale(filter->sceneitem, &scale);
} else if (filter->transform == TRANSFORM_SCALE_X) {
struct vec2 scale;
obs_sceneitem_get_scale(filter->sceneitem, &scale);
scale.x = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_scale(filter->sceneitem, &scale);
} else if (filter->transform == TRANSFORM_SCALE_Y) {
struct vec2 scale;
obs_sceneitem_get_scale(filter->sceneitem, &scale);
scale.y = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_scale(filter->sceneitem, &scale);
} else if (filter->transform == TRANSFORM_BOUNDS_X) {
struct vec2 bounds;
obs_sceneitem_get_bounds(filter->sceneitem, &bounds);
bounds.x = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_scale(filter->sceneitem, &bounds);
} else if (filter->transform == TRANSFORM_BOUNDS_Y) {
struct vec2 bounds;
obs_sceneitem_get_bounds(filter->sceneitem, &bounds);
bounds.y = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_scale(filter->sceneitem, &bounds);
} else if (filter->transform == TRANSFORM_CROP_LEFT) {
struct obs_sceneitem_crop crop;
obs_sceneitem_get_crop(filter->sceneitem, &crop);
crop.left = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_crop(filter->sceneitem, &crop);
} else if (filter->transform == TRANSFORM_CROP_TOP) {
struct obs_sceneitem_crop crop;
obs_sceneitem_get_crop(filter->sceneitem, &crop);
crop.top = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_crop(filter->sceneitem, &crop);
} else if (filter->transform == TRANSFORM_CROP_RIGHT) {
struct obs_sceneitem_crop crop;
obs_sceneitem_get_crop(filter->sceneitem, &crop);
crop.right = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_crop(filter->sceneitem, &crop);
} else if (filter->transform == TRANSFORM_CROP_BOTTOM) {
struct obs_sceneitem_crop crop;
obs_sceneitem_get_crop(filter->sceneitem, &crop);
crop.bottom = filter->factor * filter->audio_value +
filter->base_value;
obs_sceneitem_set_crop(filter->sceneitem, &crop);
} else if (filter->transform == TRANSFORM_CROP_HORIZONTAL) {
struct obs_sceneitem_crop crop;
obs_sceneitem_get_crop(filter->sceneitem, &crop);
crop.left = filter->factor * filter->audio_value +
filter->base_value;
crop.right = crop.left;
obs_sceneitem_set_crop(filter->sceneitem, &crop);
} else if (filter->transform == TRANSFORM_CROP_VERTICAL) {
struct obs_sceneitem_crop crop;
obs_sceneitem_get_crop(filter->sceneitem, &crop);
crop.top = filter->factor * filter->audio_value +
filter->base_value;
crop.bottom = crop.top;
obs_sceneitem_set_crop(filter->sceneitem, &crop);
}
} else if (filter->action == VALUE_ACTION_SOURCE_VISIBILITY) {
if (!filter->sceneitem) {
obs_data_t *settings =
obs_source_get_settings(filter->source);
audio_move_update(filter, settings);
obs_data_release(settings);
}
if (!filter->sceneitem)
return;
if ((filter->threshold_action == THRESHOLD_ENABLE_OVER ||
filter->threshold_action ==
THRESHOLD_ENABLE_OVER_DISABLE_UNDER) &&
filter->audio_value >= filter->threshold) {
obs_sceneitem_set_visible(filter->sceneitem, true);
} else if ((filter->threshold_action ==
THRESHOLD_ENABLE_UNDER ||
filter->threshold_action ==
THRESHOLD_ENABLE_UNDER_DISABLE_OVER) &&
filter->audio_value < filter->threshold) {
obs_sceneitem_set_visible(filter->sceneitem, true);
} else if ((filter->threshold_action ==
THRESHOLD_DISABLE_OVER ||
filter->threshold_action ==
THRESHOLD_ENABLE_UNDER_DISABLE_OVER) &&
filter->audio_value >= filter->threshold) {
obs_sceneitem_set_visible(filter->sceneitem, false);
} else if ((filter->threshold_action ==
THRESHOLD_DISABLE_UNDER ||
filter->threshold_action ==
THRESHOLD_ENABLE_OVER_DISABLE_UNDER) &&
filter->audio_value < filter->threshold) {
obs_sceneitem_set_visible(filter->sceneitem, false);
}
} else if (filter->action == VALUE_ACTION_FILTER_ENABLE) {
if (!filter->target_source) {
obs_data_t *settings =
obs_source_get_settings(filter->source);
audio_move_update(filter, settings);
obs_data_release(settings);
}
if (!filter->target_source)
return;
obs_source_t *source =
obs_weak_source_get_source(filter->target_source);
if (!source)
return;
if ((filter->threshold_action == THRESHOLD_ENABLE_OVER ||
filter->threshold_action ==
THRESHOLD_ENABLE_OVER_DISABLE_UNDER) &&
filter->audio_value >= filter->threshold &&
!obs_source_enabled(source)) {
obs_source_set_enabled(source, true);
} else if ((filter->threshold_action ==
THRESHOLD_ENABLE_UNDER ||
filter->threshold_action ==
THRESHOLD_ENABLE_UNDER_DISABLE_OVER) &&
filter->audio_value < filter->threshold &&
!obs_source_enabled(source)) {
obs_source_set_enabled(source, true);
} else if ((filter->threshold_action ==
THRESHOLD_DISABLE_OVER ||
filter->threshold_action ==
THRESHOLD_ENABLE_UNDER_DISABLE_OVER) &&
filter->audio_value >= filter->threshold &&
obs_source_enabled(source)) {
obs_source_set_enabled(source, false);
} else if ((filter->threshold_action ==
THRESHOLD_DISABLE_UNDER ||
filter->threshold_action ==
THRESHOLD_ENABLE_OVER_DISABLE_UNDER) &&
filter->audio_value < filter->threshold &&
obs_source_enabled(source)) {
obs_source_set_enabled(source, false);
}
obs_source_release(source);
} else if (filter->action == VALUE_ACTION_SETTING &&
filter->setting_name && strlen(filter->setting_name)) {
if (!filter->target_source) {
obs_data_t *settings =
obs_source_get_settings(filter->source);
audio_move_update(filter, settings);
obs_data_release(settings);
}
if (!filter->target_source)
return;
obs_source_t *source =
obs_weak_source_get_source(filter->target_source);
if (!source)
return;
obs_data_t *settings = obs_source_get_settings(source);
const double val = filter->factor * filter->audio_value +
filter->base_value;
obs_data_item_t *setting =
obs_data_item_byname(settings, filter->setting_name);
if (setting) {
const enum obs_data_number_type num_type =
obs_data_item_numtype(setting);
if (num_type == OBS_DATA_NUM_INT) {
obs_data_item_set_int(&setting, val);
} else if (num_type == OBS_DATA_NUM_DOUBLE) {
obs_data_item_set_double(&setting, val);
}
obs_data_item_release(&setting);
} else {
obs_data_set_double(settings, filter->setting_name,
val);
}
obs_data_release(settings);
obs_source_update(source, NULL);
obs_source_release(source);
}
}
struct obs_source_info audio_move_filter = {
.id = AUDIO_MOVE_FILTER_ID,
.type = OBS_SOURCE_TYPE_FILTER,
.output_flags = OBS_SOURCE_AUDIO,
.get_name = audio_move_get_name,
.create = audio_move_create,
.destroy = audio_move_destroy,
.get_properties = audio_move_properties,
.get_defaults = audio_move_defaults,
.update = audio_move_update,
.load = audio_move_update,
.video_tick = audio_move_tick,
};
obs-move-transition-2.5.7/data/ 0000775 0000000 0000000 00000000000 14177464325 0016372 5 ustar 00root root 0000000 0000000 obs-move-transition-2.5.7/data/locale/ 0000775 0000000 0000000 00000000000 14177464325 0017631 5 ustar 00root root 0000000 0000000 obs-move-transition-2.5.7/data/locale/de-DE.ini 0000664 0000000 0000000 00000002004 14177464325 0021204 0 ustar 00root root 0000000 0000000 Move="Verschieben"
Description="Szenenübergang, der alle Quellen an ihre neue Position verschiebt."
Easing="Easing"
Easing.None="Kein easing"
Easing.In="Ease in"
Easing.Out="Ease out"
Easing.InOut="Ease in and out"
EasingFunction="Easing Function"
EasingFunction.Quadratic="Quadratisch"
EasingFunction.Cubic="Kubisch"
EasingFunction.Quartic="Quartisch"
EasingFunction.Quintic="Quintisch"
EasingFunction.Sine="Sinus"
EasingFunction.Circular="Kreisfunktion"
EasingFunction.Exponential="Exponentiell"
EasingFunction.Elastic="Elastisch"
EasingFunction.Bounce="Aufspringen"
EasingFunction.Back="Zurückfedern"
Position="Position"
Zoom="Zoomen"
Curve="Kurvenkrümmung"
Position.None="Keine"
Position.Center="Mittig"
Position.CenterInverse="Weg von der Mitte"
Position.TopLeft="Oben links"
Position.TopCenter="Oben mittig"
Position.TopRight="Oben rechts"
Position.CenterRight="Mittig rechts"
Position.BottomRight="Unten rechts"
Position.BottomCenter="Unten mittig"
Position.BottomLeft="Unten links"
Position.CenterLeft="Mittig links"
obs-move-transition-2.5.7/data/locale/en-US.ini 0000664 0000000 0000000 00000017113 14177464325 0021264 0 ustar 00root root 0000000 0000000 Move="Move"
MoveTransition="Move Transition"
Description="Transition that moves all sources to a new position"
MoveMatch="Matched items"
MoveIn="Appearing items"
MoveOut="Disappearing items"
Easing="Easing"
Easing.None="No easing"
Easing.In="Ease in"
Easing.Out="Ease out"
Easing.InOut="Ease in and out"
EasingFunction="Easing Function"
EasingFunction.Quadratic="Quadratic"
EasingFunction.Cubic="Cubic"
EasingFunction.Quartic="Quartic"
EasingFunction.Quintic="Quintic"
EasingFunction.Sine="Sine"
EasingFunction.Circular="Circular"
EasingFunction.Exponential="Exponential"
EasingFunction.Elastic="Elastic"
EasingFunction.Bounce="Bounce"
EasingFunction.Back="Back"
Position="Position"
Zoom="Zoom"
Curve="Curve"
CurveOverride="Override Curve"
Position.None="None"
Position.Center="Center"
Position.CenterInverse="Away from center"
Position.TopLeft="Top left"
Position.TopCenter="Top center"
Position.TopRight="Top right"
Position.CenterRight="Center right"
Position.BottomRight="Bottom right"
Position.BottomCenter="Bottom center"
Position.BottomLeft="Bottom left"
Position.CenterLeft="Center left"
Position.Left="Left"
Position.Top="Top"
Position.Right="Right"
Position.Bottom="Bottom"
Transition="Transition"
Transition.None="None"
MatchName="Match if the source name"
NamePartMatch="contains the other source name"
NameNumberMatch="with numbers removed from end matches the other source name"
NameLastWordMatch="with the last word removed matches the other source name"
TransitionScaleType="Transition scale type"
TransitionScale.MaxOnly="Max only: Scale to aspect ratio, but only to the maximum size of each source"
TransitionScale.Aspect="Aspect: Always scale the sources, but keep aspect ratio"
TransitionScale.Stretch="Stretch: Scale and stretch the sources to the size of the transition"
MoveTransitionOverrideFilter="Move transition override"
NoOverride="No override"
Yes="Yes"
No="No"
StartMove="Start Move Filter"
StartMoveMatchFrom="Start Move Filter From"
StartMoveMatchTo="Start Move Filter To"
MoveSourceFilter="Move Source"
ScenesOnlyFilter="This filter only works on scenes and groups"
General="General"
TransformRelative="Transform Relative"
Transform="Transform"
GetTransform="Get transform"
CustomDuration="Custom Duration"
Duration="Duration"
Start="Start"
SwitchPoint="Switch Point"
Source="Source"
MatchSource="Match Source"
MoveAll="General"
CacheTransitions="Cache Transitions"
StartTrigger="Start Trigger"
StartTrigger.None="None: not started automatic, use a hotkey or next move to start this move"
StartTrigger.Activate="Activate: When this filter becomes actively shown in the final mix"
StartTrigger.Deactivate="Deactivate: When this filter becomes not active, so not showing the final mix."
StartTrigger.Show="Show: This filter is being displayed anywhere at all, whether on a display context or on the final output"
StartTrigger.Hide="Hide: When this filter is not showing anywhere"
StartTrigger.Enable="Enable: When the eye icon in front of this filter is enabled"
StartTrigger.SourceActivate="Source Activate: When the source becomes actively shown in the final mix"
StartTrigger.SourceDeactivate="Source Deactivate: When the source becomes not active, so not showing the final mix."
StartTrigger.SourceShow="Source Show: The source is being displayed anywhere at all, whether on a display context or on the final output"
StartTrigger.SourceHide="Source Hide: When the source is not showing anywhere"
StartTrigger.MediaStarted="Media Started: When the media of the source starts playing"
StartTrigger.MediaEnded="Media Ended: When playing of the media source has ended"
StartTrigger.Load="Load: When this filter is loaded or updated"
StopTrigger="Stop Trigger"
StopTrigger.None="None: stop only when the move is done or this filter is disabled"
Actions="Actions"
SimultaneousMove="Simultaneous Move"
SimultaneousMove.None="None"
NextMove="Next Move"
NextMove.None="None"
NextMove.Reverse="Reverse"
NextMoveOn="Next Move On"
NextMoveOn.End="Move End"
NextMoveOn.Hotkey="Hotkey"
StartDelay="Start Delay"
EndDelay="End Delay"
StartDelayTo="Start Delay To"
EndDelayTo="End Delay To"
StartDelayFrom="Start Delay From"
EndDelayFrom="End Delay From"
MoveValueFilter="Move Value"
Filter="Filter"
Filter.None="None"
MoveValueType="Move Value Type"
MoveValueType.SingleSetting="Single Setting"
MoveValueType.Settings="Settings"
MoveValueType.Random="Random"
MoveValueType.SettingAdd="Add"
MoveValueType.Type="Typing"
FormatType="Format Type"
FormatType.Decimals="Decimals number"
FormatType.Float="Float format using printf"
FormatType.Time="Time format using strftime"
Format="Format"
Settings="Settings"
Setting="Setting"
Setting.None="None"
Setting.Volume="Source volume"
Decimals="Decimals"
Value="Value"
MinValue="Min Value"
MaxValue="Max Value"
Text="Text"
GetValue="Get Value"
GetValues="Get Values"
VisibilityOrder="Visibility and Order"
ChangeVisibility="Visibility"
ChangeVisibility.No="No Change"
ChangeVisibility.ShowStart="Show at the start of movement"
ChangeVisibility.ShowEnd="Show at the end of movement"
ChangeVisibility.ShowStartEnd="Show during movement"
ChangeVisibility.HideStart="Hide at the start of movement"
ChangeVisibility.HideEnd="Hide at the end of movement"
ChangeVisibility.HideStartEnd="Hide during movement"
ChangeVisibility.Toggle="Toggle"
ChangeVisibility.ToggleStart="Toggle at the start of movement"
ChangeVisibility.ToggleEnd="Toggle at the end of movement"
ChangeOrder="Order"
ChangeOrder.No="No Change"
ChangeOrder.StartRelative="Start Relative"
ChangeOrder.EndRelative="End Relative"
ChangeOrder.StartAbsolute="Start Absolute"
ChangeOrder.EndAbsolute="End Absolute"
OrderPosition="Difference / Position"
MediaAction="Media"
MediaAction.Start="Start Action"
MediaAction.End="End Action"
MediaAction.None="None"
MediaAction.Play="Play"
MediaAction.Pause="Pause"
MediaAction.Stop="Stop"
MediaAction.Restart="Restart"
MediaAction.Next="Next"
MediaAction.Previous="Previous"
MediaAction.PlayFrom="Play From"
MediaAction.PauseAt="Pause At"
MediaAction.Time="Time"
AudioAction="Audio"
MuteAction="Mute"
MuteAction.None="None"
MuteAction.MuteStart="Mute at Start"
MuteAction.MuteEnd="Mute at End"
MuteAction.UnmuteStart="Unmute at Start"
MuteAction.UnmuteEnd="Unmute at End"
MuteAction.MuteDuring="Mute During: Mute at Start and Unmute at End"
MuteAction.UnmuteDuring="Unmute During: Unmute at Start and Mute at End"
AudioFade="Fade"
EnabledMatchMoving="Filter only enabled when moving"
AudioMoveFilter="Audio Move"
MeterType="Meter Type"
MeterType.Magnitude="Magnitude"
MeterType.PeakSample="Peak Sample"
MeterType.PeakTrue="Peak True"
MeterType.InputPeakSample="Input Peak Sample"
MeterType.InputPeakTrue="Input Peak True"
ValueAction="Action"
ValueAction.Transform="Transform"
ValueAction.Setting="Setting"
ValueAction.SourceVisibility="Source Visibility"
ValueAction.FilterEnable="Filter Enable"
Scene="Scene"
Filter="Filter"
Transform.PosX="Position X"
Transform.PosY="Position Y"
Transform.Rotation="Rotation"
Transform.Scale="Scale"
Transform.ScaleX="Scale X"
Transform.ScaleY="Scale Y"
Transform.BoundsX="Bounds X"
Transform.BoundsY="Bounds Y"
Transform.CropLeft="Crop Left"
Transform.CropTop="Crop Top"
Transform.CropRight="Crop Right"
Transform.CropBottom="Crop Bottom"
Transform.CropHorizontal="Crop Horizontal"
Transform.CropVertical="Crop Vertical"
BaseValue="Base Value"
Factor="Factor"
ThresholdAction="Threshold Action"
ThresholdAction.None="None"
ThresholdAction.EnableOver="Enable Over"
ThresholdAction.EnableUnder="Enable Under"
ThresholdAction.DisableOver="Disable Over"
ThresholdAction.DisableUnder="Disable Under"
ThresholdAction.EnableOverDisableUnder="Enable Over and Disable Under"
ThresholdAction.EnableUnderDisableOver="Enable Under and Disable Over"
Threshold="Threshold"
obs-move-transition-2.5.7/data/locale/es-ES.ini 0000664 0000000 0000000 00000021163 14177464325 0021251 0 ustar 00root root 0000000 0000000 Move="Mover"
MoveTransition="Transición Mover"
Description="Transición que mueve todas las fuentes a una nueva posición"
MoveMatch="Elementos coincidentes"
MoveIn="Elementos que aparecen"
MoveOut="Elementos que desaparecen"
Easing="Suavizado"
Easing.None="Sin suavizado"
Easing.In="Suavizado de entrada"
Easing.Out="Suavizado de salida"
Easing.InOut="Suavizado de entrada y salida"
EasingFunction="Función de suavizado"
EasingFunction.Quadratic="Cuadrática"
EasingFunction.Cubic="Cúbica"
EasingFunction.Quartic="Cuártica"
EasingFunction.Quintic="QuÃntica"
EasingFunction.Sine="Seno"
EasingFunction.Circular="Circular"
EasingFunction.Exponential="Exponencial"
EasingFunction.Elastic="Elástica"
EasingFunction.Bounce="Rebote"
EasingFunction.Back="Regreso"
Position="Posición"
Zoom="Zoom"
Curve="Curva"
CurveOverride="Anular curva"
Position.None="Ninguno"
Position.Center="Centro"
Position.CenterInverse="Alejado del centro"
Position.TopLeft="Superior izquierda"
Position.TopCenter="Superior centro"
Position.TopRight="Superior derecha"
Position.CenterRight="Centro derecha"
Position.BottomRight="Inferior derecha"
Position.BottomCenter="Inferior centro"
Position.BottomLeft="Inferior izquierda"
Position.CenterLeft="Centro izquierda"
Position.Left="Izquierda"
Position.Top="Superior"
Position.Right="Derecha"
Position.Bottom="Inferior"
Transition="Transición"
Transition.None="Ninguna"
MatchName="Compara si el nombre de la fuente"
NamePartMatch="contiene el nombre de la otra fuente"
NameNumberMatch="con los números eliminados del final coincide con el nombre de otra fuente"
NameLastWordMatch="con la última palabra eliminada coincide con el nombre de otra fuente"
TransitionScaleType="Tipo de escala"
TransitionScale.MaxOnly="Máx solo: Escala con relación de aspecto, sólo hasta el tamaño máximo de cada fuente"
TransitionScale.Aspect="Aspecto: Escala siempre las fuentes, pero mantiene la relación de aspecto"
TransitionScale.Stretch="Estirar: Escala y estira las fuentes al tamaño de la transición"
MoveTransitionOverrideFilter="Mover - Anular transición"
NoOverride="Sin anulación"
Yes="Si"
No="No"
StartMove="Iniciar Mover Filtro"
StartMoveMatchFrom="Iniciar Mover Filtro desde"
StartMoveMatchTo="Iniciar Mover Filtro hasta"
MoveSourceFilter="Mover Fuente"
ScenesOnlyFilter="Este filtro sólo funciona en escenas y grupos"
General="General"
TransformRelative="Transformación relativa"
Transform="Transformación"
GetTransform="Obtener transformación"
CustomDuration="Duración personalizada"
Duration="Duración"
Start="Iniciar"
SwitchPoint="Punto de cambio"
Source="Fuente"
MatchSource="Coincidir con fuente"
MoveAll="General"
CacheTransitions="Transiciones en caché"
StartTrigger="Activador de inicio"
StartTrigger.None="Ninguno: No se inicia automáticamente, use una tecla de acceso rápido o el siguiente movimiento para iniciar"
StartTrigger.Activate="Activar: Cuando este filtro se vuelve activo, mostrándose en la mezcla final"
StartTrigger.Deactivate="Desactivar: Cuando este filtro deja de estar activo, no mostrándose en la mezcla final"
StartTrigger.Show="Mostrar: Cuando este filtro se muestra en algún lugar, en cualquier previsualización o en la salida final"
StartTrigger.Hide="Ocultar: Cuando este filtro no se está mostrando en ninguna parte"
StartTrigger.Enable="Habilitar: Cuando el icono del ojo delante de este filtro está habilitado"
StartTrigger.SourceActivate="Activar Fuente: Cuando la fuente se vuelve activa, mostrándose en la mezcla final"
StartTrigger.SourceDeactivate="Desactivar Fuente: Cuando la fuente deja de estar activa, no mostrándose en la mezcla final"
StartTrigger.SourceShow="Mostrar Fuente: Cuando la fuente se muestra en algún lugar, en cualquier previsualización o en la salida final"
StartTrigger.SourceHide="Ocultar Fuente: Cuando la fuente no se está mostrando en ninguna parte"
StartTrigger.MediaStarted="Medio Iniciado: Cuando la fuente multimedia comienza a reproducirse"
StartTrigger.MediaEnded="Medio Finalizado: Cuando la reproducción de la fuente multimedia ha finalizado"
StartTrigger.Load="Carga: Cuando este filtro se carga o actualiza"
StopTrigger="Activador de detención"
StopTrigger.None="Ninguno: Detener sólo cuando el movimiento ha terminado o este filtro está deshabilitado"
Actions="Acciones"
SimultaneousMove="Mover simultáneamente"
SimultaneousMove.None="Ninguno"
NextMove="Siguiente movimiento"
NextMove.None="Ninguno"
NextMove.Reverse="Revertir"
NextMoveOn="Activar siguiente movimiento"
NextMoveOn.End="Al finalizar el movimiento"
NextMoveOn.Hotkey="Con tecla de acceso rápido"
StartDelay="Retardar inicio"
EndDelay="Retardar final"
StartDelayTo="Retardar inicio hasta"
EndDelayTo="Retardar final hasta"
StartDelayFrom="Retardar inicio desde"
EndDelayFrom="Retardar final desde"
MoveValueFilter="Mover Valor"
Filter="Filtro"
Filter.None="Ninguno"
MoveValueType="Tipo de valor"
MoveValueType.SingleSetting="Ajuste individual"
MoveValueType.Settings="Ajustes"
MoveValueType.Random="Aleatorio"
MoveValueType.SettingAdd="Añadir"
MoveValueType.Type="Escribiendo"
FormatType="Tipo de formato"
FormatType.Decimals="Número de decimales"
FormatType.Float="Formato flotante usando printf"
FormatType.Time="Formato de tiempo usando strftime"
Format="Formato"
Settings="Ajustes"
Setting="Ajuste"
Setting.None="Ninguno"
Setting.Volume="Volumen de la fuente"
Decimals="Decimales"
Value="Valor"
MinValue="Valor Min"
MaxValue="Valor Max"
Text="Texto"
GetValue="Obtener Valor"
GetValues="Obtener Valores"
VisibilityOrder="Visibilidad y Orden"
ChangeVisibility="Visibilidad"
ChangeVisibility.No="Sin cambios"
ChangeVisibility.ShowStart="Mostrar al iniciar el movimiento"
ChangeVisibility.ShowEnd="Mostrar al finalizar el movimiento"
ChangeVisibility.ShowStartEnd="Mostrar mientras se realiza el movimiento"
ChangeVisibility.HideStart="Ocultar al iniciar el movimiento"
ChangeVisibility.HideEnd="Ocultar al finalizar el movimiento"
ChangeVisibility.HideStartEnd="Ocultar mientras se realiza el movimiento"
ChangeVisibility.Toggle="Alternar"
ChangeVisibility.ToggleStart="Alternar al iniciar el movimiento"
ChangeVisibility.ToggleEnd="Alternar al finalizar el movimiento"
ChangeOrder="Orden"
ChangeOrder.No="Sin cambios"
ChangeOrder.StartRelative="Inicio Relativo"
ChangeOrder.EndRelative="Final Relativo"
ChangeOrder.StartAbsolute="Inicio Absoluto"
ChangeOrder.EndAbsolute="Final Absoluto"
OrderPosition="Diferencia de Orden / Posición"
MediaAction="Multimedia"
MediaAction.Start="Acción inicial"
MediaAction.End="Acción final"
MediaAction.None="Ninguna"
MediaAction.Play="Reproducir"
MediaAction.Pause="Pausa"
MediaAction.Stop="Detener"
MediaAction.Restart="Reiniciar"
MediaAction.Next="Siguiente"
MediaAction.Previous="Anterior"
MediaAction.PlayFrom="Reproducir desde"
MediaAction.PauseAt="Pausar en"
MediaAction.Time="Tiempo"
AudioAction="Audio"
MuteAction="Silenciar"
MuteAction.None="Ninguna"
MuteAction.MuteStart="Silenciar al inicio"
MuteAction.MuteEnd="Silenciar al finalizar"
MuteAction.UnmuteStart="No silenciar al inicio"
MuteAction.UnmuteEnd="No silenciar al finalizar"
MuteAction.MuteDuring="Silenciar durante: Silenciar al inicio y dejar de silenciar al final"
MuteAction.UnmuteDuring="No silenciar durante: No silenciar al inicio y silenciar al final"
AudioFade="Desvanecimiento"
EnabledMatchMoving="El filtro sólo se habilita cuando se mueve"
AudioMoveFilter="Mover Audio"
MeterType="Tipo de medidor"
MeterType.Magnitude="Magnitud"
MeterType.PeakSample="Pico de muestra"
MeterType.PeakTrue="True Peak"
MeterType.InputPeakSample="Entrada Pico de muestra"
MeterType.InputPeakTrue="Entrada True Peak"
ValueAction="Acción"
ValueAction.Transform="Transformar"
ValueAction.Setting="Ajuste"
ValueAction.SourceVisibility="Visibilidad de la fuente"
ValueAction.FilterEnable="Habilitar filtro"
Scene="Escena"
Filter="Filtro"
Transform.PosX="Posición X"
Transform.PosY="Posición Y"
Transform.Rotation="Rotación"
Transform.Scale="Escala"
Transform.ScaleX="Escala X"
Transform.ScaleY="Escala Y"
Transform.BoundsX="LÃmites X"
Transform.BoundsY="LÃmites Y"
Transform.CropLeft="Recorte Izquierda"
Transform.CropTop="Recorte Arriba"
Transform.CropRight="Recorte Derecha"
Transform.CropBottom="Recorte Abajo"
Transform.CropHorizontal="Recorte Horizontal"
Transform.CropVertical="Recorte Vertical"
BaseValue="Valor Base"
Factor="Factor"
ThresholdAction="Acción de umbral"
ThresholdAction.None="Ninguna"
ThresholdAction.EnableOver="Habilitar por encima"
ThresholdAction.EnableUnder="Habilitar por debajo"
ThresholdAction.DisableOver="Deshabilitar por encima"
ThresholdAction.DisableUnder="Deshabilitar por debajo"
ThresholdAction.EnableOverDisableUnder="Habilitar por encima y deshabilitar por debajo"
ThresholdAction.EnableUnderDisableOver="Habilitar por debajo y deshabilitar por encima"
Threshold="Umbral"
obs-move-transition-2.5.7/data/locale/nl-NL.ini 0000664 0000000 0000000 00000005256 14177464325 0021262 0 ustar 00root root 0000000 0000000 Move="Move"
MoveTransition="Move transitie"
Description="Transitie die alle bronnen naar een nieuwe plek verplaats"
MoveMatch="Gekoppelde items"
MoveIn="Verschijnende items"
MoveOut="Verdwijnende items"
Easing="Soepel"
Easing.None="Niet soepel"
Easing.In="Soepel in"
Easing.Out="Soepel uit"
Easing.InOut="Soepel in en uit"
EasingFunction="Soepel functie"
EasingFunction.Quadratic="Tweedegraads"
EasingFunction.Cubic="Derdegraads"
EasingFunction.Quartic="Vierdegraads"
EasingFunction.Quintic="Vijfdegraads"
EasingFunction.Sine="Sinus"
EasingFunction.Circular="Cirkelvormig"
EasingFunction.Exponential="Exponentieel"
EasingFunction.Elastic="Elastiek"
EasingFunction.Bounce="Stuiter"
EasingFunction.Back="Terug"
Position="Positie"
Zoom="Zoem"
Curve="Kromming"
CurveOverride="Overschrijf kromming"
Position.None="Geen"
Position.Center="Midden"
Position.CenterInverse="Weg van het midden"
Position.TopLeft="Linksboven"
Position.TopCenter="Middenboven"
Position.TopRight="Rechtsboven"
Position.CenterRight="Rechtsmidden"
Position.BottomRight="Rechtsonder"
Position.BottomCenter="Middenonder"
Position.BottomLeft="Linksonder"
Position.CenterLeft="Linksmidden"
Position.Left="Links"
Position.Top="Boven"
Position.Right="Rechts"
Position.Bottom="Beneden"
Transition="Transitie"
Transition.None="Geen"
MatchName="Match als de bron naam"
NamePartMatch="de andere bron naam bevat"
NameNumberMatch="met cijfers verwijderd van het einde overeen komt met de andere bron naam"
NameLastWordMatch="met het laatste woord verwijderd overeen komt met de andere bron naam"
TransitionScaleType="Transitie move schaal type"
TransitionScale.MaxOnly="Alleen max: Schaal naar aspectverhouding tot maximum de grootte van de bron"
TransitionScale.Aspect="Aspect: Altijd de bronnen schalen, maar behoud de aspectverhouding"
TransitionScale.Stretch="Uitrekken: Schaalt en rekt de bronnen naar de grootte van transistie"
MoveTransitionOverrideFilter="Move transitie overschrijven"
NoOverride="Niet overschrijven"
Yes="Ja"
No="Nee"
MoveSourceFilter="Move Bron"
ScenesOnlyFilter="Dit filter werkt alleen op scenes"
Transform="Transformatie"
GetTransform="Transformatie ophalen"
Duration="Duur"
Start="Start"
SwitchPoint="Schakel Punt"
Source="Bron"
MatchSource="Match bron"
MoveAll="Algemeen"
CacheTransitions="Cache transities"
StartTrigger="Start trigger"
StartTrigger.None="Geen"
StartTrigger.Activate="Activeren"
StartTrigger.Deactivate="Deactiveren"
StartTrigger.Show="Tonen"
StartTrigger.Hide="Verbergen"
StartTrigger.Enable="Inschakelen"
NextMove="Volgende Move"
NextMove.None="Geen"
StartDelay="Start vertraging"
MoveValueFilter="Move waarde"
Filter="Filter"
Filter.None="Geen"
Setting="Instelling"
Setting.None="Geen"
Value="Waarde"
GetValue="Waarde ophalen"
obs-move-transition-2.5.7/data/locale/pt-BR.ini 0000664 0000000 0000000 00000020721 14177464325 0021260 0 ustar 00root root 0000000 0000000 Move="Mover"
MoveTransition="Mover Transição"
Description="Transição que move todas as fontes para uma nova posição"
MoveMatch="Itens Correspondidos"
MoveIn="Itens Aparecendo"
MoveOut="Itens Desaparecendo"
Easing="Suavização"
Easing.None="Não suavizar"
Easing.In="Suavizar entrada"
Easing.Out="Suavizar saÃda"
Easing.InOut="Suavizar entrada e saÃda"
EasingFunction="Função de Suavização"
EasingFunction.Quadratic="Quadrática"
EasingFunction.Cubic="Cúbica"
EasingFunction.Quartic="Quártica"
EasingFunction.Quintic="QuÃntica"
EasingFunction.Sine="Senoidal"
EasingFunction.Circular="Circular"
EasingFunction.Exponential="Exponencial"
EasingFunction.Elastic="Elástica"
EasingFunction.Bounce="Salto"
EasingFunction.Back="Retorno"
Position="Posição"
Zoom="Ampliar"
Curve="Curva"
CurveOverride="Sobrepor Curva"
Position.None="Nenhuma"
Position.Center="Centralizada"
Position.CenterInverse="Longe do centro"
Position.TopLeft="Superior esquerda"
Position.TopCenter="Superior centralizada"
Position.TopRight="Superior direita"
Position.CenterRight="Centro direita"
Position.BottomRight="Inferior direita"
Position.BottomCenter="Inferior centralizada"
Position.BottomLeft="Inferior esquerda"
Position.CenterLeft="Centro esquerda"
Position.Left="Esquerda"
Position.Top="Superior"
Position.Right="Direita"
Position.Bottom="Inferior"
Transition="Transição"
Transition.None="Nenhuma"
MatchName="Corresponder se o nome da fonte"
NamePartMatch="contém o nome da outra fonte"
NameNumberMatch="com números removidos do final, coincide com o nome da outra fonte"
NameLastWordMatch="com a última palavra removida, coincide com o nome da outra fonte"
TransitionScaleType="Escala de Transição"
TransitionScale.MaxOnly="Máxima: escalar para a proporção, mas apenas para o tamanho máximo de cada fonte"
TransitionScale.Aspect="Aspecto: sempre escalar as fontes, mas manter a proporção"
TransitionScale.Stretch="Esticada: escalar e esticar as fontes para o tamanho da transição"
MoveTransitionOverrideFilter="Mover/Sobrepor Transição"
NoOverride="Não sobrepor"
Yes="Sim"
No="Não"
StartMove="Iniciar Filtro Mover"
StartMoveMatchFrom="Iniciar Filtro Mover de"
StartMoveMatchTo="Iniciar Filtro Mover para"
MoveSourceFilter="Mover/Fonte"
ScenesOnlyFilter="Este filtro funciona apenas em cenas e grupos"
General="Configurações gerais"
TransformRelative="Transformação Relativa"
Transform="Transformação"
GetTransform="Obter Transformação"
CustomDuration="Duração Customizada"
Duration="Duração"
Start="Iniciar"
SwitchPoint="Ponto de Mudança"
Source="Fonte"
MatchSource="Corresponder com a fonte"
MoveAll="Configurações gerais"
CacheTransitions="Cache de Transições"
StartTrigger="Gatilho de InÃcio"
StartTrigger.None="Nenhum: não é iniciado automaticamente, use uma tecla de atalho ou mover próximo para iniciar esta transição"
StartTrigger.Activate="Ativado: quando este filtro se torna ativo mostrando na saÃda final"
StartTrigger.Deactivate="Desativado: quando este filtro fica inativo, não mostrando na saÃda final"
StartTrigger.Show="Mostrado: este filtro está sendo exibido em qualquer lugar, seja em um contexto de exibição ou na saÃda final"
StartTrigger.Hide="Ocultado: quando este filtro não está sendo exibido em nenhum lugar"
StartTrigger.Enable="Habilitado: quando o Ãcone de olho na frente deste filtro está habilitado"
StartTrigger.SourceActivate="Fonte Ativada: quando a fonte se torna ativa mostrando na saÃda final"
StartTrigger.SourceDeactivate="Fonte Desativada: quando a fonte fica inativa, não mostrando na saÃda final"
StartTrigger.SourceShow="Fonte VisÃvel: quando a fonte está sendo exibida em qualquer lugar, seja em um contexto de exibição ou na saÃda final"
StartTrigger.SourceHide="Fonte Ocultada: quando a fonte não está sendo exibida em nenhum lugar"
StartTrigger.MediaStarted="MÃdia Iniciada: quando a fonte de mÃdia começar a tocar"
StartTrigger.MediaEnded="MÃdia Finalizada: quando a reprodução da fonte de mÃdia terminar"
StartTrigger.Load="Carregado: quando este filtro for carregado ou atualizado"
StopTrigger="Gatilho de Parada"
StopTrigger.None="Nenhum: parar apenas quando a movimentação for concluÃda ou este filtro for desativado"
Actions="Ações"
SimultaneousMove="Mover Simultaneamente"
SimultaneousMove.None="Não mover"
NextMove="Próxima Ação"
NextMove.None="Nenhuma"
NextMove.Reverse="Reverter"
NextMoveOn="Próxima Ação ao"
NextMoveOn.End="Finalizar o movimento"
NextMoveOn.Hotkey="Usar uma tecla de atalho"
StartDelay="Atraso Inicial"
EndDelay="Atraso Final"
StartDelayTo="Atraso Inicial para"
EndDelayTo="Atraso Final para"
StartDelayFrom="Atraso Inicial de"
EndDelayFrom="Atraso Final de"
MoveValueFilter="Mover/Valor"
Filter="Filtro"
Filter.None="Nenhum"
MoveValueType="Mover/Valor Tipo"
MoveValueType.SingleSetting="Propriedade Individual"
MoveValueType.Settings="Propriedades"
MoveValueType.Random="Aleatório"
MoveValueType.SettingAdd="Adicionar"
MoveValueType.Type="Digitando"
FormatType="Tipo de formato"
FormatType.Decimals="Número de decimais"
FormatType.Float="Formato flutuante usando printf"
FormatType.Time="Formato de tempo usando strftime"
Format="Formato"
Settings="Propriedades"
Setting="Propriedade"
Setting.None="Nenhuma"
Decimals="Decimais"
Value="Valor"
MinValue="MÃnimo"
MaxValue="Máximo"
Text="Texto"
GetValue="Obter Valor"
GetValues="Obter Valores"
VisibilityOrder="Visibilidade e Ordenação"
ChangeVisibility="Visibilidade"
ChangeVisibility.No="Não alterar"
ChangeVisibility.ShowStart="Mostrar no inÃcio do movimento"
ChangeVisibility.ShowEnd="Mostrar no final do movimento"
ChangeVisibility.ShowStartEnd="Mostrar durante o movimento"
ChangeVisibility.HideStart="Ocultar no inÃcio do movimento"
ChangeVisibility.HideEnd="Ocultar no final do movimento"
ChangeVisibility.HideStartEnd="Ocultar durante o movimento"
ChangeVisibility.Toggle="Alternar durante o movimento"
ChangeVisibility.ToggleStart="Alternar no inÃcio do movimento"
ChangeVisibility.ToggleEnd="Alternar no final do movimento"
ChangeOrder="Ordenação"
ChangeOrder.No="Não alterar"
ChangeOrder.StartRelative="InÃcio relativo"
ChangeOrder.EndRelative="Final relativo"
ChangeOrder.StartAbsolute="InÃcio absoluto"
ChangeOrder.EndAbsolute="Final absoluto"
OrderPosition="Diferença / Posição"
MediaAction="MÃdia"
MediaAction.Start="Iniciar ação"
MediaAction.End="Finalizar ação"
MediaAction.None="Nenhuma"
MediaAction.Play="Reproduzir"
MediaAction.Pause="Pausar"
MediaAction.Stop="Parar"
MediaAction.Restart="Reiniciar"
MediaAction.Next="Próximo"
MediaAction.Previous="Anterior"
MediaAction.PlayFrom="Reproduzir de"
MediaAction.PauseAt="Pausar em"
MediaAction.Time="Tempo"
AudioAction="Ãudio"
MuteAction="Silenciar"
MuteAction.None="Nenhum"
MuteAction.MuteStart="Silenciar no inÃcio"
MuteAction.MuteEnd="Silenciar no final"
MuteAction.UnmuteStart="Ativar no inÃcio"
MuteAction.UnmuteEnd="Reativar no final"
MuteAction.MuteDuring="Silenciar Durante: silenciar no inÃcio e reativar no final"
MuteAction.UnmuteDuring="Ativar Durante: ativar no inÃcio e silenciar no final"
AudioFade="Desvanecimento"
EnabledMatchMoving="Habilitar filtro apenas ao mover"
AudioMoveFilter="Mover/Ãudio"
MeterType="Tipo de Medidor"
MeterType.Magnitude="Magnitude"
MeterType.PeakSample="Amostra de pico"
MeterType.PeakTrue="Pico verdadeiro"
MeterType.InputPeakSample="Amostra de pico de entrada"
MeterType.InputPeakTrue="Pico de entrada verdadeiro"
ValueAction="Ação"
ValueAction.Transform="Transformar"
ValueAction.Setting="Configurar"
ValueAction.SourceVisibility="Alterar visibilidade da fonte"
ValueAction.FilterEnable="Habilitar filtro"
Scene="Cena"
Filter="Filtro"
Transform.PosX="Posicionar em X"
Transform.PosY="Posicionar em Y"
Transform.Rotation="Rotacionar"
Transform.Scale="Escalar"
Transform.ScaleX="Escalar em X"
Transform.ScaleY="Escalar em Y"
Transform.BoundsX="Limitar em X"
Transform.BoundsY="Limitar em Y"
Transform.CropLeft="Cortar à esquerda"
Transform.CropTop="Cortar parte superior"
Transform.CropRight="Cortar à direita"
Transform.CropBottom="Cortar parte inferior"
Transform.CropHorizontal="Cortar na horizontal"
Transform.CropVertical="Cortar na vertical"
BaseValue="Valor Base"
Factor="Fator"
ThresholdAction="Ação Limiar"
ThresholdAction.None="Nenhuma"
ThresholdAction.EnableOver="Habilitar acima"
ThresholdAction.EnableUnder="Habilitar abaixo"
ThresholdAction.DisableOver="Desabilitar acima"
ThresholdAction.DisableUnder="Desabilitar abaixo"
ThresholdAction.EnableOverDisableUnder="Habilitar acima e desabilitar abaixo"
ThresholdAction.EnableUnderDisableOver="Habilitar abaixo e desabilitar acima"
Threshold="Limiar"
obs-move-transition-2.5.7/data/locale/ru-RU.ini 0000664 0000000 0000000 00000022470 14177464325 0021311 0 ustar 00root root 0000000 0000000 Move="Движение"
MoveTransition="ДвижущийÑÑ ÐŸÐµÑ€ÐµÑ…Ð¾Ð´"
Description="Переход который перемещает вÑе иÑточники в новую позицию"
MoveMatch="Одинаковые Ñлементы"
MoveIn="ПоÑвлÑющиеÑÑ Ñлементы"
MoveOut="ИÑчезающие Ñлементы"
Easing="ÐнимациÑ"
Easing.None="Ðет"
Easing.In="Плавный вход"
Easing.Out="Плавный выход"
Easing.InOut="Плавный вход и выход"
EasingFunction="Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿Ð»Ð°Ð²Ð½Ð¾Ñти"
EasingFunction.Quadratic="КвадратичнаÑ"
EasingFunction.Cubic="КубичеÑкаÑ"
EasingFunction.Quartic="ЧетвертичнаÑ"
EasingFunction.Quintic="КвинтичеÑкаÑ"
EasingFunction.Sine="СинуÑоваÑ"
EasingFunction.Circular="КруговаÑ"
EasingFunction.Exponential="ÐкÑпоненциальнаÑ"
EasingFunction.Elastic="УпругаÑ"
EasingFunction.Bounce="ОтÑкакивающаÑ"
EasingFunction.Back="ОбратнаÑ"
Position="ПозициÑ"
Zoom="Увеличение"
Curve="КриваÑ"
CurveOverride="Указать другую кривую"
Position.None="Ðет"
Position.Center="Центр"
Position.CenterInverse="Вдали от центра"
Position.TopLeft="Сверху Ñлева"
Position.TopCenter="Сверху по центру"
Position.TopRight="Сверху Ñправа"
Position.CenterRight="Справа по центру"
Position.BottomRight="Снизу Ñправа"
Position.BottomCenter="Снизу по центру"
Position.BottomLeft="Слева Ñнизу"
Position.CenterLeft="Слева по центру"
Position.Left="Слева"
Position.Top="Сверху"
Position.Right="Справа"
Position.Bottom="Снизу"
Transition="Переход"
Transition.None="Ðет"
MatchName="СоответÑтвовать еÑли Ð¸Ð¼Ñ Ð¸Ñточника"
NamePartMatch="Ñодержит другое Ð¸Ð¼Ñ Ð¸Ñточника"
NameNumberMatch="Ñодержит другое Ð¸Ð¼Ñ Ð¸Ñточника без цифр в конце"
NameLastWordMatch="Ñодержит другое Ð¸Ð¼Ñ Ð¸Ñточника без Ñлова в конце"
TransitionScaleType="Тип маÑштабированного перехода"
TransitionScale.MaxOnly="МакÑимальный: маÑштабировать до ÑÐ¾Ð¾Ñ‚Ð½Ð¾ÑˆÐµÐ½Ð¸Ñ Ñторон,но только до макÑимального размера каждого иÑточника"
TransitionScale.Aspect="ÐÑпект: вÑегда маÑштабировать иÑточники,но ÑохранÑть Ñоотношение Ñторон "
TransitionScale.Stretch="РаÑÑ‚Ñгивание: маÑштабировать и раÑÑ‚Ñгивать иÑточники до размера перехода"
MoveTransitionOverrideFilter="Указать другой движущийÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´"
NoOverride="Ðе указывать"
Yes="Да"
No="Ðет"
MoveSourceFilter="ПеремеÑтить иÑточник"
ScenesOnlyFilter="Ðтот фильтр работает только на Ñценах и группах"
General="Общие"
TransformRelative="ТранÑформировать ОтноÑительно"
Transform="ТранÑформировать"
GetTransform="Получить транÑформацию"
CustomDuration="ÐаÑÑ‚Ñ€Ð°Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñть"
Duration="ПродолжительноÑть"
Start="Ðачать"
SwitchPoint="Точка переключениÑ"
Source="ИÑточник"
MoveAll="Общие"
CacheTransitions="КÑшировать Переходы"
StartTrigger="ЗапуÑк Триггера"
StartTrigger.None="Ðет: не запуÑкать автоматичеÑки,иÑпользовать горÑчую клавишу или Ñледующие движение чтобы запуÑтить Ñто движение"
StartTrigger.Activate="Ðктивировать: Когда Ñтот фильтр ÑтановитÑÑ Ð²Ð¸Ð´ÐµÐ½ в финальном микÑе"
StartTrigger.Deactivate="Деактивировать: Когда Ñтот фильтр больше не виден, он не отображаетÑÑ Ð² финальном микÑе"
StartTrigger.Show="Показать: Ðтот фильтр виден хоть где-то, либо в контекÑте диÑплеÑ, либо в финальном выводе"
StartTrigger.Hide="Скрыть: Когда Ñтот фильтр нигде не виден"
StartTrigger.Enable="Включить: Когда значок напротив Ñтого фильтра включен"
StartTrigger.EnableDisable="Включить & Выключить: Триггер на включение и выключение когда движение закончено"
StartTrigger.SourceActivate="Ðктивированный ИÑточник: Когда иÑточник ÑтановитÑÑ Ð²Ð¸Ð´ÐµÐ½ в финальном микÑе"
StartTrigger.SourceDeactivate="Деактивированный ИÑточник: Когда иÑточник больше не виден, он не отображаетÑÑ Ð² финальном микÑе"
StartTrigger.SourceShow="ИÑточник Виден: ИÑточник виден хоть где-то, либо в контекÑте диÑплеÑ, либо в финальном выводе"
StartTrigger.SourceHide="ИÑточник Скрыт: Когда иÑточник нигде не виден"
StartTrigger.MediaStarted="Медиа Запущено: Когда медиа иÑточника начинает воÑпроизводитÑÑ"
StartTrigger.MediaEnded="Медиа Завершено: Когда медиа иÑточника завершено"
StopTrigger="ОÑтановка Триггера"
StopTrigger.None="Ðет: оÑтанавливатÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ еÑли движение закончено либо Ñтот фильтр отключен"
Actions="ДейÑтвиÑ"
SimultaneousMove="Одновременное Движение"
SimultaneousMove.None="Ðет"
NextMove="Следующее Движение"
NextMove.None="Ðет"
NextMove.Reverse="Обратное"
NextMoveOn="Следующее Движение Ðа"
NextMoveOn.End="Конец ДвижениÑ"
NextMoveOn.Hotkey="ГорÑчую клавишу"
StartDelay="Задержка ЗапуÑка"
EndDelay="Задержка Конца"
StartDelayTo="Задержка ЗапуÑка До"
EndDelayTo="Задержка Конца До"
StartDelayFrom="Задержка ЗапуÑка От"
EndDelayFrom="Задержка Конца От"
MoveValueFilter="Движение ЗначениÑ"
Filter="Фильтр"
Filter.None="Ðет"
SingleSetting="ÐžÐ´Ð¸Ð½Ð¾Ñ‡Ð½Ð°Ñ ÐаÑтройка"
Settings="ÐаÑтройки"
Setting="Параметр"
Setting.None="Ðет"
Value="Значение"
GetValue="Получить Значение"
GetValues="Получить ЗначениÑ"
VisibilityOrder="ВидимоÑть И ПорÑдок"
ChangeVisibility="ВидимоÑть"
ChangeVisibility.No="Ðе менÑть"
ChangeVisibility.ShowStart="Показать в начале движениÑ"
ChangeVisibility.ShowEnd="Показать в конце движениÑ"
ChangeVisibility.ShowStartEnd="Показать во Ð²Ñ€ÐµÐ¼Ñ Ð´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ"
ChangeVisibility.HideStart="Скрыть в начале движениÑ"
ChangeVisibility.HideEnd="Скрыть в конце движениÑ"
ChangeVisibility.HideStartEnd="Скрыть во Ð²Ñ€ÐµÐ¼Ñ Ð´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ"
ChangeVisibility.Toggle="Переключить"
ChangeVisibility.ToggleStart="Переключить в начале движениÑ"
ChangeVisibility.ToggleEnd="Переключить в конце движениÑ"
ChangeOrder="ПорÑдок"
ChangeOrder.No="Ðе менÑть"
ChangeOrder.StartRelative="ЗапуÑк ОтноÑительно"
ChangeOrder.EndRelative="Конец ОтноÑительно"
ChangeOrder.StartAbsolute="ЗапуÑк ÐбÑолютно"
ChangeOrder.EndAbsolute="Конец ÐбÑолютно"
OrderPosition="Разница / ПозициÑ"
MediaAction="МедиÑ"
MediaAction.Start="ЗапуÑк ДейÑтвиÑ"
MediaAction.End="Конец ДейÑтвиÑ"
MediaAction.None="Ðет"
MediaAction.Play="ВоÑпроизвеÑти"
MediaAction.Pause="ПриоÑтановить"
MediaAction.Stop="ОÑтановить"
MediaAction.Restart="ПерезапуÑтить"
MediaAction.Next="Следующее"
MediaAction.Previous="Предыдущее"
MediaAction.PlayFrom="ВоÑпроизвеÑти Ñ"
MediaAction.PauseAt="ПриоÑтановить в"
MediaAction.Time="ВремÑ"
AudioAction="Ðудио"
MuteAction="Отключить звук"
MuteAction.None="Ðет"
MuteAction.MuteStart="Заглушить при ЗапуÑке"
MuteAction.MuteEnd="Заглушить в Конце"
MuteAction.UnmuteStart="Включить звук при ЗапуÑке"
MuteAction.UnmuteEnd="Включить звук в Конце"
MuteAction.MuteDuring="Выключить звук во времÑ: Выключить при ЗапуÑке Включить в Конце"
MuteAction.UnmuteDuring="Включить звук во времÑ: Включить при ЗапуÑке Выключить в Конце"
AudioFade="Затухание"
obs-move-transition-2.5.7/easing.c 0000664 0000000 0000000 00000014015 14177464325 0017074 0 ustar 00root root 0000000 0000000 //
// easing.c
//
// Copyright (c) 2011, Auerhaus Development, LLC
//
// This program is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What The Fuck You Want
// To Public License, Version 2, as published by Sam Hocevar. See
// http://sam.zoy.org/wtfpl/COPYING for more details.
//
#include
#include "easing.h"
// Modeled after the line y = x
AHFloat LinearInterpolation(AHFloat p)
{
return p;
}
// Modeled after the parabola y = x^2
AHFloat QuadraticEaseIn(AHFloat p)
{
return p * p;
}
// Modeled after the parabola y = -x^2 + 2x
AHFloat QuadraticEaseOut(AHFloat p)
{
return -(p * (p - 2));
}
// Modeled after the piecewise quadratic
// y = (1/2)((2x)^2) ; [0, 0.5)
// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
AHFloat QuadraticEaseInOut(AHFloat p)
{
if (p < 0.5) {
return 2 * p * p;
} else {
return (-2 * p * p) + (4 * p) - 1;
}
}
// Modeled after the cubic y = x^3
AHFloat CubicEaseIn(AHFloat p)
{
return p * p * p;
}
// Modeled after the cubic y = (x - 1)^3 + 1
AHFloat CubicEaseOut(AHFloat p)
{
AHFloat f = (p - 1);
return f * f * f + 1;
}
// Modeled after the piecewise cubic
// y = (1/2)((2x)^3) ; [0, 0.5)
// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
AHFloat CubicEaseInOut(AHFloat p)
{
if (p < 0.5) {
return 4 * p * p * p;
} else {
AHFloat f = ((2 * p) - 2);
return 0.5 * f * f * f + 1;
}
}
// Modeled after the quartic x^4
AHFloat QuarticEaseIn(AHFloat p)
{
return p * p * p * p;
}
// Modeled after the quartic y = 1 - (x - 1)^4
AHFloat QuarticEaseOut(AHFloat p)
{
AHFloat f = (p - 1);
return f * f * f * (1 - p) + 1;
}
// Modeled after the piecewise quartic
// y = (1/2)((2x)^4) ; [0, 0.5)
// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
AHFloat QuarticEaseInOut(AHFloat p)
{
if (p < 0.5) {
return 8 * p * p * p * p;
} else {
AHFloat f = (p - 1);
return -8 * f * f * f * f + 1;
}
}
// Modeled after the quintic y = x^5
AHFloat QuinticEaseIn(AHFloat p)
{
return p * p * p * p * p;
}
// Modeled after the quintic y = (x - 1)^5 + 1
AHFloat QuinticEaseOut(AHFloat p)
{
AHFloat f = (p - 1);
return f * f * f * f * f + 1;
}
// Modeled after the piecewise quintic
// y = (1/2)((2x)^5) ; [0, 0.5)
// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
AHFloat QuinticEaseInOut(AHFloat p)
{
if (p < 0.5) {
return 16 * p * p * p * p * p;
} else {
AHFloat f = ((2 * p) - 2);
return 0.5 * f * f * f * f * f + 1;
}
}
// Modeled after quarter-cycle of sine wave
AHFloat SineEaseIn(AHFloat p)
{
return sin((p - 1) * M_PI_2) + 1;
}
// Modeled after quarter-cycle of sine wave (different phase)
AHFloat SineEaseOut(AHFloat p)
{
return sin(p * M_PI_2);
}
// Modeled after half sine wave
AHFloat SineEaseInOut(AHFloat p)
{
return 0.5 * (1 - cos(p * M_PI));
}
// Modeled after shifted quadrant IV of unit circle
AHFloat CircularEaseIn(AHFloat p)
{
return 1 - sqrt(1 - (p * p));
}
// Modeled after shifted quadrant II of unit circle
AHFloat CircularEaseOut(AHFloat p)
{
return sqrt((2 - p) * p);
}
// Modeled after the piecewise circular function
// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5)
// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]
AHFloat CircularEaseInOut(AHFloat p)
{
if (p < 0.5) {
return 0.5 * (1 - sqrt(1 - 4 * (p * p)));
} else {
return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1);
}
}
// Modeled after the exponential function y = 2^(10(x - 1))
AHFloat ExponentialEaseIn(AHFloat p)
{
return (p == 0.0) ? p : pow(2, 10 * (p - 1));
}
// Modeled after the exponential function y = -2^(-10x) + 1
AHFloat ExponentialEaseOut(AHFloat p)
{
return (p == 1.0) ? p : 1 - pow(2, -10 * p);
}
// Modeled after the piecewise exponential
// y = (1/2)2^(10(2x - 1)) ; [0,0.5)
// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]
AHFloat ExponentialEaseInOut(AHFloat p)
{
if (p == 0.0 || p == 1.0)
return p;
if (p < 0.5) {
return 0.5 * pow(2, (20 * p) - 10);
} else {
return -0.5 * pow(2, (-20 * p) + 10) + 1;
}
}
// Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))
AHFloat ElasticEaseIn(AHFloat p)
{
return sin(13 * M_PI_2 * p) * pow(2, 10 * (p - 1));
}
// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1
AHFloat ElasticEaseOut(AHFloat p)
{
return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1;
}
// Modeled after the piecewise exponentially-damped sine wave:
// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5)
// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1]
AHFloat ElasticEaseInOut(AHFloat p)
{
if (p < 0.5) {
return 0.5 * sin(13 * M_PI_2 * (2 * p)) *
pow(2, 10 * ((2 * p) - 1));
} else {
return 0.5 * (sin(-13 * M_PI_2 * ((2 * p - 1) + 1)) *
pow(2, -10 * (2 * p - 1)) +
2);
}
}
// Modeled after the overshooting cubic y = x^3-x*sin(x*pi)
AHFloat BackEaseIn(AHFloat p)
{
return p * p * p - p * sin(p * M_PI);
}
// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
AHFloat BackEaseOut(AHFloat p)
{
AHFloat f = (1 - p);
return 1 - (f * f * f - f * sin(f * M_PI));
}
// Modeled after the piecewise overshooting cubic function:
// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5)
// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1]
AHFloat BackEaseInOut(AHFloat p)
{
if (p < 0.5) {
AHFloat f = 2 * p;
return 0.5 * (f * f * f - f * sin(f * M_PI));
} else {
AHFloat f = (1 - (2 * p - 1));
return 0.5 * (1 - (f * f * f - f * sin(f * M_PI))) + 0.5;
}
}
AHFloat BounceEaseIn(AHFloat p)
{
return 1 - BounceEaseOut(1 - p);
}
AHFloat BounceEaseOut(AHFloat p)
{
if (p < 4 / 11.0) {
return (121 * p * p) / 16.0;
} else if (p < 8 / 11.0) {
return (363 / 40.0 * p * p) - (99 / 10.0 * p) + 17 / 5.0;
} else if (p < 9 / 10.0) {
return (4356 / 361.0 * p * p) - (35442 / 1805.0 * p) +
16061 / 1805.0;
} else {
return (54 / 5.0 * p * p) - (513 / 25.0 * p) + 268 / 25.0;
}
}
AHFloat BounceEaseInOut(AHFloat p)
{
if (p < 0.5) {
return 0.5 * BounceEaseIn(p * 2);
} else {
return 0.5 * BounceEaseOut(p * 2 - 1) + 0.5;
}
}
obs-move-transition-2.5.7/easing.h 0000664 0000000 0000000 00000004524 14177464325 0017105 0 ustar 00root root 0000000 0000000 //
// easing.h
//
// Copyright (c) 2011, Auerhaus Development, LLC
//
// This program is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What The Fuck You Want
// To Public License, Version 2, as published by Sam Hocevar. See
// http://sam.zoy.org/wtfpl/COPYING for more details.
//
#ifndef AH_EASING_H
#define AH_EASING_H
#if defined(__LP64__) && !defined(AH_EASING_USE_DBL_PRECIS)
#define AH_EASING_USE_DBL_PRECIS
#endif
#ifdef AH_EASING_USE_DBL_PRECIS
#define AH_FLOAT_TYPE float
#else
#define AH_FLOAT_TYPE float
#endif
typedef AH_FLOAT_TYPE AHFloat;
#if defined __cplusplus
extern "C" {
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#endif
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923 /* pi/2 */
#endif
typedef AHFloat (*AHEasingFunction)(AHFloat);
// Linear interpolation (no easing)
AHFloat LinearInterpolation(AHFloat p);
// Quadratic easing; p^2
AHFloat QuadraticEaseIn(AHFloat p);
AHFloat QuadraticEaseOut(AHFloat p);
AHFloat QuadraticEaseInOut(AHFloat p);
// Cubic easing; p^3
AHFloat CubicEaseIn(AHFloat p);
AHFloat CubicEaseOut(AHFloat p);
AHFloat CubicEaseInOut(AHFloat p);
// Quartic easing; p^4
AHFloat QuarticEaseIn(AHFloat p);
AHFloat QuarticEaseOut(AHFloat p);
AHFloat QuarticEaseInOut(AHFloat p);
// Quintic easing; p^5
AHFloat QuinticEaseIn(AHFloat p);
AHFloat QuinticEaseOut(AHFloat p);
AHFloat QuinticEaseInOut(AHFloat p);
// Sine wave easing; sin(p * PI/2)
AHFloat SineEaseIn(AHFloat p);
AHFloat SineEaseOut(AHFloat p);
AHFloat SineEaseInOut(AHFloat p);
// Circular easing; sqrt(1 - p^2)
AHFloat CircularEaseIn(AHFloat p);
AHFloat CircularEaseOut(AHFloat p);
AHFloat CircularEaseInOut(AHFloat p);
// Exponential easing, base 2
AHFloat ExponentialEaseIn(AHFloat p);
AHFloat ExponentialEaseOut(AHFloat p);
AHFloat ExponentialEaseInOut(AHFloat p);
// Exponentially-damped sine wave easing
AHFloat ElasticEaseIn(AHFloat p);
AHFloat ElasticEaseOut(AHFloat p);
AHFloat ElasticEaseInOut(AHFloat p);
// Overshooting cubic easing;
AHFloat BackEaseIn(AHFloat p);
AHFloat BackEaseOut(AHFloat p);
AHFloat BackEaseInOut(AHFloat p);
// Exponentially-decaying bounce easing
AHFloat BounceEaseIn(AHFloat p);
AHFloat BounceEaseOut(AHFloat p);
AHFloat BounceEaseInOut(AHFloat p);
#ifdef __cplusplus
}
#endif
#endif
obs-move-transition-2.5.7/installer.iss.in 0000664 0000000 0000000 00000007723 14177464325 0020614 0 ustar 00root root 0000000 0000000 ; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "@PROJECT_FULL_NAME@"
#define MyAppVersion "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@"
#define MyAppPublisher "Exeldro"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
; app Information
AppId={{83443BC3-6FCC-4A35-922E-1FF66F294AA4}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppMutex={#MyAppName}
VersionInfoVersion={#MyAppVersion}
VersionInfoCompany={#MyAppPublisher}
VersionInfoDescription={#MyAppName} Setup
; Compression
Compression=lzma2/ultra64
SolidCompression=yes
LZMAAlgorithm=1
; Other Information
DefaultDirName={code:GetDirName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
OutputDir="@ISS_FILES_DIR@"
OutputBaseFilename=@PROJECT_NAME@-installer
DirExistsWarning=no
; Wizard Information
WizardStyle=modern
WizardResizable=yes
SetupIconFile="@PROJECT_SOURCE_DIR@/media/icon.ico"
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: "@ISS_FILES_DIR@/*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "@ISS_PACKAGE_DIR@/msvc-redist-helper.exe"; DestDir: "{app}"; DestName: "msvc-redist-helper.exe"; Flags: ignoreversion dontcopy noencryption
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
[Code]
function GetDirName(Value: string): string;
var
InstallPath: string;
begin
// initialize default path, which will be returned when the following registry
// key queries fail due to missing keys or for some different reason
Result := ExpandConstant('{pf}\obs-studio');
// query the first registry value; if this succeeds, return the obtained value
if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then
Result := InstallPath
end;
/////////////////////////////////////////////////////////////////////
function GetUninstallString(): String;
var
sUnInstPath: String;
sUnInstallString: String;
begin
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
sUnInstallString := '';
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
Result := sUnInstallString;
end;
/////////////////////////////////////////////////////////////////////
function IsUpgrade(): Boolean;
begin
Result := (GetUninstallString() <> '');
end;
/////////////////////////////////////////////////////////////////////
function UnInstallOldVersion(): Integer;
var
sUnInstallString: String;
iResultCode: Integer;
begin
// Return Values:
// 1 - uninstall string is empty
// 2 - error executing the UnInstallString
// 3 - successfully executed the UnInstallString
// default return value
Result := 0;
// get the uninstall string of the old app
sUnInstallString := GetUninstallString();
if sUnInstallString <> '' then begin
sUnInstallString := RemoveQuotes(sUnInstallString);
if Exec(sUnInstallString, '/VERYSILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
Result := 3
else
Result := 2;
end else
Result := 1;
end;
/////////////////////////////////////////////////////////////////////
procedure CurStepChanged(CurStep: TSetupStep);
var
ResultCode: Integer;
begin
if (CurStep=ssInstall) then
begin
if (IsUpgrade()) then
begin
UnInstallOldVersion();
end;
end;
if (CurStep=ssPostInstall) then
begin
ExtractTemporaryFile('msvc-redist-helper.exe');
Exec(ExpandConstant('{tmp}\msvc-redist-helper.exe'), '2019', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
end;
obs-move-transition-2.5.7/media/ 0000775 0000000 0000000 00000000000 14177464325 0016540 5 ustar 00root root 0000000 0000000 obs-move-transition-2.5.7/media/icon.ico 0000664 0000000 0000000 00000073426 14177464325 0020200 0 ustar 00root root 0000000 0000000 h V ˆ ¾ ¨ F 00 ¨% î ßæ €2 –D ( à à ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ¸¸¸ÿ¸¸¸ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿáááÿùùùÿÿÿÿÿøøøÿ„„„ÿ„„„ÿøøøÿÿÿÿÿõõõÿâââÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼¼ÿQQQÿãããÿÿÿÿÿÿÿÿÿÐÐÐÿÐÐÐÿÿÿÿÿÿÿÿÿÍÍÍÿMMMÿÜÜÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿéééÿÂÂÂÿ±±±ÿóóóÿÿÿÿÿÒÒÒÿÒÒÒÿÿÿÿÿæææÿ¬¬¬ÿÂÂÂÿðððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÚÚÚÿ½½½ÿ»»»ÿ§§§ÿ§§§ÿ¼¼¼ÿ½½½ÿèèèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿüüüÿÿÿÿÿÿÿÿÿ™™™ÿÿÿÿÿÅÅÅÿÿÿÿÿÿÿÿÿöööÿüüüÿÿÿÿÿúúúÿŠŠŠÿŸŸŸÿÌÌÌÿÏÏÏÿˆˆˆÿ ÿ ÿ ÿÿ©©©ÿÆÆÆÿÆÆÆÿÿ¡¡¡ÿÿÿÿÿûûûÿ”””ÿ¨¨¨ÿÓÓÓÿÕÕÕÿŠŠŠÿ ÿ ÿ ÿ
ÿ²²²ÿÚÚÚÿÚÚÚÿ›››ÿ¸¸¸ÿÿÿÿÿÿÿÿÿýýýÿýýýÿÿÿÿÿÿÿÿÿ™™™ÿÿÿÿÿÂÂÂÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÕÕÕÿÂÂÂÿ»»»ÿ ÿ§§§ÿ¼¼¼ÿ···ÿÞÞÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááÿ»»»ÿ´´´ÿöööÿÿÿÿÿËËËÿÙÙÙÿÿÿÿÿîîîÿÿ²²²ÿîîîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿZZZÿïïïÿÿÿÿÿÿÿÿÿÈÈÈÿÖÖÖÿÿÿÿÿÿÿÿÿËËËÿUUUÿßßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóóóÿãããÿüüüÿÿÿÿÿôôôÿtttÿ‰‰‰ÿúúúÿÿÿÿÿùùùÿñññÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ¼¼¼ÿÈÈÈÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ( 0 à à ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñññÿzzzÿzzzÿñññÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÄÄÄÿ888ÿ888ÿÄÄÄÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöööÿ”””ÿ„„„ÿäääÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ²²²ÿ²²²ÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÏÏÏÿ~~~ÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëëëÿ///ÿ>>>ÿçççÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ···ÿ···ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÃÃÃÿÿhhhÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿ½½½ÿ°°°ÿ”””ÿòòòÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÙÙÙÿˆˆˆÿ¶¶¶ÿ»»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ···ÿ‘‘‘ÿôôôÿÿÿÿÿÿÿÿÿÀÀÀÿÀÀÀÿÿÿÿÿÿÿÿÿÚÚÚÿ………ÿÚÚÚÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿËËËÿ³³³ÿ£££ÿ£££ÿ–––ÿ–––ÿ£££ÿ¥¥¥ÿ···ÿßßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿiiiÿÿÿÿÿÿÿ±±±ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÒÒÒÿÛÛÛÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿhhhÿ ÿ ÿ ÿ ÿ ÿÿ°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ···ÿáááÿÿÿÿÿÿÿÿÿÿÿÿÿÔÔÔÿ...ÿpppÿ±±±ÿ±±±ÿ±±±ÿÄÄÄÿeeeÿ ÿ ÿ ÿ ÿ ÿÿÿ«««ÿ¤¤¤ÿ¤¤¤ÿ¤¤¤ÿ999ÿPPPÿñññÿÿÿÿÿÿÿÿÿÛÛÛÿ<<<ÿ{{{ÿÀÀÀÿÀÀÀÿÀÀÀÿÏÏÏÿeeeÿ ÿ ÿ ÿ ÿ ÿÿ¥¥¥ÿÒÒÒÿÏÏÏÿÏÏÏÿÎÎÎÿVVVÿ|||ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿßßßÿãããÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿhhhÿ ÿ ÿ ÿ ÿ ÿÿ°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÞÞÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿiiiÿÿÿÿÿÿÿ¯¯¯ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿÇÇÇÿºººÿ£££ÿ£££ÿÿ•••ÿ£££ÿ¥¥¥ÿªªªÿÉÉÉÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ«««ÿ›››ÿùùùÿÿÿÿÿÿÿÿÿ¯¯¯ÿÍÍÍÿÿÿÿÿÿÿÿÿéééÿŠŠŠÿÄÄÄÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìììÿÿ¥¥¥ÿÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿ§§§ÿÆÆÆÿÿÿÿÿÿÿÿÿÿÿÿÿëëëÿÿšššÿ®®®ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜÜÜÿÿXXXÿôôôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¨¨ÿÇÇÇÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ···ÿÿlllÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïïïÿ‹‹‹ÿ“““ÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿöööÿžžžÿºººÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÔÔÔÿªªªÿÐÐÐÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿ'''ÿ999ÿÑÑÑÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿ‚‚‚ÿÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ( @ à à ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿæææÿæææÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØØØÿAAAÿAAAÿØØØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿfffÿÿÿfffÿõõõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïïïÿÞÞÞÿÞÞÞÿôôôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿäääÿ‹‹‹ÿ‹‹‹ÿäääÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìììÿÞÞÞÿáááÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‡‡‡ÿÿ555ÿÐÐÐÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¢¢¢ÿ###ÿ,,,ÿÖÖÖÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿqqqÿÿVVVÿñññÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸŸŸÿŸŸŸÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÅÅÅÿ&&&ÿÿÍÍÍÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³³³ÿ»»»ÿÿ€€€ÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸŸŸÿŸŸŸÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÿdddÿ···ÿ„„„ÿÜÜÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿÿ|||ÿðððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿžžžÿžžžÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÈÈÈÿcccÿËËËÿÿÿÿÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿ”””ÿ„„„ÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿ»»»ÿ»»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÖÖÖÿeeeÿÎÎÎÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿÎÎÎÿ¡¡¡ÿŠŠŠÿŠŠŠÿŠŠŠÿ‡‡‡ÿ‡‡‡ÿŠŠŠÿŠŠŠÿŠŠŠÿ¸¸¸ÿÞÞÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿ<<<ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿœœœÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿ>>>ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ›››ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿéééÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿ~~~ÿ¢¢¢ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿ>>>ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ›››ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿSSSÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿÿÿPPPÿ–––ÿ–––ÿ–––ÿ–––ÿ–––ÿÈÈÈÿ@@@ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ”””ÿžžžÿÿÿÿÿyyyÿÿÿÂÂÂÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ’’’ÿÿ\\\ÿ®®®ÿ®®®ÿ®®®ÿ®®®ÿ®®®ÿÓÓÓÿ???ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ˜˜˜ÿÔÔÔÿÇÇÇÿÇÇÇÿÇÇÇÿÇÇÇÿºººÿ###ÿFFFÿßßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿ———ÿ®®®ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿ>>>ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ›››ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿ”””ÿàààÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿ>>>ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ›››ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿ<<<ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ›››ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿÏÏÏÿ¥¥¥ÿŠŠŠÿŠŠŠÿŠŠŠÿÿ„„„ÿŠŠŠÿŠŠŠÿŠŠŠÿ¨¨¨ÿ¹¹¹ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿÿ———ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿžžžÿÈÈÈÿÿÿÿÿÿÿÿÿÿÿÿÿçççÿlllÿ¨¨¨ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿÿÿÿÿòòòÿ~~~ÿŽŽŽÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ†††ÿ¸¸¸ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿæææÿnnnÿ¤¤¤ÿþþþÿùùùÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ’’’ÿ²²²ÿ~~~ÿ’’’ÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‡‡‡ÿ¹¹¹ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿéééÿtttÿÿjjjÿ×××ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿQQQÿÿzzzÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‡‡‡ÿ¹¹¹ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿºººÿÿ
ÿÍÍÍÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿkkkÿÿXXXÿïïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰‰‰ÿ¼¼¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ‘‘‘ÿKKKÿYYYÿßßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëëëÿÞÞÞÿáááÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿÍÍÍÿjjjÿ’’’ÿ×××ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿúúúÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿQQQÿÿ
ÿƒƒƒÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙÙÙÿGGGÿnnnÿðððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿîîîÿöööÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ( 0 ` $ à à ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿ|||ÿ|||ÿôôôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿqqqÿÿÿqqqÿòòòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿpppÿ ÿ ÿ ÿ ÿpppÿøøøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿ™™™ÿ|||ÿ888ÿ888ÿ|||ÿ™™™ÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿéééÿÝÝÝÿÝÝÝÿÝÝÝÿòòòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿtttÿtttÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿæææÿÝÝÝÿÝÝÝÿáááÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿVVVÿÿÿÿ¦¦¦ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿsssÿsssÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿVVVÿÿÿ(((ÿÏÏÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿ:::ÿ ÿ ÿ```ÿìììÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿsssÿsssÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ¿¿¿ÿÿ ÿ ÿÄÄÄÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿ888ÿÿ"""ÿpppÿöööÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿsssÿsssÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³³³ÿ'''ÿÿÿÄÄÄÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿcccÿ’’’ÿÏÏÏÿ>>>ÿpppÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿsssÿsssÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ---ÿ ÿ¨¨¨ÿ+++ÿÊÊÊÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóóóÿýýýÿÿÿÿÿ×××ÿ@@@ÿkkkÿñññÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿsssÿsssÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ§§§ÿ---ÿ¥¥¥ÿþþþÿÿÿÿÿÝÝÝÿöööÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛÛÛÿDDDÿfffÿðððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿrrrÿrrrÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ¢¢¢ÿ---ÿªªªÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÞÞÿHHHÿ```ÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿxxxÿxxxÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿ›››ÿ---ÿ¯¯¯ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááÿ[[[ÿ½½½ÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿÛÛÛÿÛÛÛÿþþþÿþþþÿþþþÿþþþÿþþþÿìììÿ]]]ÿ³³³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿÏÏÏÿ]]]ÿXXXÿXXXÿXXXÿXXXÿXXXÿZZZÿZZZÿXXXÿXXXÿXXXÿXXXÿXXXÿ ÿôôôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ½½½ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿnnnÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿqqqÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿöööÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿqqqÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿâââÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöööÿ|||ÿ{{{ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿqqqÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°ÿ111ÿÁÁÁÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿwwwÿÿVVVÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿqqqÿüüüÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿŸŸŸÿ ÿ%%%ÿ½½½ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ~~~ÿÿ ÿ"""ÿ```ÿaaaÿaaaÿaaaÿaaaÿaaaÿaaaÿaaaÿ ÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿtttÿÄÄÄÿDDDÿAAAÿAAAÿAAAÿAAAÿAAAÿAAAÿAAAÿ+++ÿ ÿ ÿ***ÿáááÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿšššÿÿ ÿ111ÿÿŽŽŽÿŽŽŽÿŽŽŽÿŽŽŽÿŽŽŽÿŽŽŽÿŽŽŽÿ¼¼¼ÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿrrrÿìììÿ½½½ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ{{{ÿ ÿÿ~~~ÿõõõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿœœœÿÿWWWÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿqqqÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿªªªÿ
ÿ„„„ÿøøøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ£££ÿ–––ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿqqqÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙÙÙÿ§§§ÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿqqqÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿqqqÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ½½½ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿoooÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿÒÒÒÿ]]]ÿXXXÿXXXÿXXXÿXXXÿXXXÿ[[[ÿYYYÿXXXÿXXXÿXXXÿXXXÿXXXÿ™™™ÿÀÀÀÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÇÇÇÿVVVÿÝÝÝÿþþþÿþþþÿþþþÿþþþÿþþþÿüüüÿ°°°ÿØØØÿþþþÿþþþÿþþþÿþþþÿþþþÿîîîÿNNNÿkkkÿòòòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÄÄÄÿ333ÿ„„„ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿIIIÿ£££ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙÙÙÿCCCÿgggÿðððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¿¿¿ÿ111ÿŠŠŠÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿIIIÿ£££ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÝÝÿGGGÿbbbÿîîîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿÜÜÜÿüüüÿÿÿÿÿ»»»ÿ000ÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿIIIÿ£££ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàààÿKKKÿ]]]ÿìììÿûûûÿ½½½ÿîîîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßßÿ222ÿ’’’ÿ³³³ÿ///ÿ•••ÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿIIIÿ£££ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿäääÿQQQÿ\\\ÿ|||ÿÿÆÆÆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛÛÛÿÿ
ÿ ÿœœœÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿIIIÿ£££ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÒÒÒÿÿÿ
ÿÅÅÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛÛÛÿÿ ÿÿ©©©ÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿIIIÿ£££ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿWWWÿ ÿ ÿÿÄÄÄÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿãããÿ666ÿÿÿAAAÿèèèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿIIIÿ£££ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿçççÿtttÿgggÿgggÿrrrÿâââÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿäääÿÝÝÝÿÝÝÝÿâââÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿöööÿHHHÿ¡¡¡ÿûûûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿåååÿ___ÿMMMÿÿ222ÿMMMÿ”””ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿiiiÿ ÿ ÿ ÿÿ³³³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóóóÿqqqÿÿ ÿ¸¸¸ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿÿ¾¾¾ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ( ß Ì ( à à ÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþ ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿø ?ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿð ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿà ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÀ ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÀ ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÀ ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿà ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿþ ÿÿÿÿÿø?ÿÿÿÿÿð ÿÿÿÿþÿÿÿÿü ?ÿÿÿÿÿø?ÿÿÿÿÿà ÿÿÿÿþÿÿÿÿü ?ÿÿÿÿÿø?ÿÿÿÿÿà ÿÿÿÿþÿÿÿÿü ?ÿÿÿÿÿø?ÿÿÿÿÿà ÿÿÿÿþÿÿÿÿü ÿÿÿÿÿø?ÿÿÿÿÿð ÿÿÿÿþÿÿÿÿü ÿÿÿÿÿÿø?ÿÿÿÿÿø ÿÿÿÿþÿÿÿÿü ÿÿÿÿÿÿø?ÿÿÿÿÿü ÿÿÿÿþÿÿÿÿü ÿÿÿÿÿÿø?ÿÿÿÿÿþ ÿÿÿÿþÿÿÿÿü ÿÿÿÿÿÿø?ÿÿÿÿÿÿ ÿÿÿÿþÿÿÿÿü ÿÿÿÿÿÿø?ÿÿÿÿÿÿ€ÿÿÿÿþÿÿÿÿü ÿÿÿÿÿÿø?ÿÿÿÿÿÿ ÿÿÿÿþÿÿÿÿü ÿÿÿÿÿÿø?ÿÿÿÿÿþ ÿÿÿÿþÿÿÿÿü ÿÿÿÿÿÿø?ÿÿÿÿÿü ÿÿÿÿþÿÿÿÿüÿÿÿÿÿÿø?ÿÿÿÿÿø ÿÿÿÿþÿÿÿÿü€ÿÿÿÿÿÿø?ÿÿÿÿÿðÿÿÿÿþÿÿÿÿüÀÿÿÿÿÿø?ÿÿÿÿÿà<ÿÿÿÿþÿÿÿÿüà?ÿÿÿÿÿø?ÿÿÿÿÿÀ~ÿÿÿÿþÿÿÿÿüðÿÿÿÿÿø?ÿÿÿÿÿ€ÿÿÿÿÿþÿÿÿÿþ?øÿÿÿÿÿø?ÿÿÿÿÿÿƒÿÿÿÿþÿÿÿÿÿÿüÿÿÿÿÿø?ÿÿÿÿþÿÇÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿø?ÿÿÿÿüÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿøÿÿÿÿÿÿþÿÿÿÿÿÿÿ€ÿÿÿÿÿø?ÿÿÿÿðÿÿÿÿÿÿþÿÿÿÿÿÿÿÀÿÿÿÿø?ÿÿÿÿà?ÿÿÿÿÿÿþÿÿÿÿÿÿÿà?ÿÿÿÿø?ÿÿÿÿÀÿÿÿÿÿÿþÿÿÿÿÿÿÿðÿÿÿÿø?ÿÿÿÿ€ÿÿÿÿÿÿÿþÿÿÿÿÿÿÿøÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿüÿÿÿÿø?ÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿø?ÿÿÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿøÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿ€ÿÿÿÿø?ÿÿÿðÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÀÿÿÿø?ÿÿÿà?ÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿà?ÿÿÿø?ÿÿÿÀÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿðÿÿÿø?ÿÿÿ€ÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿøÿÿÿüÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿüÿÿþÿÿÿãÿÿÿÿÿü ÿÿÿÿÿø?ÿÿþÿÿÿÁÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿÿÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿÿÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿþÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿüÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿøÿÿÿÿÿü ÿÿÿÿÿø ÿÿþÿÿðÿÿÿÿÿü ÿÿÿÿÿø ÿþÿÿàÿÿÿÿÿü ÿÿÿÿÿø ?ÿþÿÿÀÿÿÿÿÿü ÿÿÿÿÿø ÿþÿÿ€ÿÿÿÿÿü ð ÿþÿÿ ü à ÿþÿþ | à ÿþÿþ | à ÿþÿþ | ð ÿþÿÿ ü ÿÿÿÿÿø ÿþÿÿ€ÿÿÿÿÿü ÿÿÿÿÿø ?ÿþÿÿÀÿÿÿÿÿü ÿÿÿÿÿø ÿþÿÿàÿÿÿÿÿü ÿÿÿÿÿø ÿÿþÿÿðÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿøÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿüÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿþÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿÿÿÿÿÿÿü ÿÿÿÿÿøÿÿþÿÿÿÿÿÿÿÿü ÿÿÿÿÿø?ÿÿþÿÿÿÁÿÿÿÿÿü ÿÿÿÿÿüÿÿþÿÿÿãÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿøÿÿÿøÿÿÿÿ€ÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿðÿÿÿðÿÿÿÀÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿà?ÿÿÿðÿÿÿà?ÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÀÿÿÿðÿÿÿðÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿ€ÿÿÿÿðÿÿÿøÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿðÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿüÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿøÿÿÿÿðÿÿÿÿ€ÿÿÿÿÿÿÿþÿÿÿÿÿÿÿðÿÿÿÿðÿÿÿÿÀÿÿÿÿÿÿþÿÿÿÿÿÿÿà?ÿÿÿÿðÿÿÿÿà?ÿÿÿÿÿÿþÿÿÿÿÿÿÿÀÿÿÿÿðÿÿÿÿðÿÿÿÿÿÿþÿÿÿÿÿÿÿ€ÿÿÿÿÿðÿÿÿÿøÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿüÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿðÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿüÿÿÿÿÿðÿÿÿÿÿÿÇÿÿÿÿþÿÿÿÿüøÿÿÿÿÿðÿÿÿÿÿ€ÿƒÿÿÿÿþÿÿÿÿø?ðÿÿÿÿÿðÿÿÿÿÿÀÿÿÿÿþÿÿÿÿøà?ÿÿÿÿÿðÿÿÿÿÿà>ÿÿÿÿþÿÿÿÿøÀÿÿÿÿÿðÿÿÿÿÿðÿÿÿÿþÿÿÿÿø€ÿÿÿÿÿÿðÿÿÿÿÿøÿÿÿÿþÿÿÿÿøÿÿÿÿÿÿðÿÿÿÿÿü ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿþ ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿÿ ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿÿ ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿþ ÿÿÿÿþÿÿÿÿø ?ÿÿÿÿÿÿðÿÿÿÿÿü ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿø ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿð ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿà ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿÀ ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿÀ ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿÀ ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿà ÿÿÿÿþÿÿÿÿø ÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿü ÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÀ ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿ€ ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿ€ ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿ€ ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÀ ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿà ?ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿð ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿø ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþ ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿà?ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ obs-move-transition-2.5.7/media/logo.png 0000664 0000000 0000000 00000005142 14177464325 0020210 0 ustar 00root root 0000000 0000000 ‰PNG
IHDR ß æ ÚîÇ sRGB ®Îé gAMA ±üa pHYs à ÃÇo¨d ÷IDATx^íÕÑ’ë¶DÑüÿOçº2·Œ²l“"-6Ä^oD©Acrþù×L•·Óty;M—·Óty;M—·Óty;M—·Óty;M—·Óty;M—·Óty;M—·Óty;M—·Óty;M—·Óty;M—·Óty;M—·sŽÿm3ø6'`1Uæ«ÅJfôlŒïqËx„'l€/ñ<Öð=ž³³|ƒ'±€ßð´âë;ƒÕkÃëç»ëÆÒõà¤uòÅõaÝúqÞzøÖ:°hgñkæ+kÅŠá]ÖÆ÷Õ„åš7Z_Öw¬Õ<¼×¾ñM}ÇNÍÃ{íßÔwìÔ<¼×¾ñM5afàÖÀ—5{¨Ú0_åle jÃ|•°•ª
óUNÀVª6ÌW9[¨Ú0_åle jÃ\%¿aNª"e jî¾J~À~œ—DÄ@Õ†y;' b *†p8¼ˆ·s"ªJHv
¯X¡ÆvrX)U%$;…W¬P`;9)Œ ª’Â+VPßNŽi#k *†pý8¿‚ôvrFqU=äëÄát·“8P•DÄœ\At;yºBªªHÙŒc+ˆnç* q *Œ m8³‚îv>pFqUmdmÀ¤·ócÚȨj#k¬ ¾œFÐ@UAÛpf¡íüðÀ_K)UU¤lƱT¶“ö(eô$1P•DÄì]ýÏßÁ%®þ6gôžÐÈèé!_ ª‡|½7ÝÚ+\ým&~Bã팞ªb—ÑT3z+\ým&Tßࡌž’ªJH–ÑËè=¡±Â‚o3tÛØ<šÑ“A¬@U±2zGx"P]Aî*_qI=
d
T5)£÷Ïž¥Àv>pU=
T(£WA™¬\mFo5Òª«‘&£WD©¿¤#ô–"J ºQ2zuTûc:Borªë#£WJÁ¿§#ô!D º!2zÕÔü“:Boª+ £WPÙ¿ª#ô.ÇçÕËñùŒ^M•ÿ°ŽÐ»ßT¯Å·3zeÿÛ:BïB|8P½ÎèUVÿÏ뽫ðÕ@õ*|5£WÜ-þŽлŸT/Á'3zõÝåì½ßã{êïñ½ŒÞ-Üèïì½ãcêñ±ŒÞ]ÜëOí½_âKê/ñ¥ŒÞÜî¯íãc^Í©îø—Q½¦ÊèÝÎMÿæÿ}#ö„ÆÝy¶[b%Õ›òvÖÃbÞ}56ÚN~Ò²c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ÞÎ2c'ógæ.õn“Xe1ÆN&ÏÌEªÈTcÈ Ö/ƒÍ|5aŸÐÐ@¦²C™ÕÙ¦½—˜=
d*‹14é ©æ¼”€/hk SYŒ¡L½y&¼‘hGxB™Êb
dzA{’Ñ×ê
Ò@¦²C™ŽðÄCï"Î{<§Le1†2½ÁCÃοˆ ñ¨2•ÅÈôÏ9ù"|ÃÓÈTch ÓG<:àÌ+øxh SYŒ¡LßðôYÝçù¬<â>¡Qch SœÒw˜Aè@µ,ÆxBCqûy;Ë`Œ@µBwòv–Áj„îÔ}Œ¯É#îe1F Z¡;9Æp@™ÊbŒ'4ä·ßÙ¥nÃÓÈTch Sœ2°×
xT™Êb
dú†§Ï[íoxN™Êb
dúˆGo÷G<¤Le1†2½Çscf,ø{<¡Le1†2½ÁCÃ&íø´5©,ÆÐ@¦#<1ü5?BO™Êb
dzA{’©›þ‚†2•ÅȔћgö²gT5©,ÆÐ@¦'4¦úÁ¾þ[±Êb
d
Tg“Û¡ßá"ËbÄúe0ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±ogŒ±“g¶*¼¦ë¶ÛÉ?‡wü‘Á6ø·þžò몷ÀHêMÝù-ÿGãé ;ºÛlüb½ãc?þßÈèÝÎã·ÊèýTƒodôîå>Sñ+eô~ïª?Ãg2z7r“‘ø}2z—à“ê/ñ¥ŒÞ]Üa~™ŒÞUøj úc|,£wå‡á7Éè]ˆª¿Ç÷2zõÕž„_#£w-¾¨^‚OfôŠ+<¿CFïr|>P½
_ÍèUVu~ŒÞ
$T/ć3ze•€»Ïè-Bˆ@õZ|;£WS½ôÜzForª—ã󽂊Eç¾3zK%P]½j*忦3z«‘&P]„½RÊ„æŽ3z¨®CŽŒ^5s»=
d
T—"JF¯ˆq¹×Œžbª«‘&£÷®dÍç½axžËè)!Y *€@½7x(P]aÁ·:P=Â=1„T5)£÷‚ö+,ø6C?¡‘ÑËèé!_ *ƒX½'42z+,ø6CgôÕŒž$"ªJH–Ñû¥´WXðm†~A»á‘2PC¸ìCëÏßK,ø6Cy×ý;¨Œ ªòõàä
ZÛyˆcÚȨJ"b3Ž ¾œ‘GÜ@U)Ûpféíä@$T…´VðvÎAâ@UY¿á餷ó3òˆ¨
#h¬ ¾ÓFÖ@U)Ûpf…ÛùÀIa
T%±ÇV¨±VEÊ@Uùzpr…2ÛùÀyIDTÅ®‡W¨´¼BùU%$ëÇù¼s/PUB²~œ_ÁÛ9ùU%$ëÇùÖ|›¹;qXU1„ëÁÉE¤òBø1Uã{œƒTmŒïq¶2Pµ1¾Ç9ØÊ@ÕÆøç`+Uã{œƒTmŒïq¶2Pµ1¾ÇVìݼѾñM5aæá½ö‘¯© ;5ïµ|MMØ©yx¯}äkjÅZÍÀíßT–kï²¾¬>¬ØY¼ÅÚø¾º±hý8oÍ|eg°n=8i=|k'±tm8c|qç±zßð´õóÝ
aßã9;Å×7Š5<Âv–op–1£g|‰s°’ªñ=NÃbz5çñUš.o§éòvš.o§éòvš.o§éòvš.o§éòvš.o§éòvš.o§éòvš.o§éòvš.o§éòvš.o§éòvš.o§©ú÷ßÿ¤…_ÌJ¨ IEND®B`‚ obs-move-transition-2.5.7/move-source-filter.c 0000664 0000000 0000000 00000207575 14177464325 0021374 0 ustar 00root root 0000000 0000000 #include "move-transition.h"
#include
#include
#include
#include
void move_source_item_remove(void *data, calldata_t *call_data)
{
struct move_source_info *move_source = data;
if (!move_source)
return;
if (!call_data)
return;
obs_sceneitem_t *item = calldata_ptr(call_data, "item");
if (!item || item != move_source->scene_item)
return;
move_source->scene_item = NULL;
obs_scene_t *scene = calldata_ptr(call_data, "scene");
if (!scene)
return;
obs_source_t *parent = obs_scene_get_source(scene);
if (!parent)
return;
signal_handler_t *sh = obs_source_get_signal_handler(parent);
if (!sh)
return;
signal_handler_disconnect(sh, "item_remove", move_source_item_remove,
move_source);
}
bool find_sceneitem(obs_scene_t *scene, obs_sceneitem_t *scene_item, void *data)
{
UNUSED_PARAMETER(scene);
struct move_source_info *move_source = data;
const char *name =
obs_source_get_name(obs_sceneitem_get_source(scene_item));
if (!name || strcmp(name, move_source->source_name) != 0)
return true;
move_source->scene_item = scene_item;
obs_source_t *parent = obs_scene_get_source(scene);
if (!parent)
return false;
signal_handler_t *sh = obs_source_get_signal_handler(parent);
if (sh)
signal_handler_connect(sh, "item_remove",
move_source_item_remove, move_source);
return false;
}
char obs_data_get_char(obs_data_t *data, const char *name)
{
const char *s = obs_data_get_string(data, name);
return (s && strlen(s)) ? s[0] : ' ';
}
void obs_data_set_char(obs_data_t *data, const char *name, char val)
{
char s[2];
s[0] = val;
s[1] = 0;
obs_data_set_string(data, name, s);
}
float calc_sign(char sign, float from, float to)
{
if (sign == '+') {
return from + to;
} else if (sign == '-') {
return from - to;
} else if (sign == '*') {
return from * to;
} else if (sign == '/') {
return to == 0.0f ? from : from / to;
} else {
return to;
}
}
void calc_relative_to(struct move_source_info *move_source)
{
obs_data_t *settings = obs_source_get_settings(move_source->source);
move_source->rot_to = calc_sign(
obs_data_get_char(settings, "rot_sign"), move_source->rot_from,
(float)obs_data_get_double(settings, S_ROT));
obs_data_t *pos = obs_data_get_obj(settings, S_POS);
move_source->pos_to.x = calc_sign(obs_data_get_char(pos, "x_sign"),
move_source->pos_from.x,
(float)obs_data_get_double(pos, "x"));
move_source->pos_to.y = calc_sign(obs_data_get_char(pos, "y_sign"),
move_source->pos_from.y,
(float)obs_data_get_double(pos, "y"));
obs_data_release(pos);
obs_data_t *scale = obs_data_get_obj(settings, S_SCALE);
move_source->scale_to.x = calc_sign(
obs_data_get_char(scale, "x_sign"), move_source->scale_from.x,
(float)obs_data_get_double(scale, "x"));
move_source->scale_to.y = calc_sign(
obs_data_get_char(scale, "y_sign"), move_source->scale_from.y,
(float)obs_data_get_double(scale, "y"));
obs_data_release(scale);
obs_data_t *bounds = obs_data_get_obj(settings, S_BOUNDS);
move_source->bounds_to.x = calc_sign(
obs_data_get_char(bounds, "x_sign"), move_source->bounds_from.x,
(float)obs_data_get_double(bounds, "x"));
move_source->bounds_to.y = calc_sign(
obs_data_get_char(bounds, "y_sign"), move_source->bounds_from.y,
(float)obs_data_get_double(bounds, "y"));
obs_data_release(bounds);
obs_data_t *crop = obs_data_get_obj(settings, S_CROP);
move_source->crop_to.left = calc_sign(
obs_data_get_char(crop, "left_sign"),
move_source->crop_from.left, obs_data_get_int(crop, "left"));
move_source->crop_to.top = calc_sign(
obs_data_get_char(crop, "top_sign"), move_source->crop_from.top,
obs_data_get_int(crop, "top"));
move_source->crop_to.right = calc_sign(
obs_data_get_char(crop, "right_sign"),
move_source->crop_from.right, obs_data_get_int(crop, "right"));
move_source->crop_to.bottom =
calc_sign(obs_data_get_char(crop, "bottom_sign"),
move_source->crop_from.bottom,
obs_data_get_int(crop, "bottom"));
obs_data_release(crop);
obs_data_release(settings);
}
void move_source_media_action(struct move_source_info *move_source,
long long media_action, int64_t media_time)
{
if (media_action == MEDIA_ACTION_PLAY) {
const enum obs_media_state state = obs_source_media_get_state(
obs_sceneitem_get_source(move_source->scene_item));
if (state == OBS_MEDIA_STATE_PAUSED) {
obs_source_media_play_pause(
obs_sceneitem_get_source(
move_source->scene_item),
false);
} else if (state != OBS_MEDIA_STATE_PLAYING) {
obs_source_media_restart(obs_sceneitem_get_source(
move_source->scene_item));
}
} else if (media_action == MEDIA_ACTION_PAUSE) {
obs_source_media_play_pause(
obs_sceneitem_get_source(move_source->scene_item),
true);
} else if (media_action == MEDIA_ACTION_STOP) {
obs_source_media_stop(
obs_sceneitem_get_source(move_source->scene_item));
} else if (media_action == MEDIA_ACTION_RESTART) {
obs_source_media_restart(
obs_sceneitem_get_source(move_source->scene_item));
} else if (media_action == MEDIA_ACTION_NEXT) {
obs_source_media_next(
obs_sceneitem_get_source(move_source->scene_item));
} else if (media_action == MEDIA_ACTION_PREVIOUS) {
obs_source_media_previous(
obs_sceneitem_get_source(move_source->scene_item));
} else if (media_action == MEDIA_ACTION_PLAY_FROM) {
const int64_t duration = obs_source_media_get_duration(
obs_sceneitem_get_source(move_source->scene_item));
if (media_time < 0 && duration + media_time > 0) {
const enum obs_media_state state =
obs_source_media_get_state(
obs_sceneitem_get_source(
move_source->scene_item));
if (state == OBS_MEDIA_STATE_PAUSED) {
obs_source_media_play_pause(
obs_sceneitem_get_source(
move_source->scene_item),
false);
} else if (state != OBS_MEDIA_STATE_PLAYING) {
obs_source_media_restart(
obs_sceneitem_get_source(
move_source->scene_item));
}
obs_source_media_set_time(
obs_sceneitem_get_source(
move_source->scene_item),
duration + media_time);
} else if (media_time >= 0 && media_time <= duration) {
const enum obs_media_state state =
obs_source_media_get_state(
obs_sceneitem_get_source(
move_source->scene_item));
if (state == OBS_MEDIA_STATE_PAUSED) {
obs_source_media_play_pause(
obs_sceneitem_get_source(
move_source->scene_item),
false);
} else if (state != OBS_MEDIA_STATE_PLAYING) {
obs_source_media_restart(
obs_sceneitem_get_source(
move_source->scene_item));
}
obs_source_media_set_time(
obs_sceneitem_get_source(
move_source->scene_item),
media_time);
}
} else if (media_action == MEDIA_ACTION_PAUSE_AT) {
const int64_t duration = obs_source_media_get_duration(
obs_sceneitem_get_source(move_source->scene_item));
if (media_time < 0 && duration + media_time > 0) {
obs_source_media_set_time(
obs_sceneitem_get_source(
move_source->scene_item),
duration + media_time);
obs_source_media_play_pause(
obs_sceneitem_get_source(
move_source->scene_item),
true);
} else if (media_time >= 0 && media_time <= duration) {
obs_source_media_set_time(
obs_sceneitem_get_source(
move_source->scene_item),
media_time);
obs_source_media_play_pause(
obs_sceneitem_get_source(
move_source->scene_item),
true);
}
}
}
void move_source_ended(struct move_source_info *move_source);
void move_source_start(struct move_source_info *move_source)
{
if (!move_source->scene_item && move_source->source_name &&
strlen(move_source->source_name)) {
obs_source_t *parent =
obs_filter_get_parent(move_source->source);
if (parent) {
obs_scene_t *scene = obs_scene_from_source(parent);
if (!scene)
scene = obs_group_from_source(parent);
if (scene)
obs_scene_enum_items(scene, find_sceneitem,
move_source);
}
}
if (!move_source->scene_item)
return;
if (!move_source->custom_duration)
move_source->duration = obs_frontend_get_transition_duration();
if (move_source->moving && obs_source_enabled(move_source->source)) {
if (move_source->next_move_on == NEXT_MOVE_ON_HOTKEY &&
move_source->next_move_name &&
strcmp(move_source->next_move_name, NEXT_MOVE_REVERSE) ==
0) {
move_source->reverse = !move_source->reverse;
move_source->running_duration =
(float)(move_source->duration +
move_source->start_delay +
move_source->end_delay) /
1000.0f -
move_source->running_duration;
}
return;
}
if ((move_source->change_order & CHANGE_ORDER_START) != 0) {
if ((move_source->change_order & CHANGE_ORDER_RELATIVE) != 0 &&
move_source->order_position) {
if (move_source->order_position > 0) {
for (int i = 0; i < move_source->order_position;
i++) {
obs_sceneitem_set_order(
move_source->scene_item,
OBS_ORDER_MOVE_UP);
}
} else if (move_source->order_position < 0) {
for (int i = 0; i > move_source->order_position;
i--) {
obs_sceneitem_set_order(
move_source->scene_item,
OBS_ORDER_MOVE_DOWN);
}
}
} else if ((move_source->change_order &
CHANGE_ORDER_ABSOLUTE) != 0) {
obs_sceneitem_set_order_position(
move_source->scene_item,
move_source->order_position);
}
}
if ((move_source->change_visibility == CHANGE_VISIBILITY_SHOW_START ||
move_source->change_visibility ==
CHANGE_VISIBILITY_SHOW_START_END ||
move_source->change_visibility == CHANGE_VISIBILITY_TOGGLE) &&
!obs_sceneitem_visible(move_source->scene_item)) {
obs_sceneitem_set_visible(move_source->scene_item, true);
move_source->visibility_toggled = true;
} else {
move_source->visibility_toggled = false;
}
if (move_source->change_visibility == CHANGE_VISIBILITY_TOGGLE_START) {
obs_sceneitem_set_visible(
move_source->scene_item,
!obs_sceneitem_visible(move_source->scene_item));
} else if (move_source->change_visibility ==
CHANGE_VISIBILITY_HIDE_START ||
move_source->change_visibility ==
CHANGE_VISIBILITY_HIDE_START_END) {
obs_sceneitem_set_visible(move_source->scene_item, false);
}
move_source_media_action(move_source, move_source->media_action_start,
move_source->media_time_start);
if ((move_source->mute_action == MUTE_ACTION_MUTE_START ||
move_source->mute_action == MUTE_ACTION_MUTE_DURING) &&
!obs_source_muted(
obs_sceneitem_get_source(move_source->scene_item))) {
obs_source_set_muted(
obs_sceneitem_get_source(move_source->scene_item),
true);
} else if ((move_source->mute_action == MUTE_ACTION_UNMUTE_START ||
move_source->mute_action == MUTE_ACTION_UNMUTE_DURING) &&
obs_source_muted(
obs_sceneitem_get_source(move_source->scene_item))) {
obs_source_set_muted(
obs_sceneitem_get_source(move_source->scene_item),
false);
}
move_source->running_duration = 0.0f;
if (!move_source->reverse) {
move_source->rot_from =
obs_sceneitem_get_rot(move_source->scene_item);
obs_sceneitem_get_pos(move_source->scene_item,
&move_source->pos_from);
obs_sceneitem_get_scale(move_source->scene_item,
&move_source->scale_from);
obs_sceneitem_get_bounds(move_source->scene_item,
&move_source->bounds_from);
obs_sceneitem_get_crop(move_source->scene_item,
&move_source->crop_from);
obs_source_t *scene_source = obs_scene_get_source(
obs_sceneitem_get_scene(move_source->scene_item));
move_source->canvas_width = obs_source_get_width(scene_source);
move_source->canvas_height =
obs_source_get_height(scene_source);
calc_relative_to(move_source);
move_source->audio_fade_from = obs_source_get_volume(
obs_sceneitem_get_source(move_source->scene_item));
}
move_source->moving = true;
if (move_source->enabled_match_moving &&
!obs_source_enabled(move_source->source)) {
move_source->enabled = true;
obs_source_set_enabled(move_source->source, true);
}
if (move_source->simultaneous_move_name &&
strlen(move_source->simultaneous_move_name) &&
(!move_source->filter_name ||
strcmp(move_source->filter_name,
move_source->simultaneous_move_name) != 0)) {
obs_source_t *parent =
obs_filter_get_parent(move_source->source);
if (parent) {
obs_source_t *filter = obs_source_get_filter_by_name(
parent, move_source->simultaneous_move_name);
if (!filter) {
filter = obs_source_get_filter_by_name(
obs_sceneitem_get_source(
move_source->scene_item),
move_source->simultaneous_move_name);
}
if (filter) {
if (strcmp(obs_source_get_unversioned_id(filter),
MOVE_SOURCE_FILTER_ID) == 0) {
struct move_source_info *filter_data =
obs_obj_get_data(filter);
move_source_start(filter_data);
} else if (strcmp(obs_source_get_unversioned_id(
filter),
MOVE_VALUE_FILTER_ID) == 0 ||
strcmp(obs_source_get_unversioned_id(
filter),
MOVE_AUDIO_VALUE_FILTER_ID) ==
0) {
struct move_value_info *filter_data =
obs_obj_get_data(filter);
move_value_start(filter_data);
}
obs_source_release(filter);
}
}
}
}
bool move_source_start_button(obs_properties_t *props, obs_property_t *property,
void *data)
{
struct move_source_info *move_source = data;
move_source_start(move_source);
UNUSED_PARAMETER(props);
UNUSED_PARAMETER(property);
return false;
}
void move_source_start_hotkey(void *data, obs_hotkey_id id,
obs_hotkey_t *hotkey, bool pressed)
{
if (!pressed)
return;
struct move_source_info *move_source = data;
if (move_source->next_move_on != NEXT_MOVE_ON_HOTKEY ||
!move_source->next_move_name ||
!strlen(move_source->next_move_name)) {
move_source_start(move_source);
return;
}
if (!move_source->filters_done.num) {
move_source_start(move_source);
da_push_back(move_source->filters_done, &move_source->source);
return;
}
if (move_source->moving && obs_source_enabled(move_source->source) &&
move_source->next_move_name &&
strcmp(move_source->next_move_name, NEXT_MOVE_REVERSE) != 0) {
move_source->moving = false;
if (move_source->enabled_match_moving)
obs_source_set_enabled(move_source->source, false);
}
char *next_move_name = move_source->next_move_name;
obs_source_t *filter = move_source->source;
obs_source_t *parent = obs_filter_get_parent(filter);
obs_source_t *source =
obs_sceneitem_get_source(move_source->scene_item);
long long next_move_on = move_source->next_move_on;
size_t i = 0;
while (i < move_source->filters_done.num) {
if (!next_move_name || !strlen(next_move_name)) {
move_source_start(move_source);
move_source->filters_done.num = 0;
da_push_back(move_source->filters_done,
&move_source->source);
return;
}
if (next_move_on != NEXT_MOVE_ON_HOTKEY) {
da_push_back(move_source->filters_done, &filter);
}
filter = obs_source_get_filter_by_name(parent, next_move_name);
if (!filter && source) {
filter = obs_source_get_filter_by_name(source,
next_move_name);
}
if (filter && strcmp(obs_source_get_unversioned_id(filter),
MOVE_SOURCE_FILTER_ID) == 0) {
struct move_source_info *filter_data =
obs_obj_get_data(filter);
if (filter_data->moving &&
obs_source_enabled(filter_data->source) &&
(filter_data->reverse ||
!filter_data->next_move_name ||
strcmp(filter_data->next_move_name,
NEXT_MOVE_REVERSE) != 0)) {
filter_data->moving = false;
if (filter_data->enabled_match_moving)
obs_source_set_enabled(
filter_data->source, false);
}
parent = obs_filter_get_parent(filter);
source = obs_sceneitem_get_source(
filter_data->scene_item);
next_move_name = filter_data->next_move_name;
next_move_on = filter_data->next_move_on;
} else if (filter &&
(strcmp(obs_source_get_unversioned_id(filter),
MOVE_VALUE_FILTER_ID) == 0 ||
strcmp(obs_source_get_unversioned_id(filter),
MOVE_AUDIO_VALUE_FILTER_ID) == 0)) {
struct move_value_info *filter_data =
obs_obj_get_data(filter);
if (filter_data->moving &&
obs_source_enabled(filter_data->source) &&
(filter_data->reverse ||
!filter_data->next_move_name ||
strcmp(filter_data->next_move_name,
NEXT_MOVE_REVERSE) != 0)) {
filter_data->moving = false;
if (filter_data->enabled_match_moving)
obs_source_set_enabled(
filter_data->source, false);
}
parent = obs_filter_get_parent(filter);
source = NULL;
next_move_name = filter_data->next_move_name;
next_move_on = filter_data->next_move_on;
} else {
obs_source_release(filter);
move_source_start(move_source);
move_source->filters_done.num = 0;
da_push_back(move_source->filters_done,
&move_source->source);
return;
}
obs_source_release(filter);
i++;
}
for (i = 0; i < move_source->filters_done.num; i++) {
if (move_source->filters_done.array[i] == filter) {
move_source_start(move_source);
move_source->filters_done.num = 0;
da_push_back(move_source->filters_done,
&move_source->source);
return;
}
}
if (strcmp(obs_source_get_unversioned_id(filter),
MOVE_SOURCE_FILTER_ID) == 0) {
move_source_start(obs_obj_get_data(filter));
} else if (strcmp(obs_source_get_unversioned_id(filter),
MOVE_VALUE_FILTER_ID) == 0 ||
strcmp(obs_source_get_unversioned_id(filter),
MOVE_AUDIO_VALUE_FILTER_ID) == 0) {
move_value_start(obs_obj_get_data(filter));
}
da_push_back(move_source->filters_done, &filter);
UNUSED_PARAMETER(id);
UNUSED_PARAMETER(hotkey);
}
void move_source_stop(struct move_source_info *move_source)
{
move_source->moving = false;
if (move_source->enabled_match_moving &&
obs_source_enabled(move_source->source)) {
obs_source_set_enabled(move_source->source, false);
}
}
void move_source_source_activate(void *data, calldata_t *call_data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_SOURCE_ACTIVATE)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_SOURCE_ACTIVATE)
move_source_stop(move_source);
UNUSED_PARAMETER(call_data);
}
void move_source_source_deactivate(void *data, calldata_t *call_data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_SOURCE_DEACTIVATE)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_SOURCE_DEACTIVATE)
move_source_stop(move_source);
UNUSED_PARAMETER(call_data);
}
void move_source_source_show(void *data, calldata_t *call_data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_SOURCE_SHOW)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_SOURCE_SHOW)
move_source_stop(move_source);
UNUSED_PARAMETER(call_data);
}
void move_source_source_hide(void *data, calldata_t *call_data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_SOURCE_HIDE)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_SOURCE_HIDE)
move_source_stop(move_source);
UNUSED_PARAMETER(call_data);
}
void move_source_source_media_started(void *data, calldata_t *call_data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_MEDIA_STARTED)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_MEDIA_STARTED)
move_source_stop(move_source);
UNUSED_PARAMETER(call_data);
}
void move_source_source_media_ended(void *data, calldata_t *call_data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_MEDIA_ENDED)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_MEDIA_ENDED)
move_source_stop(move_source);
UNUSED_PARAMETER(call_data);
}
void move_source_source_remove(void *data, calldata_t *call_data)
{
struct move_source_info *move_source = data;
move_source->scene_item = NULL;
UNUSED_PARAMETER(call_data);
}
void move_source_source_changed(struct move_source_info *move_source,
const char *source_name)
{
obs_source_t *source =
move_source->source_name && strlen(move_source->source_name)
? obs_get_source_by_name(move_source->source_name)
: NULL;
if (source) {
signal_handler_t *sh = obs_source_get_signal_handler(source);
if (sh) {
signal_handler_disconnect(sh, "activate",
move_source_source_activate,
move_source);
signal_handler_disconnect(sh, "deactivate",
move_source_source_deactivate,
move_source);
signal_handler_disconnect(sh, "show",
move_source_source_show,
move_source);
signal_handler_disconnect(sh, "hide",
move_source_source_hide,
move_source);
signal_handler_disconnect(
sh, "media_started",
move_source_source_media_started, move_source);
signal_handler_disconnect(
sh, "media_ended",
move_source_source_media_ended, move_source);
signal_handler_disconnect(sh, "remove",
move_source_source_remove,
move_source);
}
obs_source_release(source);
}
bfree(move_source->source_name);
move_source->source_name = NULL;
source = obs_get_source_by_name(source_name);
if (source) {
signal_handler_t *sh = obs_source_get_signal_handler(source);
if (sh) {
signal_handler_connect(sh, "activate",
move_source_source_activate,
move_source);
signal_handler_connect(sh, "deactivate",
move_source_source_deactivate,
move_source);
signal_handler_connect(sh, "show",
move_source_source_show,
move_source);
signal_handler_connect(sh, "hide",
move_source_source_hide,
move_source);
signal_handler_connect(sh, "media_started",
move_source_source_media_started,
move_source);
signal_handler_connect(sh, "media_ended",
move_source_source_media_ended,
move_source);
signal_handler_connect(sh, "remove",
move_source_source_remove,
move_source);
move_source->source_name = bstrdup(source_name);
}
obs_source_release(source);
}
move_source->scene_item = NULL;
obs_source_t *parent = obs_filter_get_parent(move_source->source);
if (parent) {
signal_handler_t *sh = obs_source_get_signal_handler(parent);
if (sh)
signal_handler_disconnect(sh, "item_remove",
move_source_item_remove,
move_source);
}
obs_scene_t *scene = obs_scene_from_source(parent);
if (!scene)
scene = obs_group_from_source(parent);
if (move_source->source_name && scene)
obs_scene_enum_items(scene, find_sceneitem, move_source);
}
static void obs_data_set_sign(obs_data_t *settings, const char *name,
const char *val)
{
obs_data_t *obj = obs_data_get_obj(settings, name);
if (obj) {
obs_data_set_string(obj, "x_sign", val);
obs_data_set_string(obj, "y_sign", val);
obs_data_release(obj);
}
}
void move_source_update(void *data, obs_data_t *settings)
{
struct move_source_info *move_source = data;
obs_source_t *parent = obs_filter_get_parent(move_source->source);
const char *source_name = obs_data_get_string(settings, S_SOURCE);
if (!move_source->source_name ||
strcmp(move_source->source_name, source_name) != 0) {
move_source_source_changed(move_source, source_name);
}
const char *filter_name = obs_source_get_name(move_source->source);
if (!move_source->filter_name ||
strcmp(move_source->filter_name, filter_name) != 0) {
bfree(move_source->filter_name);
move_source->filter_name = NULL;
if (move_source->move_start_hotkey != OBS_INVALID_HOTKEY_ID) {
obs_hotkey_unregister(move_source->move_start_hotkey);
move_source->move_start_hotkey = OBS_INVALID_HOTKEY_ID;
}
if (parent) {
move_source->filter_name = bstrdup(filter_name);
move_source->move_start_hotkey =
obs_hotkey_register_source(
parent, move_source->filter_name,
move_source->filter_name,
move_source_start_hotkey, data);
}
}
move_source->enabled_match_moving =
obs_data_get_bool(settings, S_ENABLED_MATCH_MOVING);
if (move_source->enabled_match_moving && !move_source->moving &&
obs_source_enabled(move_source->source))
move_source_start(move_source);
move_source->change_visibility =
obs_data_get_int(settings, S_CHANGE_VISIBILITY);
move_source->custom_duration =
obs_data_get_bool(settings, S_CUSTOM_DURATION);
if (move_source->custom_duration)
move_source->duration = obs_data_get_int(settings, S_DURATION);
move_source->start_delay = obs_data_get_int(settings, S_START_DELAY);
move_source->end_delay = obs_data_get_int(settings, S_END_DELAY);
move_source->curve =
(float)obs_data_get_double(settings, S_CURVE_MATCH);
move_source->easing = obs_data_get_int(settings, S_EASING_MATCH);
move_source->easing_function =
obs_data_get_int(settings, S_EASING_FUNCTION_MATCH);
move_source->transform = obs_data_get_bool(settings, S_TRANSFORM);
if (obs_data_has_user_value(settings, "crop_left") ||
obs_data_has_user_value(settings, "crop_top") ||
obs_data_has_user_value(settings, "crop_right") ||
obs_data_has_user_value(settings, "crop_bottom")) {
obs_data_t *obj = obs_data_get_obj(settings, S_CROP);
if (!obj) {
obj = obs_data_create();
obs_data_set_obj(settings, S_CROP, obj);
}
obs_data_set_int(obj, "left",
obs_data_get_int(settings, "crop_left"));
obs_data_set_int(obj, "top",
obs_data_get_int(settings, "crop_top"));
obs_data_set_int(obj, "right",
obs_data_get_int(settings, "crop_right"));
obs_data_set_int(obj, "bottom",
obs_data_get_int(settings, "crop_bottom"));
obs_data_release(obj);
obs_data_unset_user_value(settings, "crop_left");
obs_data_unset_user_value(settings, "crop_top");
obs_data_unset_user_value(settings, "crop_right");
obs_data_unset_user_value(settings, "crop_bottom");
}
if (obs_data_has_user_value(settings, S_TRANSFORM_RELATIVE)) {
if (obs_data_get_bool(settings, S_TRANSFORM_RELATIVE)) {
obs_data_set_sign(settings, S_POS, "+");
obs_data_set_sign(settings, S_SCALE, "+");
obs_data_set_sign(settings, S_BOUNDS, "+");
obs_data_set_string(settings, "rot_sign", "+");
obs_data_t *obj = obs_data_get_obj(settings, S_CROP);
if (obj) {
obs_data_set_string(obj, "left_sign", "+");
obs_data_set_string(obj, "top_sign", "+");
obs_data_set_string(obj, "right_sign", "+");
obs_data_set_string(obj, "bottom_sign", "+");
obs_data_release(obj);
}
}
obs_data_unset_user_value(settings, S_TRANSFORM_RELATIVE);
}
calc_relative_to(move_source);
move_source->start_trigger =
(uint32_t)obs_data_get_int(settings, S_START_TRIGGER);
move_source->stop_trigger =
(uint32_t)obs_data_get_int(settings, S_STOP_TRIGGER);
const char *simultaneous_move_name =
obs_data_get_string(settings, S_SIMULTANEOUS_MOVE);
if (!move_source->simultaneous_move_name ||
strcmp(move_source->simultaneous_move_name,
simultaneous_move_name) != 0) {
bfree(move_source->simultaneous_move_name);
move_source->simultaneous_move_name =
bstrdup(simultaneous_move_name);
}
const char *next_move_name = obs_data_get_string(settings, S_NEXT_MOVE);
if (!move_source->next_move_name ||
strcmp(move_source->next_move_name, next_move_name) != 0) {
bfree(move_source->next_move_name);
move_source->next_move_name = bstrdup(next_move_name);
move_source->reverse = false;
}
move_source->next_move_on = obs_data_get_int(settings, S_NEXT_MOVE_ON);
move_source->change_order = obs_data_get_int(settings, S_CHANGE_ORDER);
move_source->order_position =
obs_data_get_int(settings, S_ORDER_POSITION);
move_source->media_action_start =
obs_data_get_int(settings, S_MEDIA_ACTION_START);
move_source->media_time_start =
obs_data_get_int(settings, S_MEDIA_ACTION_START_TIME);
move_source->media_action_end =
obs_data_get_int(settings, S_MEDIA_ACTION_END);
move_source->media_time_end =
obs_data_get_int(settings, S_MEDIA_ACTION_END_TIME);
move_source->mute_action = obs_data_get_int(settings, S_MUTE_ACTION);
move_source->audio_fade = obs_data_get_bool(settings, S_AUDIO_FADE);
move_source->audio_fade_to =
(float)obs_data_get_double(settings, S_AUDIO_FADE_PERCENT) /
100.0f;
if (move_source->start_trigger == START_TRIGGER_LOAD) {
move_source_start(move_source);
}
}
void update_transform_text(struct move_source_info *move_source,
obs_data_t *settings)
{
obs_data_t *pos = obs_data_get_obj(settings, S_POS);
obs_data_t *scale = obs_data_get_obj(settings, S_SCALE);
obs_data_t *bounds = obs_data_get_obj(settings, S_BOUNDS);
obs_data_t *crop = obs_data_get_obj(settings, S_CROP);
char transform_text[500];
if (move_source->scene_item) {
if (obs_sceneitem_get_bounds_type(move_source->scene_item) ==
OBS_BOUNDS_NONE) {
snprintf(
transform_text, 500,
"pos: x%c%.1f y%c%.1f rot:%c%.1f scale: x%c%.3f y%c%.3f crop: l%c%d t%c%d r%c%d b%c%d",
obs_data_get_char(pos, "x_sign"),
obs_data_get_double(pos, "x"),
obs_data_get_char(pos, "y_sign"),
obs_data_get_double(pos, "y"),
obs_data_get_char(settings, "rot_sign"),
obs_data_get_double(settings, S_ROT),
obs_data_get_char(scale, "x_sign"),
obs_data_get_double(scale, "x"),
obs_data_get_char(scale, "y_sign"),
obs_data_get_double(scale, "y"),
obs_data_get_char(crop, "left_sign"),
(int)obs_data_get_int(crop, "left"),
obs_data_get_char(crop, "top_sign"),
(int)obs_data_get_int(crop, "top"),
obs_data_get_char(crop, "right_sign"),
(int)obs_data_get_int(crop, "right"),
obs_data_get_char(crop, "bottom_sign"),
(int)obs_data_get_int(crop, "bottom"));
} else {
snprintf(
transform_text, 500,
"pos: x%c%.1f y%c%.1f rot:%c%.1f bounds: x%c%.3f y%c%.3f crop: l%c%d t%c%d r%c%d b%c%d",
obs_data_get_char(pos, "x_sign"),
obs_data_get_double(pos, "x"),
obs_data_get_char(pos, "y_sign"),
obs_data_get_double(pos, "y"),
obs_data_get_char(settings, "rot_sign"),
obs_data_get_double(settings, S_ROT),
obs_data_get_char(bounds, "x_sign"),
obs_data_get_double(bounds, "x"),
obs_data_get_char(bounds, "y_sign"),
obs_data_get_double(bounds, "y"),
obs_data_get_char(crop, "left_sign"),
(int)obs_data_get_int(crop, "left"),
obs_data_get_char(crop, "top_sign"),
(int)obs_data_get_int(crop, "top"),
obs_data_get_char(crop, "right_sign"),
(int)obs_data_get_int(crop, "right"),
obs_data_get_char(crop, "bottom_sign"),
(int)obs_data_get_int(crop, "bottom"));
}
} else {
snprintf(
transform_text, 500,
"pos: x%c%.1f y%c%.1f rot:%c%.1f scale: x%c%.3f y%c%.3f bounds: x%c%.3f y%c%.3f crop: l%c%d t%c%d r%c%d b%c%d",
obs_data_get_char(pos, "x_sign"),
obs_data_get_double(pos, "x"),
obs_data_get_char(pos, "y_sign"),
obs_data_get_double(pos, "y"),
obs_data_get_char(settings, "rot_sign"),
obs_data_get_double(settings, S_ROT),
obs_data_get_char(scale, "x_sign"),
obs_data_get_double(scale, "x"),
obs_data_get_char(scale, "y_sign"),
obs_data_get_double(scale, "y"),
obs_data_get_char(bounds, "x_sign"),
obs_data_get_double(bounds, "x"),
obs_data_get_char(bounds, "y_sign"),
obs_data_get_double(bounds, "y"),
obs_data_get_char(crop, "left_sign"),
(int)obs_data_get_int(crop, "left"),
obs_data_get_char(crop, "top_sign"),
(int)obs_data_get_int(crop, "top"),
obs_data_get_char(crop, "right_sign"),
(int)obs_data_get_int(crop, "right"),
obs_data_get_char(crop, "bottom_sign"),
(int)obs_data_get_int(crop, "bottom"));
}
obs_data_set_string(settings, S_TRANSFORM_TEXT, transform_text);
obs_data_release(pos);
obs_data_release(scale);
obs_data_release(bounds);
obs_data_release(crop);
}
void move_source_load(void *data, obs_data_t *settings)
{
struct move_source_info *move_source = data;
move_source_update(move_source, settings);
update_transform_text(move_source, settings);
}
void move_source_source_rename(void *data, calldata_t *call_data)
{
struct move_source_info *move_source = data;
const char *new_name = calldata_string(call_data, "new_name");
const char *prev_name = calldata_string(call_data, "prev_name");
obs_data_t *settings = obs_source_get_settings(move_source->source);
if (!settings || !new_name || !prev_name)
return;
const char *source_name = obs_data_get_string(settings, S_SOURCE);
if (source_name && strlen(source_name) &&
strcmp(source_name, prev_name) == 0) {
obs_data_set_string(settings, S_SOURCE, new_name);
}
obs_data_release(settings);
}
static void *move_source_create(obs_data_t *settings, obs_source_t *source)
{
struct move_source_info *move_source =
bzalloc(sizeof(struct move_source_info));
move_source->source = source;
move_source->move_start_hotkey = OBS_INVALID_HOTKEY_ID;
move_source_update(move_source, settings);
signal_handler_connect(obs_get_signal_handler(), "source_rename",
move_source_source_rename, move_source);
return move_source;
}
static void move_source_destroy(void *data)
{
struct move_source_info *move_source = data;
signal_handler_disconnect(obs_get_signal_handler(), "source_rename",
move_source_source_rename, move_source);
obs_source_t *parent = obs_filter_get_parent(move_source->source);
if (parent) {
signal_handler_t *sh = obs_source_get_signal_handler(parent);
signal_handler_disconnect(sh, "item_remove",
move_source_item_remove, move_source);
}
obs_source_t *source = NULL;
if (move_source->scene_item) {
source = obs_sceneitem_get_source(move_source->scene_item);
}
if (!source && move_source->source_name &&
strlen(move_source->source_name)) {
source = obs_get_source_by_name(move_source->source_name);
obs_source_release(source);
}
if (source) {
signal_handler_t *sh = obs_source_get_signal_handler(source);
if (sh) {
signal_handler_disconnect(sh, "activate",
move_source_source_activate,
data);
signal_handler_disconnect(sh, "deactivate",
move_source_source_deactivate,
data);
signal_handler_disconnect(
sh, "show", move_source_source_show, data);
signal_handler_disconnect(
sh, "hide", move_source_source_hide, data);
signal_handler_disconnect(
sh, "media_started",
move_source_source_media_started, data);
signal_handler_disconnect(
sh, "media_ended",
move_source_source_media_ended, data);
signal_handler_disconnect(
sh, "remove", move_source_source_remove, data);
}
}
move_source->scene_item = NULL;
if (move_source->move_start_hotkey != OBS_INVALID_HOTKEY_ID)
obs_hotkey_unregister(move_source->move_start_hotkey);
bfree(move_source->source_name);
bfree(move_source->filter_name);
bfree(move_source->simultaneous_move_name);
bfree(move_source->next_move_name);
da_free(move_source->filters_done);
bfree(move_source);
}
static void obs_data_set_vec2_sign(obs_data_t *data, const char *name,
const struct vec2 *val, char x_sign,
char y_sign)
{
obs_data_t *obj = obs_data_create();
obs_data_set_double(obj, "x", val->x);
obs_data_set_char(obj, "x_sign", x_sign);
obs_data_set_double(obj, "y", val->y);
obs_data_set_char(obj, "y_sign", y_sign);
obs_data_set_obj(data, name, obj);
obs_data_release(obj);
}
static void obs_data_set_crop_sign(obs_data_t *settings, const char *name,
struct obs_sceneitem_crop *crop,
char crop_left_sign, char crop_top_sign,
char crop_right_sign, char crop_bottom_sign)
{
obs_data_t *obj = obs_data_create();
obs_data_set_double(obj, "left", crop->left);
obs_data_set_char(obj, "left_sign", crop_left_sign);
obs_data_set_double(obj, "top", crop->top);
obs_data_set_char(obj, "top_sign", crop_top_sign);
obs_data_set_double(obj, "right", crop->right);
obs_data_set_char(obj, "right_sign", crop_right_sign);
obs_data_set_double(obj, "bottom", crop->bottom);
obs_data_set_char(obj, "bottom_sign", crop_bottom_sign);
obs_data_set_obj(settings, name, obj);
obs_data_release(obj);
}
bool move_source_get_transform(obs_properties_t *props,
obs_property_t *property, void *data)
{
UNUSED_PARAMETER(props);
UNUSED_PARAMETER(property);
struct move_source_info *move_source = data;
bool settings_changed = false;
if (!move_source->scene_item && move_source->source_name &&
strlen(move_source->source_name)) {
obs_source_t *parent =
obs_filter_get_parent(move_source->source);
if (parent) {
obs_scene_t *scene = obs_scene_from_source(parent);
if (!scene)
scene = obs_group_from_source(parent);
if (scene)
obs_scene_enum_items(scene, find_sceneitem,
data);
}
}
if (!move_source->scene_item)
return settings_changed;
settings_changed = true;
obs_data_t *settings = obs_source_get_settings(move_source->source);
struct vec2 pos;
obs_sceneitem_get_pos(move_source->scene_item, &pos);
struct vec2 scale;
obs_sceneitem_get_scale(move_source->scene_item, &scale);
struct vec2 bounds;
obs_sceneitem_get_bounds(move_source->scene_item, &bounds);
struct obs_sceneitem_crop crop;
obs_sceneitem_get_crop(move_source->scene_item, &crop);
obs_data_set_double(settings, S_ROT,
obs_sceneitem_get_rot(move_source->scene_item));
obs_data_set_char(settings, "rot_sign", ' ');
obs_data_set_vec2_sign(settings, S_POS, &pos, ' ', ' ');
obs_data_set_vec2_sign(settings, S_SCALE, &scale, ' ', ' ');
obs_data_set_vec2_sign(settings, S_BOUNDS, &bounds, ' ', ' ');
obs_data_set_crop_sign(settings, S_CROP, &crop, ' ', ' ', ' ', ' ');
move_source_update(data, settings);
update_transform_text(move_source, settings);
obs_data_release(settings);
return settings_changed;
}
bool move_source_relative(obs_properties_t *props, obs_property_t *property,
void *data)
{
UNUSED_PARAMETER(props);
UNUSED_PARAMETER(property);
struct move_source_info *move_source = data;
bool settings_changed = true;
obs_data_t *settings = obs_source_get_settings(move_source->source);
struct vec2 pos;
pos.x = 0.0f;
pos.y = 0.0f;
struct vec2 scale;
scale.x = 1.0f;
scale.y = 1.0f;
struct vec2 bounds;
bounds.x = 1.0f;
bounds.y = 1.0f;
struct obs_sceneitem_crop crop = {0, 0, 0, 0};
obs_data_set_double(settings, S_ROT, 0.0);
obs_data_set_char(settings, "rot_sign", '+');
obs_data_set_vec2_sign(settings, S_POS, &pos, '+', '+');
obs_data_set_vec2_sign(settings, S_SCALE, &scale, '*', '*');
obs_data_set_vec2_sign(settings, S_BOUNDS, &bounds, '*', '*');
obs_data_set_crop_sign(settings, S_CROP, &crop, '+', '+', '+', '+');
update_transform_text(move_source, settings);
move_source_update(data, settings);
obs_data_release(settings);
return settings_changed;
}
void prop_list_add_move_source_filter(obs_source_t *parent, obs_source_t *child,
void *data)
{
UNUSED_PARAMETER(parent);
if (strcmp(obs_source_get_unversioned_id(child),
MOVE_SOURCE_FILTER_ID) != 0 &&
strcmp(obs_source_get_unversioned_id(child),
MOVE_VALUE_FILTER_ID) != 0 &&
strcmp(obs_source_get_unversioned_id(child),
MOVE_AUDIO_VALUE_FILTER_ID) != 0)
return;
obs_property_t *p = data;
const char *name = obs_source_get_name(child);
obs_property_list_add_string(p, name, name);
}
bool move_source_changed(void *data, obs_properties_t *props,
obs_property_t *property, obs_data_t *settings)
{
struct move_source_info *move_source = data;
bool refresh = false;
const char *source_name = obs_data_get_string(settings, S_SOURCE);
if (move_source->source_name &&
strcmp(move_source->source_name, source_name) == 0)
return refresh;
move_source_source_changed(move_source, source_name);
obs_source_t *parent = obs_filter_get_parent(move_source->source);
obs_property_t *p = obs_properties_get(props, S_SIMULTANEOUS_MOVE);
if (p) {
obs_property_list_clear(p);
obs_property_list_add_string(
p, obs_module_text("SimultaneousMove.None"), "");
obs_source_enum_filters(parent,
prop_list_add_move_source_filter, p);
obs_source_t *source =
obs_sceneitem_get_source(move_source->scene_item);
if (source)
obs_source_enum_filters(
source, prop_list_add_move_source_filter, p);
}
p = obs_properties_get(props, S_NEXT_MOVE);
if (p) {
obs_property_list_clear(p);
obs_property_list_add_string(
p, obs_module_text("NextMove.None"), "");
obs_property_list_add_string(
p, obs_module_text("NextMove.Reverse"),
NEXT_MOVE_REVERSE);
obs_source_enum_filters(parent,
prop_list_add_move_source_filter, p);
obs_source_t *source =
obs_sceneitem_get_source(move_source->scene_item);
if (source)
obs_source_enum_filters(
source, prop_list_add_move_source_filter, p);
}
obs_source_t *source = obs_get_source_by_name(source_name);
if (source) {
uint32_t flags = obs_source_get_output_flags(source);
const bool media = flags & OBS_SOURCE_CONTROLLABLE_MEDIA;
p = obs_properties_get(props, S_MEDIA_ACTION);
obs_property_set_visible(p, media);
p = obs_properties_get(props, S_AUDIO_ACTION);
const bool audio = flags & OBS_SOURCE_AUDIO;
obs_property_set_visible(p, audio);
obs_source_release(source);
} else {
p = obs_properties_get(props, S_MEDIA_ACTION);
obs_property_set_visible(p, false);
p = obs_properties_get(props, S_AUDIO_ACTION);
obs_property_set_visible(p, false);
}
refresh = move_source_get_transform(props, property, data);
return refresh;
}
bool prop_list_add_sceneitem(obs_scene_t *scene, obs_sceneitem_t *item,
void *data);
void prop_list_add_easings(obs_property_t *p);
void prop_list_add_easing_functions(obs_property_t *p);
bool move_source_transform_text_changed(void *data, obs_properties_t *props,
obs_property_t *property,
obs_data_t *settings)
{
UNUSED_PARAMETER(props);
UNUSED_PARAMETER(property);
struct move_source_info *move_source = data;
const char *transform_text =
obs_data_get_string(settings, S_TRANSFORM_TEXT);
struct vec2 pos;
float rot;
struct vec2 scale;
struct vec2 bounds;
struct obs_sceneitem_crop crop;
char pos_x_sign, pos_y_sign, rot_sign, scale_x_sign, scale_y_sign,
bounds_x_sign, bounds_y_sign, crop_left_sign, crop_top_sign,
crop_right_sign, crop_bottom_sign;
if (move_source->scene_item) {
if (obs_sceneitem_get_bounds_type(move_source->scene_item) ==
OBS_BOUNDS_NONE) {
if (sscanf(transform_text,
"pos: x%c%f y%c%f rot:%c%f scale: x%c%f y%c%f crop: l%c%d t%c%d r%c%d b%c%d",
&pos_x_sign, &pos.x, &pos_y_sign, &pos.y,
&rot_sign, &rot, &scale_x_sign, &scale.x,
&scale_y_sign, &scale.y, &crop_left_sign,
&crop.left, &crop_top_sign, &crop.top,
&crop_right_sign, &crop.right,
&crop_bottom_sign, &crop.bottom) != 18) {
update_transform_text(move_source, settings);
return true;
}
obs_data_set_vec2_sign(settings, S_SCALE, &scale,
scale_x_sign, scale_y_sign);
} else {
if (sscanf(transform_text,
"pos: x%c%f y%c%f rot:%c%f bounds: x%c%f y%c%f crop: l%c%d t%c%d r%c%d b%c%d",
&pos_x_sign, &pos.x, &pos_y_sign, &pos.y,
&rot_sign, &rot, &bounds_x_sign, &bounds.x,
&bounds_y_sign, &bounds.y, &crop_left_sign,
&crop.left, &crop_top_sign, &crop.top,
&crop_right_sign, &crop.right,
&crop_bottom_sign, &crop.bottom) != 18) {
update_transform_text(move_source, settings);
return true;
}
obs_data_set_vec2_sign(settings, S_BOUNDS, &bounds,
bounds_x_sign, bounds_y_sign);
}
} else {
if (sscanf(transform_text,
"pos: x%c%f y%c%f rot:%c%f scale: x%c%f y%c%f bounds: x%c%f y%c%f crop: l%c%d t%c%d r%c%d b%c%d",
&pos_x_sign, &pos.x, &pos_y_sign, &pos.y, &rot_sign,
&rot, &scale_x_sign, &scale.x, &scale_y_sign,
&scale.y, &bounds_x_sign, &bounds.x, &bounds_y_sign,
&bounds.y, &crop_left_sign, &crop.left,
&crop_top_sign, &crop.top, &crop_right_sign,
&crop.right, &crop_bottom_sign,
&crop.bottom) != 22) {
update_transform_text(move_source, settings);
return true;
}
obs_data_set_vec2_sign(settings, S_SCALE, &scale, scale_x_sign,
scale_y_sign);
obs_data_set_vec2_sign(settings, S_BOUNDS, &bounds,
bounds_x_sign, bounds_y_sign);
}
obs_data_set_vec2_sign(settings, S_POS, &pos, pos_x_sign, pos_y_sign);
obs_data_set_double(settings, S_ROT, rot);
obs_data_set_char(settings, "rot_sign", rot_sign);
obs_data_set_crop_sign(settings, S_CROP, &crop, crop_left_sign,
crop_top_sign, crop_right_sign,
crop_bottom_sign);
return false;
}
static void prop_list_add_media_actions(obs_property_t *p)
{
obs_property_list_add_int(p, obs_module_text("MediaAction.None"),
MEDIA_ACTION_NONE);
obs_property_list_add_int(p, obs_module_text("MediaAction.Play"),
MEDIA_ACTION_PLAY);
obs_property_list_add_int(p, obs_module_text("MediaAction.Pause"),
MEDIA_ACTION_PAUSE);
obs_property_list_add_int(p, obs_module_text("MediaAction.Stop"),
MEDIA_ACTION_STOP);
obs_property_list_add_int(p, obs_module_text("MediaAction.Restart"),
MEDIA_ACTION_RESTART);
obs_property_list_add_int(p, obs_module_text("MediaAction.Next"),
MEDIA_ACTION_NEXT);
obs_property_list_add_int(p, obs_module_text("MediaAction.Previous"),
MEDIA_ACTION_PREVIOUS);
obs_property_list_add_int(p, obs_module_text("MediaAction.PlayFrom"),
MEDIA_ACTION_PLAY_FROM);
obs_property_list_add_int(p, obs_module_text("MediaAction.PauseAt"),
MEDIA_ACTION_PAUSE_AT);
}
static obs_properties_t *move_source_properties(void *data)
{
obs_properties_t *ppts = obs_properties_create();
struct move_source_info *move_source = data;
obs_source_t *parent = obs_filter_get_parent(move_source->source);
obs_scene_t *scene = obs_scene_from_source(parent);
if (!scene)
scene = obs_group_from_source(parent);
if (!scene) {
obs_properties_add_button(ppts, "warning",
obs_module_text("ScenesOnlyFilter"),
NULL);
return ppts;
}
if (!move_source->scene_item && move_source->source_name &&
strlen(move_source->source_name)) {
obs_scene_enum_items(scene, find_sceneitem, move_source);
}
obs_properties_t *group = obs_properties_create();
obs_property_t *p = obs_properties_add_list(group, S_SOURCE,
obs_module_text("Source"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_scene_enum_items(scene, prop_list_add_sceneitem, p);
obs_property_set_modified_callback2(p, move_source_changed, data);
p = obs_properties_add_int(group, S_START_DELAY,
obs_module_text("StartDelay"), 0, 10000000,
100);
obs_property_int_set_suffix(p, "ms");
obs_properties_t *duration = obs_properties_create();
p = obs_properties_add_int(duration, S_DURATION, "", 10, 10000000, 100);
obs_property_int_set_suffix(p, "ms");
p = obs_properties_add_group(group, S_CUSTOM_DURATION,
obs_module_text("CustomDuration"),
OBS_GROUP_CHECKABLE, duration);
p = obs_properties_add_int(group, S_END_DELAY,
obs_module_text("EndDelay"), 0, 10000000,
100);
obs_property_int_set_suffix(p, "ms");
p = obs_properties_add_list(group, S_EASING_MATCH,
obs_module_text("Easing"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easings(p);
p = obs_properties_add_list(group, S_EASING_FUNCTION_MATCH,
obs_module_text("EasingFunction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easing_functions(p);
p = obs_properties_add_group(ppts, S_GENERAL,
obs_module_text("General"),
OBS_GROUP_NORMAL, group);
group = obs_properties_create();
p = obs_properties_add_text(group, S_TRANSFORM_TEXT,
obs_module_text("Transform"),
OBS_TEXT_DEFAULT);
obs_property_set_modified_callback2(
p, move_source_transform_text_changed, data);
obs_properties_add_button(group, "transform_get",
obs_module_text("GetTransform"),
move_source_get_transform);
obs_properties_add_button(group, "switch_to_relative",
obs_module_text("TransformRelative"),
move_source_relative);
obs_properties_add_float_slider(group, S_CURVE_MATCH,
obs_module_text("Curve"), -2.0, 2.0,
0.01);
p = obs_properties_add_group(ppts, S_TRANSFORM,
obs_module_text("Transform"),
OBS_GROUP_CHECKABLE, group);
group = obs_properties_create();
p = obs_properties_add_list(group, S_CHANGE_VISIBILITY,
obs_module_text("ChangeVisibility"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("ChangeVisibility.No"),
CHANGE_VISIBILITY_NONE);
obs_property_list_add_int(p,
obs_module_text("ChangeVisibility.ShowStart"),
CHANGE_VISIBILITY_SHOW_START);
obs_property_list_add_int(p,
obs_module_text("ChangeVisibility.ShowEnd"),
CHANGE_VISIBILITY_SHOW_END);
obs_property_list_add_int(
p, obs_module_text("ChangeVisibility.ShowStartEnd"),
CHANGE_VISIBILITY_SHOW_START_END);
obs_property_list_add_int(p,
obs_module_text("ChangeVisibility.HideStart"),
CHANGE_VISIBILITY_HIDE_START);
obs_property_list_add_int(p,
obs_module_text("ChangeVisibility.HideEnd"),
CHANGE_VISIBILITY_HIDE_END);
obs_property_list_add_int(
p, obs_module_text("ChangeVisibility.HideStartEnd"),
CHANGE_VISIBILITY_HIDE_START_END);
obs_property_list_add_int(p, obs_module_text("ChangeVisibility.Toggle"),
CHANGE_VISIBILITY_TOGGLE);
obs_property_list_add_int(
p, obs_module_text("ChangeVisibility.ToggleStart"),
CHANGE_VISIBILITY_TOGGLE_START);
obs_property_list_add_int(p,
obs_module_text("ChangeVisibility.ToggleEnd"),
CHANGE_VISIBILITY_TOGGLE_END);
p = obs_properties_add_list(group, S_CHANGE_ORDER,
obs_module_text("ChangeOrder"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("ChangeOrder.No"),
CHANGE_ORDER_NONE);
obs_property_list_add_int(p,
obs_module_text("ChangeOrder.StartAbsolute"),
CHANGE_ORDER_START | CHANGE_ORDER_ABSOLUTE);
obs_property_list_add_int(p, obs_module_text("ChangeOrder.EndAbsolute"),
CHANGE_ORDER_END | CHANGE_ORDER_ABSOLUTE);
obs_property_list_add_int(p,
obs_module_text("ChangeOrder.StartRelative"),
CHANGE_ORDER_START | CHANGE_ORDER_RELATIVE);
obs_property_list_add_int(p, obs_module_text("ChangeOrder.EndRelative"),
CHANGE_ORDER_END | CHANGE_ORDER_RELATIVE);
p = obs_properties_add_int(group, S_ORDER_POSITION,
obs_module_text("OrderPosition"), -1000,
1000, 1);
p = obs_properties_add_group(ppts, S_VISIBILITY_ORDER,
obs_module_text("VisibilityOrder"),
OBS_GROUP_NORMAL, group);
obs_source_t *source =
obs_sceneitem_get_source(move_source->scene_item);
group = obs_properties_create();
const uint32_t flags = source ? obs_source_get_output_flags(source) : 0;
const bool media = flags & OBS_SOURCE_CONTROLLABLE_MEDIA;
p = obs_properties_add_list(group, S_MEDIA_ACTION_START,
obs_module_text("MediaAction.Start"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_media_actions(p);
p = obs_properties_add_int(group, S_MEDIA_ACTION_START_TIME,
obs_module_text("MediaAction.Time"),
-1000000, 1000000, 100);
obs_property_int_set_suffix(p, "ms");
p = obs_properties_add_list(group, S_MEDIA_ACTION_END,
obs_module_text("MediaAction.End"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_media_actions(p);
p = obs_properties_add_int(group, S_MEDIA_ACTION_END_TIME,
obs_module_text("MediaAction.Time"),
-1000000, 1000000, 100);
obs_property_int_set_suffix(p, "ms");
p = obs_properties_add_group(ppts, S_MEDIA_ACTION,
obs_module_text("MediaAction"),
OBS_GROUP_NORMAL, group);
obs_property_set_visible(p, media);
const bool audio = flags & OBS_SOURCE_AUDIO;
group = obs_properties_create();
p = obs_properties_add_list(group, S_MUTE_ACTION,
obs_module_text("MuteAction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("MuteAction.None"),
MUTE_ACTION_NONE);
obs_property_list_add_int(p, obs_module_text("MuteAction.MuteStart"),
MUTE_ACTION_MUTE_START);
obs_property_list_add_int(p, obs_module_text("MuteAction.MuteEnd"),
MUTE_ACTION_MUTE_END);
obs_property_list_add_int(p, obs_module_text("MuteAction.UnmuteStart"),
MUTE_ACTION_UNMUTE_START);
obs_property_list_add_int(p, obs_module_text("MuteAction.UnmuteEnd"),
MUTE_ACTION_UNMUTE_END);
obs_property_list_add_int(p, obs_module_text("MuteAction.MuteDuring"),
MUTE_ACTION_MUTE_DURING);
obs_property_list_add_int(p, obs_module_text("MuteAction.UnmuteDuring"),
MUTE_ACTION_UNMUTE_DURING);
obs_properties_t *fade = obs_properties_create();
p = obs_properties_add_float_slider(fade, S_AUDIO_FADE_PERCENT, "", 0.0,
100.0, 1.0);
obs_property_float_set_suffix(p, "%");
p = obs_properties_add_group(group, S_AUDIO_FADE,
obs_module_text("AudioFade"),
OBS_GROUP_CHECKABLE, fade);
p = obs_properties_add_group(ppts, S_AUDIO_ACTION,
obs_module_text("AudioAction"),
OBS_GROUP_NORMAL, group);
obs_property_set_visible(p, audio);
group = obs_properties_create();
p = obs_properties_add_bool(group, S_ENABLED_MATCH_MOVING,
obs_module_text("EnabledMatchMoving"));
p = obs_properties_add_list(group, S_START_TRIGGER,
obs_module_text("StartTrigger"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("StartTrigger.None"),
START_TRIGGER_NONE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Activate"),
START_TRIGGER_ACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Deactivate"),
START_TRIGGER_DEACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Show"),
START_TRIGGER_SHOW);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Hide"),
START_TRIGGER_HIDE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Enable"),
START_TRIGGER_ENABLE);
obs_property_list_add_int(
p, obs_module_text("StartTrigger.SourceActivate"),
START_TRIGGER_SOURCE_ACTIVATE);
obs_property_list_add_int(
p, obs_module_text("StartTrigger.SourceDeactivate"),
START_TRIGGER_SOURCE_DEACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.SourceShow"),
START_TRIGGER_SOURCE_SHOW);
obs_property_list_add_int(p, obs_module_text("StartTrigger.SourceHide"),
START_TRIGGER_SOURCE_HIDE);
obs_property_list_add_int(p,
obs_module_text("StartTrigger.MediaStarted"),
START_TRIGGER_MEDIA_STARTED);
obs_property_list_add_int(p, obs_module_text("StartTrigger.MediaEnded"),
START_TRIGGER_MEDIA_ENDED);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Load"),
START_TRIGGER_LOAD);
p = obs_properties_add_list(group, S_STOP_TRIGGER,
obs_module_text("StopTrigger"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("StopTrigger.None"),
START_TRIGGER_NONE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Activate"),
START_TRIGGER_ACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Deactivate"),
START_TRIGGER_DEACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Show"),
START_TRIGGER_SHOW);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Hide"),
START_TRIGGER_HIDE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Enable"),
START_TRIGGER_ENABLE);
obs_property_list_add_int(
p, obs_module_text("StartTrigger.SourceActivate"),
START_TRIGGER_SOURCE_ACTIVATE);
obs_property_list_add_int(
p, obs_module_text("StartTrigger.SourceDeactivate"),
START_TRIGGER_SOURCE_DEACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.SourceShow"),
START_TRIGGER_SOURCE_SHOW);
obs_property_list_add_int(p, obs_module_text("StartTrigger.SourceHide"),
START_TRIGGER_SOURCE_HIDE);
obs_property_list_add_int(p,
obs_module_text("StartTrigger.MediaStarted"),
START_TRIGGER_MEDIA_STARTED);
obs_property_list_add_int(p, obs_module_text("StartTrigger.MediaEnded"),
START_TRIGGER_MEDIA_ENDED);
p = obs_properties_add_list(group, S_SIMULTANEOUS_MOVE,
obs_module_text("SimultaneousMove"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(
p, obs_module_text("SimultaneousMove.None"), "");
obs_source_enum_filters(parent, prop_list_add_move_source_filter, p);
if (source)
obs_source_enum_filters(source,
prop_list_add_move_source_filter, p);
p = obs_properties_add_list(group, S_NEXT_MOVE,
obs_module_text("NextMove"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, obs_module_text("NextMove.None"), "");
obs_property_list_add_string(p, obs_module_text("NextMove.Reverse"),
NEXT_MOVE_REVERSE);
obs_source_enum_filters(parent, prop_list_add_move_source_filter, p);
if (source)
obs_source_enum_filters(source,
prop_list_add_move_source_filter, p);
p = obs_properties_add_list(group, S_NEXT_MOVE_ON,
obs_module_text("NextMoveOn"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NextMoveOn.End"),
NEXT_MOVE_ON_END);
obs_property_list_add_int(p, obs_module_text("NextMoveOn.Hotkey"),
NEXT_MOVE_ON_HOTKEY);
obs_properties_add_button(group, "move_source_start",
obs_module_text("Start"),
move_source_start_button);
p = obs_properties_add_group(ppts, S_ACTIONS,
obs_module_text("Actions"),
OBS_GROUP_NORMAL, group);
return ppts;
}
void move_source_defaults(obs_data_t *settings)
{
obs_data_set_default_bool(settings, S_CUSTOM_DURATION, true);
obs_data_set_default_bool(settings, S_TRANSFORM, true);
obs_data_set_default_int(settings, S_DURATION, 300);
obs_data_set_default_int(settings, S_EASING_MATCH, EASE_IN_OUT);
obs_data_set_default_int(settings, S_EASING_FUNCTION_MATCH,
EASING_CUBIC);
obs_data_set_default_double(settings, S_CURVE_MATCH, 0.0);
obs_data_set_default_bool(settings, S_ENABLED_MATCH_MOVING, true);
}
void move_source_video_render(void *data, gs_effect_t *effect)
{
UNUSED_PARAMETER(effect);
struct move_source_info *filter = data;
obs_source_skip_video_filter(filter->source);
}
static const char *move_source_get_name(void *type_data)
{
UNUSED_PARAMETER(type_data);
return obs_module_text("MoveSourceFilter");
}
float get_eased(float f, long long easing, long long easing_function);
void vec2_bezier(struct vec2 *dst, struct vec2 *begin, struct vec2 *control,
struct vec2 *end, const float t);
void move_source_ended(struct move_source_info *move_source)
{
if (move_source->enabled_match_moving &&
(move_source->reverse ||
move_source->next_move_on == NEXT_MOVE_ON_HOTKEY ||
!move_source->next_move_name ||
strcmp(move_source->next_move_name, NEXT_MOVE_REVERSE) != 0) &&
obs_source_enabled(move_source->source)) {
obs_source_set_enabled(move_source->source, false);
}
if (move_source->change_visibility == CHANGE_VISIBILITY_HIDE_END ||
move_source->change_visibility ==
CHANGE_VISIBILITY_SHOW_START_END) {
obs_sceneitem_set_visible(move_source->scene_item, false);
} else if (move_source->change_visibility ==
CHANGE_VISIBILITY_SHOW_END ||
move_source->change_visibility ==
CHANGE_VISIBILITY_HIDE_START_END) {
obs_sceneitem_set_visible(move_source->scene_item, true);
} else if (move_source->change_visibility ==
CHANGE_VISIBILITY_TOGGLE_END) {
obs_sceneitem_set_visible(
move_source->scene_item,
!obs_sceneitem_visible(move_source->scene_item));
} else if (move_source->change_visibility == CHANGE_VISIBILITY_TOGGLE &&
!move_source->visibility_toggled) {
obs_sceneitem_set_visible(move_source->scene_item, false);
}
move_source_media_action(move_source, move_source->media_action_end,
move_source->media_time_end);
if ((move_source->mute_action == MUTE_ACTION_MUTE_END ||
move_source->mute_action == MUTE_ACTION_UNMUTE_DURING) &&
!obs_source_muted(
obs_sceneitem_get_source(move_source->scene_item))) {
obs_source_set_muted(
obs_sceneitem_get_source(move_source->scene_item),
true);
} else if ((move_source->mute_action == MUTE_ACTION_UNMUTE_END ||
move_source->mute_action == MUTE_ACTION_MUTE_DURING) &&
obs_source_muted(
obs_sceneitem_get_source(move_source->scene_item))) {
obs_source_set_muted(
obs_sceneitem_get_source(move_source->scene_item),
false);
}
if ((move_source->change_order & CHANGE_ORDER_END) != 0) {
if ((move_source->change_order & CHANGE_ORDER_RELATIVE) != 0 &&
move_source->order_position) {
if (move_source->order_position > 0) {
for (int i = 0; i < move_source->order_position;
i++) {
obs_sceneitem_set_order(
move_source->scene_item,
OBS_ORDER_MOVE_UP);
}
} else if (move_source->order_position < 0) {
for (int i = 0; i > move_source->order_position;
i--) {
obs_sceneitem_set_order(
move_source->scene_item,
OBS_ORDER_MOVE_DOWN);
}
}
} else if ((move_source->change_order &
CHANGE_ORDER_ABSOLUTE) != 0) {
obs_sceneitem_set_order_position(
move_source->scene_item,
move_source->order_position);
}
}
if (move_source->next_move_on == NEXT_MOVE_ON_END &&
move_source->next_move_name &&
strlen(move_source->next_move_name) &&
(!move_source->filter_name ||
strcmp(move_source->filter_name, move_source->next_move_name) !=
0)) {
if (strcmp(move_source->next_move_name, NEXT_MOVE_REVERSE) ==
0) {
move_source->reverse = !move_source->reverse;
if (move_source->reverse)
move_source_start(move_source);
} else {
obs_source_t *parent =
obs_filter_get_parent(move_source->source);
if (parent) {
obs_source_t *filter =
obs_source_get_filter_by_name(
parent,
move_source->next_move_name);
if (!filter) {
filter = obs_source_get_filter_by_name(
obs_sceneitem_get_source(
move_source->scene_item),
move_source->next_move_name);
}
if (filter) {
if (strcmp(obs_source_get_unversioned_id(
filter),
MOVE_SOURCE_FILTER_ID) ==
0) {
struct move_source_info
*filter_data =
obs_obj_get_data(
filter);
move_source_start(filter_data);
} else if (
strcmp(obs_source_get_unversioned_id(
filter),
MOVE_VALUE_FILTER_ID) ==
0 ||
strcmp(obs_source_get_unversioned_id(
filter),
MOVE_AUDIO_VALUE_FILTER_ID) ==
0) {
struct move_value_info
*filter_data =
obs_obj_get_data(
filter);
move_value_start(filter_data);
}
obs_source_release(filter);
}
}
}
} else if (move_source->next_move_on == NEXT_MOVE_ON_HOTKEY &&
move_source->next_move_name &&
strcmp(move_source->next_move_name, NEXT_MOVE_REVERSE) ==
0) {
move_source->reverse = !move_source->reverse;
}
}
void move_source_tick(void *data, float seconds)
{
struct move_source_info *move_source = data;
const bool enabled = obs_source_enabled(move_source->source);
if (move_source->enabled != enabled) {
if (enabled &&
(move_source->start_trigger == START_TRIGGER_ENABLE ||
(move_source->enabled_match_moving &&
!move_source->moving)))
move_source_start(move_source);
if (enabled &&
move_source->stop_trigger == START_TRIGGER_ENABLE)
move_source_stop(move_source);
move_source->enabled = enabled;
}
if (move_source->enabled_match_moving &&
enabled != move_source->moving) {
if (enabled) {
move_source_start(move_source);
} else {
move_source_stop(move_source);
}
}
if (!move_source->moving || !enabled)
return;
if (!move_source->scene_item || !move_source->duration) {
move_source->moving = false;
return;
}
move_source->running_duration += seconds;
if (move_source->running_duration * 1000.0f <
(move_source->reverse ? move_source->end_delay
: move_source->start_delay)) {
if (!move_source->reverse) {
calc_relative_to(move_source);
}
return;
}
if (move_source->running_duration * 1000.0f >=
(float)(move_source->start_delay + move_source->duration +
move_source->end_delay)) {
move_source->moving = false;
}
float t = (move_source->running_duration * 1000.0f -
(float)(move_source->reverse ? move_source->end_delay
: move_source->start_delay)) /
(float)move_source->duration;
if (t >= 1.0f) {
t = 1.0f;
}
if (move_source->reverse) {
t = 1.0f - t;
}
t = get_eased(t, move_source->easing, move_source->easing_function);
float ot = t;
if (t > 1.0f)
ot = 1.0f;
else if (t < 0.0f)
ot = 0.0f;
if (move_source->audio_fade) {
obs_source_set_volume(
obs_sceneitem_get_source(move_source->scene_item),
(1.0f - ot) * move_source->audio_fade_from +
ot * move_source->audio_fade_to);
}
if (move_source->transform) {
struct vec2 pos;
if (move_source->curve != 0.0f) {
const float diff_x = fabsf(move_source->pos_from.x -
move_source->pos_to.x);
const float diff_y = fabsf(move_source->pos_from.y -
move_source->pos_to.y);
struct vec2 control_pos;
vec2_set(&control_pos,
0.5f * move_source->pos_from.x +
0.5f * move_source->pos_to.x,
0.5f * move_source->pos_from.y +
0.5f * move_source->pos_to.y);
if (control_pos.x >= (move_source->canvas_width >> 1)) {
control_pos.x += diff_y * move_source->curve;
} else {
control_pos.x -= diff_y * move_source->curve;
}
if (control_pos.y >=
(move_source->canvas_height >> 1)) {
control_pos.y += diff_x * move_source->curve;
} else {
control_pos.y -= diff_x * move_source->curve;
}
vec2_bezier(&pos, &move_source->pos_from, &control_pos,
&move_source->pos_to, t);
} else {
vec2_set(&pos,
(1.0f - t) * move_source->pos_from.x +
t * move_source->pos_to.x,
(1.0f - t) * move_source->pos_from.y +
t * move_source->pos_to.y);
}
obs_sceneitem_defer_update_begin(move_source->scene_item);
obs_sceneitem_set_pos(move_source->scene_item, &pos);
const float rot = (1.0f - t) * move_source->rot_from +
t * move_source->rot_to;
obs_sceneitem_set_rot(move_source->scene_item, rot);
struct vec2 scale;
vec2_set(&scale,
(1.0f - t) * move_source->scale_from.x +
t * move_source->scale_to.x,
(1.0f - t) * move_source->scale_from.y +
t * move_source->scale_to.y);
obs_sceneitem_set_scale(move_source->scene_item, &scale);
struct vec2 bounds;
vec2_set(&bounds,
(1.0f - t) * move_source->bounds_from.x +
t * move_source->bounds_to.x,
(1.0f - t) * move_source->bounds_from.y +
t * move_source->bounds_to.y);
obs_sceneitem_set_bounds(move_source->scene_item, &bounds);
struct obs_sceneitem_crop crop;
crop.left = (int)((float)(1.0f - ot) *
(float)move_source->crop_from.left +
ot * (float)move_source->crop_to.left);
crop.top = (int)((float)(1.0f - ot) *
(float)move_source->crop_from.top +
ot * (float)move_source->crop_to.top);
crop.right = (int)((float)(1.0f - ot) *
(float)move_source->crop_from.right +
ot * (float)move_source->crop_to.right);
crop.bottom =
(int)((float)(1.0f - ot) *
(float)move_source->crop_from.bottom +
ot * (float)move_source->crop_to.bottom);
obs_sceneitem_set_crop(move_source->scene_item, &crop);
obs_sceneitem_defer_update_end(move_source->scene_item);
}
if (!move_source->moving) {
move_source_ended(move_source);
}
}
void move_source_activate(void *data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_ACTIVATE)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_ACTIVATE)
move_source_stop(move_source);
}
void move_source_deactivate(void *data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_DEACTIVATE)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_DEACTIVATE)
move_source_stop(move_source);
}
void move_source_show(void *data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_SHOW)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_SHOW)
move_source_stop(move_source);
}
void move_source_hide(void *data)
{
struct move_source_info *move_source = data;
if (move_source->start_trigger == START_TRIGGER_HIDE)
move_source_start(move_source);
if (move_source->stop_trigger == START_TRIGGER_HIDE)
move_source_stop(move_source);
}
struct obs_source_info move_source_filter = {
.id = MOVE_SOURCE_FILTER_ID,
.type = OBS_SOURCE_TYPE_FILTER,
.output_flags = OBS_SOURCE_VIDEO,
.get_name = move_source_get_name,
.create = move_source_create,
.destroy = move_source_destroy,
.get_properties = move_source_properties,
.get_defaults = move_source_defaults,
.video_render = move_source_video_render,
.video_tick = move_source_tick,
.update = move_source_update,
.load = move_source_load,
.activate = move_source_activate,
.deactivate = move_source_deactivate,
.show = move_source_show,
.hide = move_source_hide,
};
obs-move-transition-2.5.7/move-transition-override-filter.c 0000664 0000000 0000000 00000031536 14177464325 0024073 0 ustar 00root root 0000000 0000000 #include "move-transition.h"
#include
struct move_filter_info {
obs_source_t *source;
};
void move_filter_source_rename(void *data, calldata_t *call_data)
{
struct move_filter_info *move_filter = data;
const char *new_name = calldata_string(call_data, "new_name");
const char *prev_name = calldata_string(call_data, "prev_name");
obs_data_t *settings = obs_source_get_settings(move_filter->source);
if (!settings || !new_name || !prev_name)
return;
const char *source_name = obs_data_get_string(settings, S_SOURCE);
if (source_name && strlen(source_name) &&
strcmp(source_name, prev_name) == 0) {
obs_data_set_string(settings, S_SOURCE, new_name);
}
obs_data_release(settings);
}
static void *move_filter_create(obs_data_t *settings, obs_source_t *source)
{
struct move_filter_info *move_filter =
bzalloc(sizeof(struct move_filter_info));
move_filter->source = source;
signal_handler_connect(obs_get_signal_handler(), "source_rename",
move_filter_source_rename, move_filter);
UNUSED_PARAMETER(settings);
return move_filter;
}
static void move_filter_destroy(void *data)
{
struct move_filter_info *move_filter = data;
signal_handler_disconnect(obs_get_signal_handler(), "source_rename",
move_filter_source_rename, move_filter);
bfree(move_filter);
}
void prop_list_add_easings(obs_property_t *p);
void prop_list_add_easing_functions(obs_property_t *p);
void prop_list_add_positions(obs_property_t *p);
void prop_list_add_transitions(obs_property_t *p);
void prop_list_add_scales(obs_property_t *p);
bool prop_list_add_sceneitem(obs_scene_t *scene, obs_sceneitem_t *item,
void *data)
{
UNUSED_PARAMETER(scene);
obs_property_t *p = data;
const char *name = obs_source_get_name(obs_sceneitem_get_source(item));
obs_property_list_add_string(p, name, name);
return true;
}
bool prop_list_add_source(void *data, obs_source_t *source)
{
obs_property_t *p = data;
const char *name = obs_source_get_name(source);
if (name && strlen(name))
obs_property_list_add_string(p, name, name);
return true;
}
static obs_properties_t *move_filter_properties(void *data)
{
struct move_filter_info *move_filter = data;
obs_properties_t *ppts = obs_properties_create();
obs_property_t *p;
obs_source_t *parent = obs_filter_get_parent(move_filter->source);
obs_scene_t *scene = obs_scene_from_source(parent);
obs_source_t *source = NULL;
if (scene) {
p = obs_properties_add_list(ppts, S_SOURCE,
obs_module_text("Source"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_scene_enum_items(scene, prop_list_add_sceneitem, p);
obs_data_t *settings =
obs_source_get_settings(move_filter->source);
if (settings) {
source = obs_sceneitem_get_source(obs_scene_find_source(
scene,
obs_data_get_string(settings, S_SOURCE)));
obs_data_release(settings);
}
}
//Matched items
obs_properties_t *group = obs_properties_create();
p = obs_properties_add_list(group, S_MATCH_SOURCE,
obs_module_text("MatchSource"),
OBS_COMBO_TYPE_EDITABLE,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, "", "");
obs_enum_sources(prop_list_add_source, p);
obs_enum_scenes(prop_list_add_source, p);
p = obs_properties_add_int_slider(group, S_START_DELAY_MATCH_TO,
obs_module_text("StartDelayTo"), -1,
100, 1);
obs_property_int_set_suffix(p, "%");
p = obs_properties_add_int_slider(group, S_END_DELAY_MATCH_TO,
obs_module_text("EndDelayTo"), -1,
100, 1);
obs_property_int_set_suffix(p, "%");
p = obs_properties_add_int_slider(group, S_START_DELAY_MATCH_FROM,
obs_module_text("StartDelayFrom"), -1,
100, 1);
obs_property_int_set_suffix(p, "%");
p = obs_properties_add_int_slider(group, S_END_DELAY_MATCH_FROM,
obs_module_text("EndDelayFrom"), -1,
100, 1);
obs_property_int_set_suffix(p, "%");
p = obs_properties_add_list(group, S_EASING_MATCH,
obs_module_text("Easing"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
prop_list_add_easings(p);
p = obs_properties_add_list(group, S_EASING_FUNCTION_MATCH,
obs_module_text("EasingFunction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
prop_list_add_easing_functions(p);
p = obs_properties_add_list(group, S_TRANSITION_MATCH,
obs_module_text("Transition"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, obs_module_text("NoOverride"), NULL);
prop_list_add_transitions(p);
p = obs_properties_add_list(group, S_TRANSITION_SCALE,
obs_module_text("TransitionScaleType"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
prop_list_add_scales(p);
obs_properties_t *curve_group = obs_properties_create();
obs_properties_add_float_slider(curve_group, S_CURVE_MATCH,
obs_module_text("Curve"), -2.0, 2.0,
0.01);
obs_properties_add_group(group, S_CURVE_OVERRIDE_MATCH,
obs_module_text("CurveOverride"),
OBS_GROUP_CHECKABLE, curve_group);
p = obs_properties_add_list(group, S_START_MOVE_MATCH_FROM,
obs_module_text("StartMoveMatchFrom"),
OBS_COMBO_TYPE_EDITABLE,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, "", "");
obs_source_enum_filters(parent, prop_list_add_move_source_filter, p);
if (source)
obs_source_enum_filters(source,
prop_list_add_move_source_filter, p);
p = obs_properties_add_list(group, S_START_MOVE_MATCH_TO,
obs_module_text("StartMoveMatchTo"),
OBS_COMBO_TYPE_EDITABLE,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, "", "");
obs_source_enum_filters(parent, prop_list_add_move_source_filter, p);
if (source)
obs_source_enum_filters(source,
prop_list_add_move_source_filter, p);
obs_properties_add_group(ppts, S_MOVE_MATCH,
obs_module_text("MoveMatch"), OBS_GROUP_NORMAL,
group);
//Move in
group = obs_properties_create();
p = obs_properties_add_int_slider(group, S_START_DELAY_IN,
obs_module_text("StartDelay"), -1,
100, 1);
obs_property_int_set_suffix(p, "%");
p = obs_properties_add_int_slider(
group, S_END_DELAY_IN, obs_module_text("EndDelay"), -1, 100, 1);
obs_property_int_set_suffix(p, "%");
p = obs_properties_add_list(group, S_EASING_IN,
obs_module_text("Easing"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
prop_list_add_easings(p);
p = obs_properties_add_list(group, S_EASING_FUNCTION_IN,
obs_module_text("EasingFunction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
prop_list_add_easing_functions(p);
p = obs_properties_add_list(group, S_ZOOM_IN, obs_module_text("Zoom"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
obs_property_list_add_int(p, obs_module_text("No"), ZOOM_NO);
obs_property_list_add_int(p, obs_module_text("Yes"), ZOOM_YES);
p = obs_properties_add_list(group, S_POSITION_IN,
obs_module_text("Position"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
prop_list_add_positions(p);
p = obs_properties_add_list(group, S_TRANSITION_IN,
obs_module_text("Transition"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, obs_module_text("NoOverride"), NULL);
prop_list_add_transitions(p);
curve_group = obs_properties_create();
obs_properties_add_float_slider(curve_group, S_CURVE_IN,
obs_module_text("Curve"), -2.0, 2.0,
0.01);
obs_properties_add_group(group, S_CURVE_OVERRIDE_IN,
obs_module_text("CurveOverride"),
OBS_GROUP_CHECKABLE, curve_group);
p = obs_properties_add_list(group, S_START_MOVE_IN,
obs_module_text("StartMove"),
OBS_COMBO_TYPE_EDITABLE,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, "", "");
obs_source_enum_filters(parent, prop_list_add_move_source_filter, p);
if (source)
obs_source_enum_filters(source,
prop_list_add_move_source_filter, p);
obs_properties_add_group(ppts, S_MOVE_IN, obs_module_text("MoveIn"),
OBS_GROUP_NORMAL, group);
//Move out
group = obs_properties_create();
p = obs_properties_add_int_slider(group, S_START_DELAY_OUT,
obs_module_text("StartDelay"), -1,
100, 1);
obs_property_int_set_suffix(p, "%");
p = obs_properties_add_int_slider(group, S_END_DELAY_OUT,
obs_module_text("EndDelay"), -1, 100,
1);
obs_property_int_set_suffix(p, "%");
p = obs_properties_add_list(group, S_EASING_OUT,
obs_module_text("Easing"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
prop_list_add_easings(p);
p = obs_properties_add_list(group, S_EASING_FUNCTION_OUT,
obs_module_text("EasingFunction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
prop_list_add_easing_functions(p);
p = obs_properties_add_list(group, S_ZOOM_OUT, obs_module_text("Zoom"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
obs_property_list_add_int(p, obs_module_text("No"), ZOOM_NO);
obs_property_list_add_int(p, obs_module_text("Yes"), ZOOM_YES);
p = obs_properties_add_list(group, S_POSITION_OUT,
obs_module_text("Position"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NoOverride"),
NO_OVERRIDE);
prop_list_add_positions(p);
p = obs_properties_add_list(group, S_TRANSITION_OUT,
obs_module_text("Transition"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, obs_module_text("NoOverride"), NULL);
prop_list_add_transitions(p);
curve_group = obs_properties_create();
obs_properties_add_float_slider(curve_group, S_CURVE_OUT,
obs_module_text("Curve"), -2.0, 2.0,
0.01);
obs_properties_add_group(group, S_CURVE_OVERRIDE_OUT,
obs_module_text("CurveOverride"),
OBS_GROUP_CHECKABLE, curve_group);
p = obs_properties_add_list(group, S_START_MOVE_OUT,
obs_module_text("StartMove"),
OBS_COMBO_TYPE_EDITABLE,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, "", "");
obs_source_enum_filters(parent, prop_list_add_move_source_filter, p);
if (source)
obs_source_enum_filters(source,
prop_list_add_move_source_filter, p);
obs_properties_add_group(ppts, S_MOVE_OUT, obs_module_text("MoveOut"),
OBS_GROUP_NORMAL, group);
return ppts;
}
void move_filter_defaults(obs_data_t *settings)
{
obs_data_set_default_int(settings, S_START_DELAY_MATCH_TO, NO_OVERRIDE);
obs_data_set_default_int(settings, S_START_DELAY_MATCH_FROM,
NO_OVERRIDE);
obs_data_set_default_int(settings, S_START_DELAY_IN, NO_OVERRIDE);
obs_data_set_default_int(settings, S_START_DELAY_OUT, NO_OVERRIDE);
obs_data_set_default_int(settings, S_END_DELAY_MATCH_TO, NO_OVERRIDE);
obs_data_set_default_int(settings, S_END_DELAY_MATCH_FROM, NO_OVERRIDE);
obs_data_set_default_int(settings, S_END_DELAY_IN, NO_OVERRIDE);
obs_data_set_default_int(settings, S_END_DELAY_OUT, NO_OVERRIDE);
obs_data_set_default_int(settings, S_EASING_MATCH, NO_OVERRIDE);
obs_data_set_default_int(settings, S_EASING_IN, NO_OVERRIDE);
obs_data_set_default_int(settings, S_EASING_OUT, NO_OVERRIDE);
obs_data_set_default_int(settings, S_EASING_FUNCTION_MATCH,
NO_OVERRIDE);
obs_data_set_default_int(settings, S_EASING_FUNCTION_IN, NO_OVERRIDE);
obs_data_set_default_int(settings, S_EASING_FUNCTION_OUT, NO_OVERRIDE);
obs_data_set_default_int(settings, S_POSITION_IN, NO_OVERRIDE);
obs_data_set_default_int(settings, S_ZOOM_IN, NO_OVERRIDE);
obs_data_set_default_int(settings, S_POSITION_OUT, NO_OVERRIDE);
obs_data_set_default_int(settings, S_ZOOM_OUT, NO_OVERRIDE);
obs_data_set_default_int(settings, S_TRANSITION_SCALE, NO_OVERRIDE);
}
void move_filter_video_render(void *data, gs_effect_t *effect)
{
UNUSED_PARAMETER(effect);
struct move_filter_info *filter = data;
obs_source_skip_video_filter(filter->source);
}
static const char *move_filter_get_name(void *type_data)
{
UNUSED_PARAMETER(type_data);
return obs_module_text("MoveTransitionOverrideFilter");
}
struct obs_source_info move_transition_override_filter = {
.id = "move_transition_override_filter",
.type = OBS_SOURCE_TYPE_FILTER,
.output_flags = OBS_SOURCE_VIDEO,
.get_name = move_filter_get_name,
.create = move_filter_create,
.destroy = move_filter_destroy,
.get_properties = move_filter_properties,
.get_defaults = move_filter_defaults,
.video_render = move_filter_video_render};
obs-move-transition-2.5.7/move-transition.c 0000664 0000000 0000000 00000220161 14177464325 0020765 0 ustar 00root root 0000000 0000000 #include "move-transition.h"
#include
#include
#include "graphics/math-defs.h"
#include "graphics/matrix4.h"
#include "easing.h"
#include "version.h"
struct move_info {
obs_source_t *source;
bool start_init;
DARRAY(struct move_item *) items_a;
DARRAY(struct move_item *) items_b;
float t;
float curve_move;
float curve_in;
float curve_out;
obs_source_t *scene_source_a;
obs_source_t *scene_source_b;
gs_samplerstate_t *point_sampler;
long long easing_move;
long long easing_in;
long long easing_out;
long long easing_function_move;
long long easing_function_in;
long long easing_function_out;
bool zoom_in;
bool zoom_out;
long long position_in;
long long position_out;
char *transition_move;
char *transition_in;
char *transition_out;
bool part_match;
bool number_match;
bool last_word_match;
enum obs_transition_scale_type transition_move_scale;
size_t item_pos;
uint32_t matched_items;
bool matched_scene_a;
bool matched_scene_b;
uint32_t item_order_switch_percentage;
bool cache_transitions;
DARRAY(obs_source_t *) transition_pool_move;
size_t transition_pool_move_index;
DARRAY(obs_source_t *) transition_pool_in;
size_t transition_pool_in_index;
DARRAY(obs_source_t *) transition_pool_out;
size_t transition_pool_out_index;
};
struct move_item {
obs_sceneitem_t *item_a;
obs_sceneitem_t *item_b;
gs_texrender_t *item_render;
obs_source_t *transition;
long long easing;
long long easing_function;
bool zoom;
long long position;
char *transition_name;
enum obs_transition_scale_type transition_scale;
float curve;
bool move_scene;
int start_percentage;
int end_percentage;
obs_scene_t *release_scene_a;
obs_scene_t *release_scene_b;
};
static const char *move_get_name(void *type_data)
{
UNUSED_PARAMETER(type_data);
return obs_module_text("Move");
}
static void *move_create(obs_data_t *settings, obs_source_t *source)
{
struct move_info *move = bzalloc(sizeof(struct move_info));
move->source = source;
da_init(move->items_a);
da_init(move->items_b);
da_init(move->transition_pool_out);
da_init(move->transition_pool_in);
da_init(move->transition_pool_out);
obs_source_update(source, settings);
return move;
}
static void clear_items(struct move_info *move, bool in_graphics)
{
bool graphics = false;
for (size_t i = 0; i < move->items_a.num; i++) {
struct move_item *item = move->items_a.array[i];
if (item->item_render) {
if (!graphics && !in_graphics) {
obs_enter_graphics();
graphics = true;
}
gs_texrender_destroy(item->item_render);
item->item_render = NULL;
}
}
if (graphics)
obs_leave_graphics();
for (size_t i = 0; i < move->items_a.num; i++) {
struct move_item *item = move->items_a.array[i];
obs_scene_release(item->release_scene_a);
item->release_scene_a = NULL;
obs_sceneitem_release(item->item_a);
item->item_a = NULL;
obs_scene_release(item->release_scene_b);
item->release_scene_b = NULL;
obs_sceneitem_release(item->item_b);
item->item_b = NULL;
if (item->transition) {
obs_transition_force_stop(item->transition);
obs_transition_clear(item->transition);
obs_source_release(item->transition);
item->transition = NULL;
}
bfree(item->transition_name);
bfree(item);
}
move->items_a.num = 0;
move->items_b.num = 0;
}
void clear_transition_pool(void *data)
{
DARRAY(obs_source_t *) *transition_pool = data;
for (size_t i = 0; i < transition_pool->num; i++) {
obs_source_release(transition_pool->array[i]);
}
transition_pool->num = 0;
}
static void move_destroy(void *data)
{
struct move_info *move = data;
clear_items(move, false);
da_free(move->items_a);
da_free(move->items_b);
clear_transition_pool(&move->transition_pool_move);
da_free(move->transition_pool_move);
clear_transition_pool(&move->transition_pool_in);
da_free(move->transition_pool_in);
clear_transition_pool(&move->transition_pool_out);
da_free(move->transition_pool_out);
obs_source_release(move->scene_source_a);
obs_source_release(move->scene_source_b);
bfree(move->transition_in);
bfree(move->transition_out);
bfree(move->transition_move);
if (move->point_sampler) {
obs_enter_graphics();
gs_samplerstate_destroy(move->point_sampler);
obs_leave_graphics();
}
bfree(move);
}
static void move_update(void *data, obs_data_t *settings)
{
struct move_info *move = data;
move->easing_move = obs_data_get_int(settings, S_EASING_MATCH);
move->easing_in = obs_data_get_int(settings, S_EASING_IN);
move->easing_out = obs_data_get_int(settings, S_EASING_OUT);
move->easing_function_move =
obs_data_get_int(settings, S_EASING_FUNCTION_MATCH);
move->easing_function_in =
obs_data_get_int(settings, S_EASING_FUNCTION_IN);
move->easing_function_out =
obs_data_get_int(settings, S_EASING_FUNCTION_OUT);
move->position_in = obs_data_get_int(settings, S_POSITION_IN);
move->zoom_in = obs_data_get_bool(settings, S_ZOOM_IN);
move->position_out = obs_data_get_int(settings, S_POSITION_OUT);
move->zoom_out = obs_data_get_bool(settings, S_ZOOM_OUT);
move->curve_move = (float)obs_data_get_double(settings, S_CURVE_MATCH);
move->curve_in = (float)obs_data_get_double(settings, S_CURVE_IN);
move->curve_out = (float)obs_data_get_double(settings, S_CURVE_OUT);
bfree(move->transition_in);
move->transition_in =
bstrdup(obs_data_get_string(settings, S_TRANSITION_IN));
if (move->transition_in && strlen(move->transition_in) &&
move->transition_pool_in.num &&
strcmp(obs_source_get_name(move->transition_pool_in.array[0]),
move->transition_in) != 0) {
clear_transition_pool(&move->transition_pool_in);
}
bfree(move->transition_out);
move->transition_out =
bstrdup(obs_data_get_string(settings, S_TRANSITION_OUT));
if (move->transition_out && strlen(move->transition_out) &&
move->transition_pool_out.num &&
strcmp(obs_source_get_name(move->transition_pool_out.array[0]),
move->transition_out) != 0) {
clear_transition_pool(&move->transition_pool_out);
}
move->part_match = obs_data_get_bool(settings, S_NAME_PART_MATCH);
move->number_match = obs_data_get_bool(settings, S_NAME_NUMBER_MATCH);
move->last_word_match =
obs_data_get_bool(settings, S_NAME_LAST_WORD_MATCH);
bfree(move->transition_move);
move->transition_move =
bstrdup(obs_data_get_string(settings, S_TRANSITION_MATCH));
if (move->transition_move && strlen(move->transition_move) &&
move->transition_pool_move.num &&
strcmp(obs_source_get_name(move->transition_pool_move.array[0]),
move->transition_move) != 0) {
clear_transition_pool(&move->transition_pool_move);
}
move->transition_move_scale =
obs_data_get_int(settings, S_TRANSITION_SCALE);
move->item_order_switch_percentage =
(uint32_t)obs_data_get_int(settings, S_SWITCH_PERCENTAGE);
move->cache_transitions =
obs_data_get_bool(settings, S_CACHE_TRANSITIONS);
}
void add_alignment(struct vec2 *v, uint32_t align, int32_t cx, int32_t cy)
{
if (align & OBS_ALIGN_RIGHT)
v->x += (float)cx;
else if ((align & OBS_ALIGN_LEFT) == 0)
v->x += (float)(cx >> 1);
if (align & OBS_ALIGN_BOTTOM)
v->y += (float)cy;
else if ((align & OBS_ALIGN_TOP) == 0)
v->y += (float)(cy >> 1);
}
void add_move_alignment(struct vec2 *v, uint32_t align_a, uint32_t align_b,
float t, int32_t cx, int32_t cy)
{
if (align_a & OBS_ALIGN_RIGHT)
v->x += (float)cx * (1.0f - t);
else if ((align_a & OBS_ALIGN_LEFT) == 0)
v->x += (float)(cx >> 1) * (1.0f - t);
if (align_a & OBS_ALIGN_BOTTOM)
v->y += (float)cy * (1.0f - t);
else if ((align_a & OBS_ALIGN_TOP) == 0)
v->y += (float)(cy >> 1) * (1.0f - t);
if (align_b & OBS_ALIGN_RIGHT)
v->x += (float)cx * t;
else if ((align_b & OBS_ALIGN_LEFT) == 0)
v->x += (float)(cx >> 1) * t;
if (align_b & OBS_ALIGN_BOTTOM)
v->y += (float)cy * t;
else if ((align_b & OBS_ALIGN_TOP) == 0)
v->y += (float)(cy >> 1) * t;
}
static void calculate_bounds_data(struct obs_scene_item *item,
struct vec2 *origin, struct vec2 *scale,
int32_t *cx, int32_t *cy, struct vec2 *bounds)
{
float width = (float)(*cx) * fabsf(scale->x);
float height = (float)(*cy) * fabsf(scale->y);
const float item_aspect = width / height;
const float bounds_aspect = bounds->x / bounds->y;
uint32_t bounds_type = obs_sceneitem_get_bounds_type(item);
if (bounds_type == OBS_BOUNDS_MAX_ONLY)
if (width > bounds->x || height > bounds->y)
bounds_type = OBS_BOUNDS_SCALE_INNER;
if (bounds_type == OBS_BOUNDS_SCALE_INNER ||
bounds_type == OBS_BOUNDS_SCALE_OUTER) {
bool use_width = (bounds_aspect < item_aspect);
if (obs_sceneitem_get_bounds_type(item) ==
OBS_BOUNDS_SCALE_OUTER)
use_width = !use_width;
const float mul = use_width ? bounds->x / width
: bounds->y / height;
vec2_mulf(scale, scale, mul);
} else if (bounds_type == OBS_BOUNDS_SCALE_TO_WIDTH) {
vec2_mulf(scale, scale, bounds->x / width);
} else if (bounds_type == OBS_BOUNDS_SCALE_TO_HEIGHT) {
vec2_mulf(scale, scale, bounds->y / height);
} else if (bounds_type == OBS_BOUNDS_STRETCH) {
scale->x = bounds->x / (float)(*cx);
scale->y = bounds->y / (float)(*cy);
}
width = (float)(*cx) * scale->x;
height = (float)(*cy) * scale->y;
const float width_diff = bounds->x - width;
const float height_diff = bounds->y - height;
*cx = (int32_t)roundf(bounds->x);
*cy = (int32_t)roundf(bounds->y);
add_alignment(origin, obs_sceneitem_get_bounds_alignment(item),
(int32_t)-roundf(width_diff),
(int32_t)-roundf(height_diff));
}
static void calculate_move_bounds_data(struct obs_scene_item *item_a,
struct obs_scene_item *item_b, float t,
struct vec2 *origin, struct vec2 *scale,
int32_t *cx, int32_t *cy,
struct vec2 *bounds)
{
struct vec2 origin_a;
vec2_set(&origin_a, origin->x, origin->y);
struct vec2 origin_b;
vec2_set(&origin_b, origin->x, origin->y);
struct vec2 scale_a;
vec2_set(&scale_a, scale->x, scale->y);
struct vec2 scale_b;
vec2_set(&scale_b, scale->x, scale->y);
int32_t cxa = *cx;
int32_t cxb = *cx;
int32_t cya = *cy;
int32_t cyb = *cy;
calculate_bounds_data(item_a, &origin_a, &scale_a, &cxa, &cya, bounds);
calculate_bounds_data(item_b, &origin_b, &scale_b, &cxb, &cyb, bounds);
vec2_set(origin, origin_a.x * (1.0f - t) + origin_b.x * t,
origin_a.y * (1.0f - t) + origin_b.y * t);
vec2_set(scale, scale_a.x * (1.0f - t) + scale_b.x * t,
scale_a.y * (1.0f - t) + scale_b.y * t);
*cx = (int32_t)roundf((float)cxa * (1.0f - t) + (float)cxb * t);
*cy = (int32_t)roundf((float)cya * (1.0f - t) + (float)cyb * t);
}
static inline bool item_is_scene(struct obs_scene_item *item)
{
obs_source_t *source = obs_sceneitem_get_source(item);
return source && obs_source_get_type(source) == OBS_SOURCE_TYPE_SCENE;
}
static inline bool scale_filter_enabled(struct obs_scene_item *item)
{
return obs_sceneitem_get_scale_filter(item) != OBS_SCALE_DISABLE;
}
static inline bool crop_enabled(const struct obs_sceneitem_crop *crop)
{
return crop->left || crop->right || crop->top || crop->bottom;
}
static inline bool item_texture_enabled(struct obs_scene_item *item)
{
if (!item)
false;
struct obs_sceneitem_crop crop;
obs_sceneitem_get_crop(item, &crop);
return crop_enabled(&crop) || scale_filter_enabled(item) ||
(item_is_scene(item) && !obs_sceneitem_is_group(item));
}
void pos_add_center(struct vec2 *pos, uint32_t alignment, uint32_t cx,
uint32_t cy)
{
if (alignment & OBS_ALIGN_LEFT) {
pos->x -= cx >> 1;
} else if (alignment & OBS_ALIGN_RIGHT) {
pos->x += cx >> 1;
}
if (alignment & OBS_ALIGN_TOP) {
pos->y -= cy >> 1;
} else if (alignment & OBS_ALIGN_BOTTOM) {
pos->y += cy >> 1;
}
}
void pos_subtract_center(struct vec2 *pos, uint32_t alignment, int32_t cx,
int32_t cy)
{
if (alignment & OBS_ALIGN_LEFT) {
pos->x += cx >> 1;
} else if (alignment & OBS_ALIGN_RIGHT) {
pos->x -= cx >> 1;
}
if (alignment & OBS_ALIGN_TOP) {
pos->y += cy >> 1;
} else if (alignment & OBS_ALIGN_BOTTOM) {
pos->y -= cy >> 1;
}
}
void calc_edge_position(struct vec2 *pos, long long position,
uint32_t canvas_width, uint32_t canvas_height,
uint32_t alignment, int32_t cx, int32_t cy, bool zoom)
{
int32_t cx2 = abs(cx >> 1);
int32_t cy2 = abs(cy >> 1);
if (zoom) {
cx2 = 0;
cy2 = 0;
}
if (position - POS_EDGE == 0) {
if (alignment & OBS_ALIGN_LEFT) {
pos->x += cx >> 1;
} else if (alignment & OBS_ALIGN_RIGHT) {
pos->x -= cx >> 1;
}
if (alignment & OBS_ALIGN_TOP) {
pos->y += cy >> 1;
} else if (alignment & OBS_ALIGN_BOTTOM) {
pos->y -= cy >> 1;
}
// pos is center of object
float diff_x = pos->x - (canvas_width >> 1);
float diff_y = pos->y - (canvas_height >> 1);
float factor_x = fabsf(diff_x) / (canvas_width >> 1);
float factor_y = fabsf(diff_y) / (canvas_height >> 1);
if (diff_x == 0.0f && diff_y == 0.0f) {
diff_y = 1.0f;
}
if (factor_x > factor_y) {
if (diff_x < 0.0f) {
//left edge
const float move_x = -(pos->x + cx2);
const float move_y =
diff_y * (diff_x + move_x) / diff_x;
vec2_set(pos, -(float)cx2,
(float)(canvas_height >> 1) + move_y);
} else {
//right edge
const float move_x =
(canvas_width - pos->x) + cx2;
const float move_y =
diff_y * (diff_x + move_x) / diff_x;
vec2_set(pos, (float)canvas_width + cx2,
(float)(canvas_height >> 1) + move_y);
}
} else {
if (diff_y < 0.0f) {
//top edge
const float move_y = -(pos->y + cy2);
const float move_x =
diff_x * (diff_y + move_y) / diff_y;
vec2_set(pos,
(float)(canvas_width >> 1) + move_x,
-(float)cy2);
} else {
//bottom edge
const float move_y =
(canvas_height - pos->y) + cy2;
const float move_x =
diff_x * (diff_y + move_y) / diff_y;
vec2_set(pos,
(float)(canvas_width >> 1) + move_x,
(float)canvas_height + cy2);
}
}
if (alignment & OBS_ALIGN_LEFT) {
if (cx < 0) {
pos->x += cx2;
} else {
pos->x -= cx2;
}
} else if (alignment & OBS_ALIGN_RIGHT) {
if (cx < 0) {
pos->x -= cx2;
} else {
pos->x += cx2;
}
}
if (alignment & OBS_ALIGN_TOP) {
if (cy < 0) {
pos->y += cy2;
} else {
pos->y -= cy2;
}
} else if (alignment & OBS_ALIGN_BOTTOM) {
if (cy < 0) {
pos->y -= cy2;
} else {
pos->y += cy2;
}
}
return;
}
if (zoom) {
cx = 0;
cy = 0;
}
if (position & POS_EDGE)
vec2_set(pos, 0, 0);
if (position & POS_RIGHT) {
pos->x = (float)canvas_width;
if (alignment & OBS_ALIGN_RIGHT) {
pos->x += cx;
} else if (alignment & OBS_ALIGN_LEFT) {
} else {
pos->x += cx2;
}
} else if (position & POS_LEFT) {
pos->x = 0;
if (alignment & OBS_ALIGN_RIGHT) {
} else if (alignment & OBS_ALIGN_LEFT) {
pos->x -= cx;
} else {
pos->x -= cx2;
}
} else if (position & POS_EDGE) {
pos->x = (float)(canvas_width >> 1);
if (alignment & OBS_ALIGN_RIGHT) {
pos->x += cx2;
} else if (alignment & OBS_ALIGN_LEFT) {
pos->x -= cx2;
}
}
if (position & POS_BOTTOM) {
pos->y = (float)canvas_height;
if (alignment & OBS_ALIGN_TOP) {
} else if (alignment & OBS_ALIGN_BOTTOM) {
pos->y += cy;
} else {
pos->y += cy2;
}
} else if (position & POS_TOP) {
pos->y = 0;
if (alignment & OBS_ALIGN_BOTTOM) {
} else if (alignment & OBS_ALIGN_TOP) {
pos->y -= cy;
} else {
pos->y -= cy2;
}
} else if (position & POS_EDGE) {
pos->y = (float)(canvas_height >> 1);
if (alignment & OBS_ALIGN_TOP) {
pos->y -= cy2;
} else if (alignment & OBS_ALIGN_BOTTOM) {
pos->y += cy2;
}
}
}
float bezier(float point[], float t, int order)
{
const float p = 1.0f - t;
if (order < 1)
return point[0];
if (order == 1)
return p * point[0] + t * point[1];
return p * bezier(point, t, order - 1) +
t * bezier(&point[1], t, order - 1);
}
void vec2_bezier(struct vec2 *dst, struct vec2 *begin, struct vec2 *control,
struct vec2 *end, const float t)
{
float x[3] = {begin->x, control->x, end->x};
float y[3] = {begin->y, control->y, end->y};
dst->x = bezier(x, t, 2);
dst->y = bezier(y, t, 2);
}
static obs_source_t *obs_frontend_get_transition(const char *name)
{
if (!name)
return NULL;
struct obs_frontend_source_list transitions = {0};
obs_frontend_get_transitions(&transitions);
for (size_t i = 0; i < transitions.sources.num; i++) {
const char *n =
obs_source_get_name(transitions.sources.array[i]);
if (n && strcmp(n, name) == 0) {
obs_source_t *transition = obs_source_get_ref(transitions.sources.array[i]);
obs_frontend_source_list_free(&transitions);
return transition;
}
}
obs_frontend_source_list_free(&transitions);
return NULL;
}
float get_eased(float f, long long easing, long long easing_function)
{
float t = f;
if (EASE_NONE == easing) {
} else if (EASE_IN == easing) {
switch (easing_function) {
case EASING_QUADRATIC:
t = QuadraticEaseIn(f);
break;
case EASING_CUBIC:
t = CubicEaseIn(f);
break;
case EASING_QUARTIC:
t = QuarticEaseIn(f);
break;
case EASING_QUINTIC:
t = QuinticEaseIn(f);
break;
case EASING_SINE:
t = SineEaseIn(f);
break;
case EASING_CIRCULAR:
t = CircularEaseIn(f);
break;
case EASING_EXPONENTIAL:
t = ExponentialEaseIn(f);
break;
case EASING_ELASTIC:
t = ElasticEaseIn(f);
break;
case EASING_BOUNCE:
t = BounceEaseIn(f);
break;
case EASING_BACK:
t = BackEaseIn(f);
break;
default:;
}
} else if (EASE_OUT == easing) {
switch (easing_function) {
case EASING_QUADRATIC:
t = QuadraticEaseOut(f);
break;
case EASING_CUBIC:
t = CubicEaseOut(f);
break;
case EASING_QUARTIC:
t = QuarticEaseOut(f);
break;
case EASING_QUINTIC:
t = QuinticEaseOut(f);
break;
case EASING_SINE:
t = SineEaseOut(f);
break;
case EASING_CIRCULAR:
t = CircularEaseOut(f);
break;
case EASING_EXPONENTIAL:
t = ExponentialEaseOut(f);
break;
case EASING_ELASTIC:
t = ElasticEaseOut(f);
break;
case EASING_BOUNCE:
t = BounceEaseOut(f);
break;
case EASING_BACK:
t = BackEaseOut(f);
break;
default:;
}
} else if (EASE_IN_OUT == easing) {
switch (easing_function) {
case EASING_QUADRATIC:
t = QuadraticEaseInOut(f);
break;
case EASING_CUBIC:
t = CubicEaseInOut(f);
break;
case EASING_QUARTIC:
t = QuarticEaseInOut(f);
break;
case EASING_QUINTIC:
t = QuinticEaseInOut(f);
break;
case EASING_SINE:
t = SineEaseInOut(f);
break;
case EASING_CIRCULAR:
t = CircularEaseInOut(f);
break;
case EASING_EXPONENTIAL:
t = ExponentialEaseInOut(f);
break;
case EASING_ELASTIC:
t = ElasticEaseInOut(f);
break;
case EASING_BOUNCE:
t = BounceEaseInOut(f);
break;
case EASING_BACK:
t = BackEaseInOut(f);
break;
default:;
}
}
return t;
}
obs_source_t *get_transition(const char *transition_name, void *pool_data,
size_t *index, bool cache)
{
if (!transition_name || strlen(transition_name) == 0 ||
strcmp(transition_name, "None") == 0)
return NULL;
DARRAY(obs_source_t *) *transition_pool = pool_data;
const size_t i = *index;
if (cache && transition_pool->num && *index < transition_pool->num) {
obs_source_t *transition =
obs_source_get_ref(transition_pool->array[i]);
*index = i + 1;
return transition;
}
obs_source_t *frontend_transition =
obs_frontend_get_transition(transition_name);
if (!frontend_transition)
return NULL;
obs_source_t *transition = obs_source_duplicate(frontend_transition,
transition_name, true);
obs_source_release(frontend_transition);
if (cache) {
transition = obs_source_get_ref(transition);
darray_push_back(sizeof(obs_source_t *), &transition_pool->da,
&transition);
*index = i + 1;
}
return transition;
}
bool render2_item(struct move_info *move, struct move_item *item)
{
obs_sceneitem_t *scene_item = NULL;
if (item->item_a && item->item_b) {
if (move->t <= 0.5) {
scene_item = item->item_a;
} else {
scene_item = item->item_b;
}
} else if (item->item_a) {
scene_item = item->item_a;
} else if (item->item_b) {
scene_item = item->item_b;
}
obs_source_t *source = obs_sceneitem_get_source(scene_item);
uint32_t width = obs_source_get_width(source);
uint32_t height = obs_source_get_height(source);
bool move_out = item->item_a == scene_item;
if (item->move_scene) {
if (item->transition_name && !item->transition) {
item->transition = get_transition(
item->transition_name,
&move->transition_pool_move,
&move->transition_pool_move_index,
move->cache_transitions);
if (item->transition) {
obs_transition_set_size(item->transition, width,
height);
obs_transition_set_alignment(item->transition,
OBS_ALIGN_CENTER);
obs_transition_set_scale_type(
item->transition,
item->transition_scale);
obs_transition_set(
item->transition,
obs_sceneitem_get_source(scene_item));
obs_transition_start(
item->transition,
obs_transition_fixed(item->transition)
? OBS_TRANSITION_MODE_AUTO
: OBS_TRANSITION_MODE_MANUAL,
obs_frontend_get_transition_duration(),
obs_sceneitem_get_source(scene_item));
}
}
} else if (item->item_a && item->item_b) {
if (item->transition_name && !item->transition) {
item->transition = get_transition(
item->transition_name,
&move->transition_pool_move,
&move->transition_pool_move_index,
move->cache_transitions);
if (item->transition) {
obs_transition_set_size(item->transition, width,
height);
obs_transition_set_alignment(item->transition,
OBS_ALIGN_CENTER);
obs_transition_set_scale_type(
item->transition,
item->transition_scale);
obs_transition_set(
item->transition,
obs_sceneitem_get_source(item->item_a));
obs_transition_start(
item->transition,
obs_transition_fixed(item->transition)
? OBS_TRANSITION_MODE_AUTO
: OBS_TRANSITION_MODE_MANUAL,
obs_frontend_get_transition_duration(),
obs_sceneitem_get_source(item->item_b));
}
}
} else if (move_out && item->transition_name && !item->transition) {
item->transition = get_transition(
item->transition_name, &move->transition_pool_out,
&move->transition_pool_out_index,
move->cache_transitions);
if (item->transition) {
obs_transition_set_size(item->transition, width,
height);
obs_transition_set_alignment(item->transition,
OBS_ALIGN_CENTER);
obs_transition_set_scale_type(
item->transition, OBS_TRANSITION_SCALE_ASPECT);
obs_transition_set(item->transition, source);
obs_transition_start(
item->transition,
obs_transition_fixed(item->transition)
? OBS_TRANSITION_MODE_AUTO
: OBS_TRANSITION_MODE_MANUAL,
obs_frontend_get_transition_duration(), NULL);
}
} else if (!move_out && item->transition_name && !item->transition) {
item->transition = get_transition(
item->transition_name, &move->transition_pool_in,
&move->transition_pool_in_index,
move->cache_transitions);
if (item->transition) {
obs_transition_set_size(item->transition, width,
height);
obs_transition_set_alignment(item->transition,
OBS_ALIGN_CENTER);
obs_transition_set_scale_type(
item->transition, OBS_TRANSITION_SCALE_ASPECT);
obs_transition_set(item->transition, NULL);
obs_transition_start(
item->transition,
obs_transition_fixed(item->transition)
? OBS_TRANSITION_MODE_AUTO
: OBS_TRANSITION_MODE_MANUAL,
obs_frontend_get_transition_duration(), source);
}
}
float t = 0.0f;
if (item->start_percentage > 0 || item->end_percentage < 100) {
if (item->start_percentage > item->end_percentage) {
float avg_switch_point =
(float)(item->start_percentage +
item->end_percentage) /
200.0f;
if (move->t > avg_switch_point) {
t = 1.0f;
}
} else if (move->t * 100.0 < item->start_percentage) {
t = 0.0f;
} else if (move->t * 100.0 > item->end_percentage) {
t = 1.0f;
} else {
int duration_percentage =
item->end_percentage - item->start_percentage;
t = move->t - (float)item->start_percentage / 100.0f;
t = t / (float)duration_percentage * 100.0f;
t = get_eased(t, item->easing, item->easing_function);
}
} else {
t = get_eased(move->t, item->easing, item->easing_function);
}
float ot = t;
if (t > 1.0f)
ot = 1.0f;
else if (t < 0.0f)
ot = 0.0f;
if (item->item_a && item->item_b && item->transition &&
!move->start_init) {
uint32_t width_a = obs_source_get_width(
obs_sceneitem_get_source(item->item_a));
uint32_t width_b = obs_source_get_width(
obs_sceneitem_get_source(item->item_b));
uint32_t height_a = obs_source_get_height(
obs_sceneitem_get_source(item->item_a));
uint32_t height_b = obs_source_get_height(
obs_sceneitem_get_source(item->item_b));
if (width_a != width_b)
width = (uint32_t)roundf((1.0f - t) * width_a +
t * width_b);
if (height_a != height_b)
height = (uint32_t)roundf((1.0f - t) * height_a +
t * height_b);
if (height_a != height_b || width_a != width_b)
obs_transition_set_size(item->transition, width,
height);
}
uint32_t original_width = width;
uint32_t original_height = height;
struct obs_sceneitem_crop crop;
if (item->move_scene) {
obs_sceneitem_get_crop(scene_item, &crop);
if (item->item_a) {
crop.left = (int)roundf((float)(1.0f - ot) *
(float)crop.left);
crop.top = (int)roundf((float)(1.0f - ot) *
(float)crop.top);
crop.right = (int)roundf((float)(1.0f - ot) *
(float)crop.right);
crop.bottom = (int)roundf((float)(1.0f - ot) *
(float)crop.bottom);
} else if (item->item_b) {
crop.left = (int)roundf((float)ot * (float)crop.left);
crop.top = (int)roundf((float)ot * (float)crop.top);
crop.right = (int)roundf((float)ot * (float)crop.right);
crop.bottom =
(int)roundf((float)ot * (float)crop.bottom);
}
} else if (item->item_a && item->item_b) {
struct obs_sceneitem_crop crop_a;
obs_sceneitem_get_crop(item->item_a, &crop_a);
struct obs_sceneitem_crop crop_b;
obs_sceneitem_get_crop(item->item_b, &crop_b);
crop.left =
(int)roundf((float)(1.0f - ot) * (float)crop_a.left +
ot * (float)crop_b.left);
crop.top = (int)roundf((float)(1.0f - ot) * (float)crop_a.top +
ot * (float)crop_b.top);
crop.right =
(int)roundf((float)(1.0f - ot) * (float)crop_a.right +
ot * (float)crop_b.right);
crop.bottom =
(int)roundf((float)(1.0f - ot) * (float)crop_a.bottom +
ot * (float)crop_b.bottom);
} else {
obs_sceneitem_get_crop(scene_item, &crop);
}
uint32_t crop_cx = crop.left + crop.right;
int32_t cx = (crop_cx > width) ? 2 : (width - crop_cx);
uint32_t crop_cy = crop.top + crop.bottom;
int32_t cy = (crop_cy > height) ? 2 : (height - crop_cy);
struct vec2 scale;
struct vec2 original_scale;
obs_sceneitem_get_scale(scene_item, &original_scale);
if (item->item_a && item->item_b) {
struct vec2 scale_a;
obs_sceneitem_get_scale(item->item_a, &scale_a);
struct vec2 scale_b;
obs_sceneitem_get_scale(item->item_b, &scale_b);
vec2_set(&scale, (1.0f - t) * scale_a.x + t * scale_b.x,
(1.0f - t) * scale_a.y + t * scale_b.y);
} else {
if (obs_sceneitem_get_bounds_type(scene_item) !=
OBS_BOUNDS_NONE) {
obs_sceneitem_get_scale(scene_item, &scale);
} else {
obs_sceneitem_get_scale(scene_item, &scale);
if (item->move_scene) {
if (item->item_a) {
vec2_set(&scale,
(1.0f - t) * scale.x + t,
(1.0f - t) * scale.y + t);
} else if (item->item_b) {
vec2_set(&scale,
(1.0f - t) + t * scale.x,
(1.0f - t) + t * scale.y);
}
} else if (!move_out && item->zoom) {
vec2_set(&scale, t * scale.x, t * scale.y);
} else if (move_out && item->zoom) {
vec2_set(&scale, (1.0f - t) * scale.x,
(1.0f - t) * scale.y);
}
}
}
width = cx;
height = cy;
int32_t original_cx = cx;
int32_t original_cy = cy;
struct vec2 base_origin;
struct vec2 origin;
struct vec2 origin2;
vec2_zero(&base_origin);
vec2_zero(&origin);
vec2_zero(&origin2);
uint32_t canvas_width = obs_source_get_width(move->source);
uint32_t canvas_height = obs_source_get_height(move->source);
if (obs_sceneitem_get_bounds_type(scene_item) != OBS_BOUNDS_NONE) {
struct vec2 bounds;
if (item->move_scene) {
obs_sceneitem_get_bounds(scene_item, &bounds);
if (item->item_a) {
vec2_set(&bounds,
(1.0f - t) * bounds.x +
t * canvas_width,
(1.0f - t) * bounds.y +
t * canvas_height);
} else if (item->item_b) {
vec2_set(&bounds,
(1.0f - t) * canvas_width +
t * bounds.x,
(1.0f - t) * canvas_height +
t * bounds.y);
}
} else if (item->item_a && item->item_b) {
struct vec2 bounds_a;
obs_sceneitem_get_bounds(item->item_a, &bounds_a);
struct vec2 bounds_b;
obs_sceneitem_get_bounds(item->item_b, &bounds_b);
vec2_set(&bounds,
(1.0f - t) * bounds_a.x + t * bounds_b.x,
(1.0f - t) * bounds_a.y + t * bounds_b.y);
} else {
obs_sceneitem_get_bounds(scene_item, &bounds);
if (!move_out && item->zoom) {
vec2_set(&bounds, t * bounds.x, t * bounds.y);
} else if (move_out && item->zoom) {
vec2_set(&bounds, (1.0f - t) * bounds.x,
(1.0f - t) * bounds.y);
}
}
if (item->item_a && item->item_b &&
(obs_sceneitem_get_bounds_alignment(item->item_a) !=
obs_sceneitem_get_bounds_alignment(item->item_b) ||
obs_sceneitem_get_bounds_type(item->item_a) !=
obs_sceneitem_get_bounds_type(item->item_b))) {
calculate_move_bounds_data(item->item_a, item->item_b,
t, &origin, &scale, &cx, &cy,
&bounds);
} else {
calculate_bounds_data(scene_item, &origin, &scale, &cx,
&cy, &bounds);
}
struct vec2 original_bounds;
obs_sceneitem_get_bounds(scene_item, &original_bounds);
calculate_bounds_data(scene_item, &origin2, &original_scale,
&original_cx, &original_cy,
&original_bounds);
} else {
original_cx = (int32_t)roundf((float)cx * original_scale.x);
original_cy = (int32_t)roundf((float)cy * original_scale.y);
cx = (int32_t)roundf((float)cx * scale.x);
cy = (int32_t)roundf((float)cy * scale.y);
}
if (item->item_a && item->item_b &&
obs_sceneitem_get_alignment(item->item_a) !=
obs_sceneitem_get_alignment(item->item_b)) {
add_move_alignment(&origin,
obs_sceneitem_get_alignment(item->item_a),
obs_sceneitem_get_alignment(item->item_b), t,
cx, cy);
} else {
add_alignment(&origin, obs_sceneitem_get_alignment(scene_item),
cx, cy);
}
struct matrix4 draw_transform;
matrix4_identity(&draw_transform);
matrix4_scale3f(&draw_transform, &draw_transform, scale.x, scale.y,
1.0f);
matrix4_translate3f(&draw_transform, &draw_transform, -origin.x,
-origin.y, 0.0f);
float rot;
if (item->move_scene) {
rot = obs_sceneitem_get_rot(scene_item);
if (item->item_a) {
rot *= (1.0f - t);
} else if (item->item_b) {
rot *= t;
}
} else if (item->item_a && item->item_b) {
float rot_a = obs_sceneitem_get_rot(item->item_a);
float rot_b = obs_sceneitem_get_rot(item->item_b);
rot = (1.0f - t) * rot_a + t * rot_b;
} else {
rot = obs_sceneitem_get_rot(scene_item);
}
matrix4_rotate_aa4f(&draw_transform, &draw_transform, 0.0f, 0.0f, 1.0f,
RAD(rot));
struct vec2 pos_a;
if (item->item_a) {
obs_sceneitem_get_pos(item->item_a, &pos_a);
} else if (item->move_scene) {
uint32_t alignment = obs_sceneitem_get_alignment(scene_item);
vec2_set(&pos_a, 0, 0);
if (alignment & OBS_ALIGN_RIGHT) {
pos_a.x += canvas_width;
} else if (alignment & OBS_ALIGN_LEFT) {
} else {
pos_a.x += canvas_width >> 1;
}
if (alignment & OBS_ALIGN_BOTTOM) {
pos_a.y += canvas_height;
} else if (alignment & OBS_ALIGN_TOP) {
} else {
pos_a.x += canvas_height >> 1;
}
} else {
uint32_t alignment = obs_sceneitem_get_alignment(scene_item);
if (item->position & POS_CENTER) {
vec2_set(&pos_a, (float)(canvas_width >> 1),
(float)(canvas_height >> 1));
if (!item->zoom)
pos_add_center(&pos_a, alignment, cx, cy);
} else if (item->position & POS_EDGE ||
item->position & POS_SWIPE) {
obs_sceneitem_get_pos(item->item_b, &pos_a);
calc_edge_position(&pos_a, item->position, canvas_width,
canvas_height, alignment,
original_cx, original_cy,
item->zoom);
} else {
obs_sceneitem_get_pos(item->item_b, &pos_a);
if (item->zoom)
pos_subtract_center(&pos_a, alignment,
original_cx, original_cy);
}
}
struct vec2 pos_b;
if (item->item_b) {
obs_sceneitem_get_pos(item->item_b, &pos_b);
} else if (item->move_scene) {
uint32_t alignment = obs_sceneitem_get_alignment(scene_item);
vec2_set(&pos_b, 0, 0);
if (alignment & OBS_ALIGN_RIGHT) {
pos_b.x += canvas_width;
} else if (alignment & OBS_ALIGN_LEFT) {
} else {
pos_b.x += canvas_width >> 1;
}
if (alignment & OBS_ALIGN_BOTTOM) {
pos_b.y += canvas_height;
} else if (alignment & OBS_ALIGN_TOP) {
} else {
pos_b.x += canvas_height >> 1;
}
} else {
uint32_t alignment = obs_sceneitem_get_alignment(scene_item);
if (item->position & POS_CENTER) {
vec2_set(&pos_b, (float)(canvas_width >> 1),
(float)(canvas_height >> 1));
if (!item->zoom)
pos_add_center(&pos_b, alignment, cx, cy);
} else if (item->position & POS_EDGE ||
item->position & POS_SWIPE) {
obs_sceneitem_get_pos(item->item_a, &pos_b);
calc_edge_position(&pos_b, item->position, canvas_width,
canvas_height, alignment,
original_cx, original_cy,
item->zoom);
} else {
obs_sceneitem_get_pos(item->item_a, &pos_b);
if (item->zoom)
pos_subtract_center(&pos_b, alignment,
original_cx, original_cy);
}
}
struct vec2 pos;
if (item->curve != 0.0f) {
float diff_x = fabsf(pos_a.x - pos_b.x);
float diff_y = fabsf(pos_a.y - pos_b.y);
struct vec2 control_pos;
vec2_set(&control_pos, 0.5f * pos_a.x + 0.5f * pos_b.x,
0.5f * pos_a.y + 0.5f * pos_b.y);
if (control_pos.x >= (canvas_width >> 1)) {
control_pos.x += diff_y * item->curve;
} else {
control_pos.x -= diff_y * item->curve;
}
if (control_pos.y >= (canvas_height >> 1)) {
control_pos.y += diff_x * item->curve;
} else {
control_pos.y -= diff_x * item->curve;
}
vec2_bezier(&pos, &pos_a, &control_pos, &pos_b, t);
} else {
vec2_set(&pos, (1.0f - t) * pos_a.x + t * pos_b.x,
(1.0f - t) * pos_a.y + t * pos_b.y);
}
matrix4_translate3f(&draw_transform, &draw_transform, pos.x, pos.y,
0.0f);
struct vec2 output_scale = scale;
if (item->item_render && !item_texture_enabled(item->item_a) &&
!item_texture_enabled(item->item_b)) {
gs_texrender_destroy(item->item_render);
item->item_render = NULL;
} else if (!item->item_render &&
(item->item_a && item_texture_enabled(item->item_a) ||
item->item_b && item_texture_enabled(item->item_b))) {
item->item_render = gs_texrender_create(GS_RGBA, GS_ZS_NONE);
} else if (item->item_render) {
gs_texrender_reset(item->item_render);
}
if (!move->point_sampler) {
struct gs_sampler_info point_sampler_info = {0};
point_sampler_info.max_anisotropy = 1;
move->point_sampler =
gs_samplerstate_create(&point_sampler_info);
}
if (item->item_render) {
if (width && height &&
gs_texrender_begin(item->item_render, width, height)) {
float cx_scale = (float)original_width / (float)width;
float cy_scale = (float)original_height / (float)height;
struct vec4 clear_color;
vec4_zero(&clear_color);
gs_clear(GS_CLEAR_COLOR, &clear_color, 0.0f, 0);
gs_ortho(0.0f, (float)original_width, 0.0f,
(float)original_height, -100.0f, 100.0f);
gs_matrix_scale3f(cx_scale, cy_scale, 1.0f);
gs_matrix_translate3f(-(float)crop.left,
-(float)crop.top, 0.0f);
if (item->transition) {
obs_transition_set_manual_time(item->transition,
ot);
if (!move->start_init) {
obs_source_video_render(
item->transition);
} else if (item->item_a) {
obs_source_video_render(source);
}
} else {
obs_source_video_render(source);
}
gs_texrender_end(item->item_render);
}
}
gs_matrix_push();
gs_matrix_mul(&draw_transform);
const bool previous = gs_set_linear_srgb(true);
if (item->item_render) {
//render_item_texture(item);
gs_texture_t *tex = gs_texrender_get_texture(item->item_render);
if (!tex) {
gs_set_linear_srgb(previous);
gs_matrix_pop();
return true;
}
gs_effect_t *effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
enum obs_scale_type type =
obs_sceneitem_get_scale_filter(scene_item);
cx = gs_texture_get_width(tex);
cy = gs_texture_get_height(tex);
const char *tech = "Draw";
if (type != OBS_SCALE_DISABLE) {
if (type == OBS_SCALE_POINT) {
gs_eparam_t *image =
gs_effect_get_param_by_name(effect,
"image");
gs_effect_set_next_sampler(image,
move->point_sampler);
} else if (!close_float(output_scale.x, 1.0f,
EPSILON) ||
!close_float(output_scale.y, 1.0f,
EPSILON)) {
gs_eparam_t *scale_param;
gs_eparam_t *scale_i_param;
if (output_scale.x < 0.5f ||
output_scale.y < 0.5f) {
effect = obs_get_base_effect(
OBS_EFFECT_BILINEAR_LOWRES);
} else if (type == OBS_SCALE_BICUBIC) {
effect = obs_get_base_effect(
OBS_EFFECT_BICUBIC);
} else if (type == OBS_SCALE_LANCZOS) {
effect = obs_get_base_effect(
OBS_EFFECT_LANCZOS);
} else if (type == OBS_SCALE_AREA) {
effect = obs_get_base_effect(
OBS_EFFECT_AREA);
if ((output_scale.x >= 1.0f) &&
(output_scale.y >= 1.0f))
tech = "DrawUpscale";
}
scale_param = gs_effect_get_param_by_name(
effect, "base_dimension");
if (scale_param) {
struct vec2 base_res = {(float)cx,
(float)cy};
gs_effect_set_vec2(scale_param,
&base_res);
}
scale_i_param = gs_effect_get_param_by_name(
effect, "base_dimension_i");
if (scale_i_param) {
struct vec2 base_res_i = {
1.0f / (float)cx,
1.0f / (float)cy};
gs_effect_set_vec2(scale_i_param,
&base_res_i);
}
}
}
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
while (gs_effect_loop(effect, tech))
obs_source_draw(tex, 0, 0, 0, 0, 0);
gs_blend_state_pop();
} else {
if (item->transition) {
obs_transition_set_manual_time(item->transition, ot);
if (!move->start_init) {
obs_source_video_render(item->transition);
} else if (item->item_a) {
obs_source_video_render(source);
}
} else {
obs_source_video_render(source);
}
}
gs_set_linear_srgb(previous);
gs_matrix_pop();
return true;
}
void get_override_filter(obs_source_t *source, obs_source_t *filter,
void *param)
{
UNUSED_PARAMETER(source);
if (!obs_source_enabled(filter))
return;
if (strcmp(obs_source_get_unversioned_id(filter),
"move_transition_override_filter") != 0)
return;
obs_source_t *target = *(obs_source_t **)param;
if (!target) {
*(obs_source_t **)param = filter;
return;
}
if (obs_source_get_type(target) == OBS_SOURCE_TYPE_FILTER)
return;
obs_data_t *settings = obs_source_get_settings(filter);
if (!settings)
return;
const char *sn = obs_data_get_string(settings, S_SOURCE);
if (sn && strlen(sn)) {
if (strcmp(obs_source_get_name(target), sn) == 0) {
*(obs_source_t **)param = filter;
}
}
obs_data_release(settings);
}
obs_data_t *get_override_filter_settings(obs_sceneitem_t *item)
{
if (!item)
return NULL;
obs_source_t *filter = obs_sceneitem_get_source(item);
obs_scene_t *scene = obs_sceneitem_get_scene(item);
if (scene) {
obs_source_t *scene_source = obs_scene_get_source(scene);
obs_source_enum_filters(scene_source, get_override_filter,
&filter);
}
obs_source_t *source = obs_sceneitem_get_source(item);
if (!source)
return NULL;
if (filter && filter != source)
return obs_source_get_settings(filter);
filter = NULL;
obs_source_enum_filters(source, get_override_filter, &filter);
if (filter && filter != source)
return obs_source_get_settings(filter);
return NULL;
}
bool same_transform_type(struct obs_transform_info *info_a,
struct obs_transform_info *info_b)
{
if (!info_a || !info_b)
return false;
return info_a->alignment == info_b->alignment &&
info_a->bounds_type == info_b->bounds_type &&
info_a->bounds_alignment == info_b->bounds_alignment;
}
bool is_number_match(const char c)
{
if (c >= '0' && c <= '9')
return true;
if (c == '(' || c == ')' || c == ' ' || c == '.' || c == ',')
return true;
return false;
}
struct move_item *match_item2(struct move_info *move,
obs_sceneitem_t *scene_item, bool part_match,
size_t *found_pos)
{
struct move_item *item = NULL;
obs_source_t *source = obs_sceneitem_get_source(scene_item);
const char *name_b = obs_source_get_name(source);
obs_data_t *override_filter = get_override_filter_settings(scene_item);
const char *name_b2 =
override_filter
? obs_data_get_string(override_filter, S_MATCH_SOURCE)
: NULL;
if (override_filter)
obs_data_release(override_filter);
for (size_t i = 0; i < move->items_a.num; i++) {
struct move_item *check_item = move->items_a.array[i];
if (check_item->item_b)
continue;
if (obs_sceneitem_get_bounds_type(check_item->item_a) ==
OBS_BOUNDS_NONE &&
obs_sceneitem_get_bounds_type(scene_item) !=
OBS_BOUNDS_NONE)
continue;
if (obs_sceneitem_get_bounds_type(check_item->item_a) !=
OBS_BOUNDS_NONE &&
obs_sceneitem_get_bounds_type(scene_item) ==
OBS_BOUNDS_NONE)
continue;
obs_source_t *check_source =
obs_sceneitem_get_source(check_item->item_a);
if (!check_source)
continue;
if (check_source == source) {
item = check_item;
*found_pos = i;
break;
}
const char *name_a = obs_source_get_name(check_source);
if (name_a && name_b) {
if (strcmp(name_a, name_b) == 0) {
item = check_item;
*found_pos = i;
break;
}
if (name_b2 && strcmp(name_a, name_b2) == 0) {
item = check_item;
*found_pos = i;
break;
}
override_filter = get_override_filter_settings(
check_item->item_a);
if (override_filter) {
const char *name_a2 = obs_data_get_string(
override_filter, S_MATCH_SOURCE);
obs_data_release(override_filter);
if (strcmp(name_a2, name_b) == 0) {
item = check_item;
*found_pos = i;
break;
}
}
if (part_match) {
size_t len_a = strlen(name_a);
size_t len_b = strlen(name_b);
if (!len_a || !len_b)
continue;
if (len_a > len_b) {
if (move->last_word_match) {
char *last_space =
strrchr(name_b, ' ');
if (last_space &&
last_space > name_b) {
len_b = last_space -
name_b;
}
}
while (len_b > 0 &&
move->number_match &&
is_number_match(
name_b[len_b - 1]))
len_b--;
if (len_b > 0 && move->part_match) {
for (size_t pos = 0;
pos <= len_a - len_b;
pos++) {
if (memcmp(name_a + pos,
name_b,
len_b) ==
0) {
item = check_item;
*found_pos = i;
break;
}
}
if (item)
break;
} else if (len_b > 0 &&
memcmp(name_a, name_b,
len_b) == 0) {
item = check_item;
*found_pos = i;
break;
}
} else {
if (move->last_word_match) {
char *last_space =
strrchr(name_a, ' ');
if (last_space &&
last_space > name_a) {
len_a = last_space -
name_a;
}
}
while (len_a > 0 &&
move->number_match &&
is_number_match(
name_a[len_a - 1]))
len_a--;
if (len_a > 0 && move->part_match) {
for (size_t pos = 0;
pos <= len_b - len_a;
pos++) {
if (memcmp(name_a,
name_b + pos,
len_a) ==
0) {
item = check_item;
*found_pos = i;
break;
}
}
if (item)
break;
} else if (len_a > 0 &&
memcmp(name_a, name_b,
len_a) == 0) {
item = check_item;
*found_pos = i;
break;
}
}
}
} else if (!part_match) {
if (obs_source_get_type(check_source) ==
obs_source_get_type(source)) {
obs_data_t *settings =
obs_source_get_settings(source);
obs_data_t *check_settings =
obs_source_get_settings(check_source);
if (settings && check_settings &&
strcmp(obs_data_get_json(settings),
obs_data_get_json(check_settings)) ==
0) {
item = check_item;
*found_pos = i;
obs_data_release(check_settings);
obs_data_release(settings);
break;
}
obs_data_release(check_settings);
obs_data_release(settings);
}
}
}
return item;
}
struct move_item *create_move_item()
{
struct move_item *item = bzalloc(sizeof(struct move_item));
item->end_percentage = 100;
return item;
}
bool add_item(obs_scene_t *scene, obs_sceneitem_t *scene_item, void *data)
{
UNUSED_PARAMETER(scene);
if (!obs_sceneitem_visible(scene_item)) {
return true;
}
struct move_info *move = data;
struct move_item *item = create_move_item();
da_push_back(move->items_a, &item);
obs_sceneitem_addref(scene_item);
item->item_a = scene_item;
item->move_scene = obs_sceneitem_get_source(scene_item) ==
move->scene_source_b;
if (item->move_scene)
move->matched_scene_b = true;
return true;
}
bool match_item(obs_scene_t *scene, obs_sceneitem_t *scene_item, void *data)
{
UNUSED_PARAMETER(scene);
if (!obs_sceneitem_visible(scene_item)) {
return true;
}
struct move_info *move = data;
size_t old_pos;
struct move_item *item = match_item2(move, scene_item, false, &old_pos);
if (!item &&
(move->part_match || move->number_match || move->last_word_match)) {
item = match_item2(move, scene_item, true, &old_pos);
}
if (item) {
move->matched_items++;
if (old_pos >= move->item_pos)
move->item_pos = old_pos + 1;
} else {
item = create_move_item();
da_insert(move->items_a, move->item_pos, &item);
move->item_pos++;
}
obs_sceneitem_addref(scene_item);
item->item_b = scene_item;
item->move_scene = obs_sceneitem_get_source(scene_item) ==
move->scene_source_a;
if (item->move_scene)
move->matched_scene_a = true;
da_push_back(move->items_b, &item);
return true;
}
void sceneitem_start_move(obs_sceneitem_t *item, const char *start_move)
{
obs_scene_t *scene = obs_sceneitem_get_scene(item);
obs_source_t *scene_source = obs_scene_get_source(scene);
obs_source_t *filter =
obs_source_get_filter_by_name(scene_source, start_move);
if (!filter) {
obs_source_t *source = obs_sceneitem_get_source(item);
filter = obs_source_get_filter_by_name(source, start_move);
}
if (!filter)
return;
const char *filter_id = obs_source_get_unversioned_id(filter);
if (strcmp(filter_id, MOVE_SOURCE_FILTER_ID) == 0) {
move_source_start(obs_obj_get_data(filter));
} else if (strcmp(filter_id, MOVE_VALUE_FILTER_ID) == 0 ||
strcmp(filter_id, MOVE_AUDIO_VALUE_FILTER_ID) == 0) {
move_value_start(obs_obj_get_data(filter));
}
}
static void move_video_render(void *data, gs_effect_t *effect)
{
struct move_info *move = data;
move->t = obs_transition_get_time(move->source);
if (move->start_init) {
obs_source_t *old_scene_a = move->scene_source_a;
move->scene_source_a = obs_transition_get_source(
move->source, OBS_TRANSITION_SOURCE_A);
obs_source_t *old_scene_b = move->scene_source_b;
move->scene_source_b = obs_transition_get_source(
move->source, OBS_TRANSITION_SOURCE_B);
obs_source_release(old_scene_a);
obs_source_release(old_scene_b);
clear_items(move, true);
move->matched_items = 0;
move->transition_pool_move_index = 0;
move->transition_pool_in_index = 0;
move->transition_pool_out_index = 0;
move->matched_scene_a = false;
move->matched_scene_b = false;
move->item_pos = 0;
obs_scene_t *scene_a =
obs_scene_from_source(move->scene_source_a);
if (scene_a) {
obs_scene_enum_items(scene_a, add_item, data);
} else if (move->scene_source_a) {
scene_a = obs_scene_create_private(
obs_source_get_name(move->scene_source_a));
obs_sceneitem_t *scene_item =
obs_scene_add(scene_a, move->scene_source_a);
struct move_item *item = create_move_item();
da_push_back(move->items_a, &item);
item->item_a = scene_item;
item->release_scene_a = scene_a;
}
move->item_pos = 0;
obs_scene_t *scene_b =
obs_scene_from_source(move->scene_source_b);
if (scene_b) {
obs_scene_enum_items(scene_b, match_item, data);
} else if (move->scene_source_b) {
scene_b = obs_scene_create_private(
obs_source_get_name(move->scene_source_b));
obs_sceneitem_t *scene_item =
obs_scene_add(scene_b, move->scene_source_b);
size_t old_pos;
struct move_item *item =
match_item2(move, scene_item, false, &old_pos);
if (!item && (move->part_match || move->number_match ||
move->last_word_match)) {
item = match_item2(move, scene_item, true,
&old_pos);
}
if (item) {
move->matched_items++;
if (old_pos >= move->item_pos)
move->item_pos = old_pos + 1;
} else {
item = create_move_item();
da_insert(move->items_a, move->item_pos, &item);
move->item_pos++;
}
item->item_b = scene_item;
item->release_scene_b = scene_b;
da_push_back(move->items_b, &item);
}
if (!move->matched_items &&
(move->matched_scene_a || move->matched_scene_b)) {
size_t i = 0;
while (i < move->items_a.num) {
struct move_item *item = move->items_a.array[i];
if (move->matched_scene_a && item->item_a) {
obs_sceneitem_release(item->item_a);
da_erase(move->items_a, i);
} else if (move->matched_scene_b &&
item->item_b) {
obs_sceneitem_release(item->item_b);
da_erase(move->items_a, i);
} else {
i++;
}
}
if (move->matched_scene_b) {
move->items_b.num = 0;
}
}
// insert missing items from items_a into items_b
move->item_pos = 0;
for (size_t i = 0; i < move->items_a.num; i++) {
struct move_item *item = move->items_a.array[i];
if (item->item_a && !item->item_b) {
da_insert(move->items_b, move->item_pos, &item);
move->item_pos++;
} else {
for (size_t j = move->item_pos;
j < move->items_b.num; j++) {
if (item == move->items_b.array[j]) {
move->item_pos = j + 1;
break;
}
}
}
}
for (size_t i = 0; i < move->items_a.num; i++) {
struct move_item *item = move->items_a.array[i];
if ((item->item_a && item->item_b) ||
item->move_scene) {
item->easing = move->easing_move;
item->easing_function =
move->easing_function_move;
item->transition_scale =
move->transition_move_scale;
item->curve = move->curve_move;
} else if (item->item_b) {
item->easing = move->easing_in;
item->easing_function =
move->easing_function_in;
item->position = move->position_in;
item->zoom = move->zoom_in;
item->curve = move->curve_in;
} else if (item->item_a) {
item->easing = move->easing_out;
item->easing_function =
move->easing_function_out;
item->position = move->position_out;
item->zoom = move->zoom_out;
item->curve = move->curve_out;
}
obs_data_t *settings_a =
get_override_filter_settings(item->item_a);
obs_data_t *settings_b =
get_override_filter_settings(item->item_b);
if (settings_a && settings_b) {
long long val_a = obs_data_get_int(
settings_a, S_EASING_MATCH);
long long val_b = obs_data_get_int(
settings_b, S_EASING_MATCH);
if (val_a != NO_OVERRIDE &&
val_b != NO_OVERRIDE) {
item->easing = (val_a & EASE_IN) |
(val_b & EASE_OUT);
} else if (val_a != NO_OVERRIDE) {
item->easing = val_a;
} else if (val_b != NO_OVERRIDE) {
item->easing = val_b;
}
val_a = obs_data_get_int(
settings_a, S_EASING_FUNCTION_MATCH);
val_b = obs_data_get_int(
settings_b, S_EASING_FUNCTION_MATCH);
if (val_a != NO_OVERRIDE) {
item->easing_function = val_a;
} else if (val_b != NO_OVERRIDE) {
item->easing_function = val_b;
}
const char *cv_a = obs_data_get_string(
settings_a, S_TRANSITION_MATCH);
const char *cv_b = obs_data_get_string(
settings_b, S_TRANSITION_MATCH);
if (cv_a && strlen(cv_a)) {
bfree(item->transition_name);
item->transition_name = bstrdup(cv_a);
} else if (cv_b && strlen(cv_b)) {
bfree(item->transition_name);
item->transition_name = bstrdup(cv_b);
}
val_a = obs_data_get_int(settings_a,
S_TRANSITION_SCALE);
val_b = obs_data_get_int(settings_b,
S_TRANSITION_SCALE);
if (val_a != NO_OVERRIDE) {
item->transition_scale = val_a;
} else if (val_b != NO_OVERRIDE) {
item->transition_scale = val_b;
}
if (obs_data_get_bool(settings_a,
S_CURVE_OVERRIDE_MATCH)) {
item->curve = (float)obs_data_get_double(
settings_a, S_CURVE_MATCH);
} else if (obs_data_get_bool(
settings_b,
S_CURVE_OVERRIDE_MATCH)) {
item->curve = (float)obs_data_get_double(
settings_b, S_CURVE_MATCH);
}
val_a = obs_data_get_int(
settings_a, S_START_DELAY_MATCH_FROM);
val_b = obs_data_get_int(
settings_b, S_START_DELAY_MATCH_TO);
if (val_a != NO_OVERRIDE &&
val_b != NO_OVERRIDE) {
item->start_percentage =
(int)(val_a + val_b) >> 1;
} else if (val_a != NO_OVERRIDE) {
item->start_percentage = (int)val_a;
} else if (val_b != NO_OVERRIDE) {
item->start_percentage = (int)val_b;
}
val_a = obs_data_get_int(
settings_a, S_END_DELAY_MATCH_FROM);
val_b = obs_data_get_int(settings_b,
S_END_DELAY_MATCH_TO);
if (val_a != NO_OVERRIDE &&
val_b != NO_OVERRIDE) {
item->end_percentage =
100 -
((int)(val_a + val_b) >> 1);
} else if (val_a != NO_OVERRIDE) {
item->end_percentage = 100 - (int)val_a;
} else if (val_b != NO_OVERRIDE) {
item->end_percentage = 100 - (int)val_b;
}
const char *start_move_a = obs_data_get_string(
settings_a, S_START_MOVE_MATCH_FROM);
if (start_move_a && strlen(start_move_a)) {
sceneitem_start_move(item->item_a,
start_move_a);
}
const char *start_move_b = obs_data_get_string(
settings_b, S_START_MOVE_MATCH_TO);
if (start_move_b && strlen(start_move_b)) {
sceneitem_start_move(item->item_b,
start_move_b);
}
} else if (settings_a) {
long long val;
if ((item->item_a && item->item_b) ||
item->move_scene)
val = obs_data_get_int(settings_a,
S_EASING_MATCH);
else
val = obs_data_get_int(settings_a,
S_EASING_OUT);
if (val != NO_OVERRIDE) {
item->easing = val;
}
if ((item->item_a && item->item_b) ||
item->move_scene)
val = obs_data_get_int(
settings_a,
S_EASING_FUNCTION_MATCH);
else
val = obs_data_get_int(
settings_a,
S_EASING_FUNCTION_OUT);
if (val != NO_OVERRIDE) {
item->easing_function = val;
}
val = obs_data_get_int(settings_a, S_ZOOM_OUT);
if (val != NO_OVERRIDE) {
item->zoom = !!val;
}
val = obs_data_get_int(settings_a,
S_POSITION_OUT);
if (val != NO_OVERRIDE) {
item->position = val;
}
val = obs_data_get_int(settings_a,
S_TRANSITION_SCALE);
if (val != NO_OVERRIDE) {
item->transition_scale = val;
}
const char *ti = obs_data_get_string(
settings_a, S_TRANSITION_OUT);
if (!item->move_scene && ti && strlen(ti) &&
item->item_a && !item->item_b) {
bfree(item->transition_name);
item->transition_name = bstrdup(ti);
}
const char *tm = obs_data_get_string(
settings_a, S_TRANSITION_MATCH);
if (tm && strlen(tm) &&
((item->item_a && item->item_b) ||
item->move_scene)) {
bfree(item->transition_name);
item->transition_name = bstrdup(tm);
}
if (((item->item_a && item->item_b) ||
item->move_scene) &&
obs_data_get_bool(settings_a,
S_CURVE_OVERRIDE_MATCH)) {
item->curve = (float)obs_data_get_double(
settings_a, S_CURVE_MATCH);
} else if (!item->move_scene && item->item_a &&
!item->item_b &&
obs_data_get_bool(
settings_a,
S_CURVE_OVERRIDE_OUT)) {
item->curve = (float)obs_data_get_double(
settings_a, S_CURVE_OUT);
}
if ((item->item_a && item->item_b) ||
item->move_scene)
val = obs_data_get_int(
settings_a,
S_START_DELAY_MATCH_FROM);
else
val = obs_data_get_int(
settings_a, S_START_DELAY_OUT);
if (val != NO_OVERRIDE) {
item->start_percentage = (int)val;
}
if ((item->item_a && item->item_b) ||
item->move_scene)
val = obs_data_get_int(
settings_a,
S_END_DELAY_MATCH_FROM);
else
val = obs_data_get_int(settings_a,
S_END_DELAY_OUT);
if (val != NO_OVERRIDE) {
item->end_percentage = 100 - (int)val;
}
const char *move_start =
((item->item_a && item->item_b) ||
item->move_scene)
? obs_data_get_string(
settings_a,
S_START_MOVE_MATCH_FROM)
: obs_data_get_string(
settings_a,
S_START_MOVE_OUT);
if (move_start && strlen(move_start)) {
sceneitem_start_move(item->item_a,
move_start);
}
} else if (settings_b) {
long long val;
if ((item->item_a && item->item_b) ||
item->move_scene)
val = obs_data_get_int(settings_b,
S_EASING_MATCH);
else
val = obs_data_get_int(settings_b,
S_EASING_IN);
if (val != NO_OVERRIDE) {
item->easing = val;
}
if ((item->item_a && item->item_b) ||
item->move_scene)
val = obs_data_get_int(
settings_b,
S_EASING_FUNCTION_MATCH);
else
val = obs_data_get_int(
settings_b,
S_EASING_FUNCTION_IN);
if (val != NO_OVERRIDE) {
item->easing_function = val;
}
val = obs_data_get_int(settings_b, S_ZOOM_IN);
if (val != NO_OVERRIDE) {
item->zoom = !!val;
}
val = obs_data_get_int(settings_b,
S_POSITION_IN);
if (val != NO_OVERRIDE) {
item->position = val;
}
val = obs_data_get_int(settings_b,
S_TRANSITION_SCALE);
if (val != NO_OVERRIDE) {
item->transition_scale = val;
}
const char *to = obs_data_get_string(
settings_b, S_TRANSITION_IN);
if (!item->move_scene && to && strlen(to) &&
!item->item_a && item->item_b) {
bfree(item->transition_name);
item->transition_name = bstrdup(to);
}
const char *tm = obs_data_get_string(
settings_b, S_TRANSITION_MATCH);
if (tm && strlen(tm) &&
((item->item_a && item->item_b) ||
item->move_scene)) {
bfree(item->transition_name);
item->transition_name = bstrdup(tm);
}
if (((item->item_a && item->item_b) ||
item->move_scene) &&
obs_data_get_bool(settings_b,
S_CURVE_OVERRIDE_MATCH)) {
item->curve = (float)obs_data_get_double(
settings_b, S_CURVE_MATCH);
} else if (!item->move_scene && !item->item_a &&
item->item_b &&
obs_data_get_bool(
settings_b,
S_CURVE_OVERRIDE_IN)) {
item->curve =
(float)obs_data_get_double(
settings_b, S_CURVE_IN);
}
if ((item->item_a && item->item_b) ||
item->move_scene)
val = obs_data_get_int(
settings_b,
S_START_DELAY_MATCH_TO);
else
val = obs_data_get_int(
settings_b, S_START_DELAY_IN);
if (val != NO_OVERRIDE) {
item->start_percentage = (int)val;
}
if ((item->item_a && item->item_b) ||
item->move_scene)
val = obs_data_get_int(
settings_b,
S_END_DELAY_MATCH_TO);
else
val = obs_data_get_int(settings_b,
S_END_DELAY_IN);
if (val != NO_OVERRIDE) {
item->end_percentage = 100 - (int)val;
}
const char *move_start =
((item->item_a && item->item_b) ||
item->move_scene)
? obs_data_get_string(
settings_b,
S_START_MOVE_MATCH_TO)
: obs_data_get_string(
settings_a,
S_START_MOVE_IN);
if (move_start && strlen(move_start)) {
sceneitem_start_move(item->item_b,
move_start);
}
}
obs_data_release(settings_a);
obs_data_release(settings_b);
if (!item->transition_name && !item->move_scene &&
!item->item_a && item->item_b &&
move->transition_in &&
strlen(move->transition_in)) {
bfree(item->transition_name);
item->transition_name =
bstrdup(move->transition_in);
}
if (!item->transition_name && !item->move_scene &&
item->item_a && !item->item_b &&
move->transition_out &&
strlen(move->transition_out)) {
bfree(item->transition_name);
item->transition_name =
bstrdup(move->transition_out);
}
if (!item->transition_name &&
((item->item_a && item->item_b) ||
item->move_scene) &&
move->transition_move &&
strlen(move->transition_move)) {
bfree(item->transition_name);
item->transition_name =
bstrdup(move->transition_move);
}
}
}
if (move->t > 0.0f && move->t < 1.0f) {
if (!move->scene_source_a)
move->scene_source_a = obs_transition_get_source(
move->source, OBS_TRANSITION_SOURCE_A);
if (!move->scene_source_b)
move->scene_source_b = obs_transition_get_source(
move->source, OBS_TRANSITION_SOURCE_B);
gs_matrix_push();
gs_blend_state_push();
gs_reset_blend_state();
if (move->t * 100.0 < move->item_order_switch_percentage) {
for (size_t i = 0; i < move->items_a.num; i++) {
struct move_item *item = move->items_a.array[i];
render2_item(move, item);
}
} else {
for (size_t i = 0; i < move->items_b.num; i++) {
struct move_item *item = move->items_b.array[i];
render2_item(move, item);
}
}
gs_blend_state_pop();
gs_matrix_pop();
} else if (move->t <= 0.5f) {
obs_transition_video_render_direct(move->source,
OBS_TRANSITION_SOURCE_A);
} else {
obs_transition_video_render_direct(move->source,
OBS_TRANSITION_SOURCE_B);
}
move->start_init = false;
UNUSED_PARAMETER(effect);
}
static float mix_a(void *data, float t)
{
UNUSED_PARAMETER(data);
return 1.0f - CubicEaseInOut(t);
}
static float mix_b(void *data, float t)
{
UNUSED_PARAMETER(data);
return CubicEaseInOut(t);
}
static bool move_audio_render(void *data, uint64_t *ts_out,
struct obs_source_audio_mix *audio,
uint32_t mixers, size_t channels,
size_t sample_rate)
{
struct move_info *move = data;
return obs_transition_audio_render(move->source, ts_out, audio, mixers,
channels, sample_rate, mix_a, mix_b);
}
void prop_list_add_positions(obs_property_t *p)
{
obs_property_list_add_int(p, obs_module_text("Position.None"),
POS_NONE);
obs_property_list_add_int(p, obs_module_text("Position.Center"),
POS_CENTER);
obs_property_list_add_int(p, obs_module_text("Position.CenterInverse"),
POS_EDGE);
obs_property_list_add_int(p, obs_module_text("Position.TopLeft"),
POS_EDGE | POS_TOP | POS_LEFT);
obs_property_list_add_int(p, obs_module_text("Position.TopCenter"),
POS_EDGE | POS_TOP);
obs_property_list_add_int(p, obs_module_text("Position.TopRight"),
POS_EDGE | POS_TOP | POS_RIGHT);
obs_property_list_add_int(p, obs_module_text("Position.CenterRight"),
POS_EDGE | POS_RIGHT);
obs_property_list_add_int(p, obs_module_text("Position.BottomRight"),
POS_EDGE | POS_BOTTOM | POS_RIGHT);
obs_property_list_add_int(p, obs_module_text("Position.BottomCenter"),
POS_EDGE | POS_BOTTOM);
obs_property_list_add_int(p, obs_module_text("Position.BottomLeft"),
POS_EDGE | POS_BOTTOM | POS_LEFT);
obs_property_list_add_int(p, obs_module_text("Position.CenterLeft"),
POS_EDGE | POS_LEFT);
obs_property_list_add_int(p, obs_module_text("Position.Left"),
POS_SWIPE | POS_LEFT);
obs_property_list_add_int(p, obs_module_text("Position.Top"),
POS_SWIPE | POS_TOP);
obs_property_list_add_int(p, obs_module_text("Position.Right"),
POS_SWIPE | POS_RIGHT);
obs_property_list_add_int(p, obs_module_text("Position.Bottom"),
POS_SWIPE | POS_BOTTOM);
}
void prop_list_add_easings(obs_property_t *p)
{
obs_property_list_add_int(p, obs_module_text("Easing.None"), EASE_NONE);
obs_property_list_add_int(p, obs_module_text("Easing.In"), EASE_IN);
obs_property_list_add_int(p, obs_module_text("Easing.Out"), EASE_OUT);
obs_property_list_add_int(p, obs_module_text("Easing.InOut"),
EASE_IN_OUT);
}
void prop_list_add_easing_functions(obs_property_t *p)
{
obs_property_list_add_int(p,
obs_module_text("EasingFunction.Quadratic"),
EASING_QUADRATIC);
obs_property_list_add_int(p, obs_module_text("EasingFunction.Cubic"),
EASING_CUBIC);
obs_property_list_add_int(p, obs_module_text("EasingFunction.Quartic"),
EASING_QUARTIC);
obs_property_list_add_int(p, obs_module_text("EasingFunction.Quintic"),
EASING_QUINTIC);
obs_property_list_add_int(p, obs_module_text("EasingFunction.Sine"),
EASING_SINE);
obs_property_list_add_int(p, obs_module_text("EasingFunction.Circular"),
EASING_CIRCULAR);
obs_property_list_add_int(p,
obs_module_text("EasingFunction.Exponential"),
EASING_EXPONENTIAL);
obs_property_list_add_int(p, obs_module_text("EasingFunction.Elastic"),
EASING_ELASTIC);
obs_property_list_add_int(p, obs_module_text("EasingFunction.Bounce"),
EASING_BOUNCE);
obs_property_list_add_int(p, obs_module_text("EasingFunction.Back"),
EASING_BACK);
}
void prop_list_add_transitions(obs_property_t *p)
{
struct obs_frontend_source_list transitions = {0};
obs_property_list_add_string(p, obs_module_text("Transition.None"),
"None");
obs_frontend_get_transitions(&transitions);
for (size_t i = 0; i < transitions.sources.num; i++) {
const char *id = obs_source_get_unversioned_id(
transitions.sources.array[i]);
if (!id || strcmp(id, "move_transition") == 0)
continue;
const char *name =
obs_source_get_name(transitions.sources.array[i]);
obs_property_list_add_string(p, name, name);
}
obs_frontend_source_list_free(&transitions);
}
void prop_list_add_scales(obs_property_t *p)
{
obs_property_list_add_int(p, obs_module_text("TransitionScale.MaxOnly"),
OBS_TRANSITION_SCALE_MAX_ONLY);
obs_property_list_add_int(p, obs_module_text("TransitionScale.Aspect"),
OBS_TRANSITION_SCALE_ASPECT);
obs_property_list_add_int(p, obs_module_text("TransitionScale.Stretch"),
OBS_TRANSITION_SCALE_STRETCH);
}
static obs_properties_t *move_properties(void *data)
{
obs_property_t *p;
obs_properties_t *ppts = obs_properties_create();
obs_properties_t *group = obs_properties_create();
obs_properties_add_bool(group, S_NAME_PART_MATCH,
obs_module_text("NamePartMatch"));
obs_properties_add_bool(group, S_NAME_NUMBER_MATCH,
obs_module_text("NameNumberMatch"));
obs_properties_add_bool(group, S_NAME_LAST_WORD_MATCH,
obs_module_text("NameLastWordMatch"));
obs_properties_add_group(ppts, S_MATCH, obs_module_text("MatchName"),
OBS_GROUP_NORMAL, group);
group = obs_properties_create();
obs_properties_add_bool(group, S_CACHE_TRANSITIONS,
obs_module_text("CacheTransitions"));
p = obs_properties_add_int_slider(group, S_SWITCH_PERCENTAGE,
obs_module_text("SwitchPoint"), 0,
100, 1);
obs_property_int_set_suffix(p, "%");
obs_properties_add_group(ppts, S_MOVE_ALL, obs_module_text("MoveAll"),
OBS_GROUP_NORMAL, group);
//Matched items
group = obs_properties_create();
p = obs_properties_add_list(group, S_EASING_MATCH,
obs_module_text("Easing"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easings(p);
p = obs_properties_add_list(group, S_EASING_FUNCTION_MATCH,
obs_module_text("EasingFunction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easing_functions(p);
p = obs_properties_add_list(group, S_TRANSITION_MATCH,
obs_module_text("Transition"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
prop_list_add_transitions(p);
p = obs_properties_add_list(group, S_TRANSITION_SCALE,
obs_module_text("TransitionScaleType"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_scales(p);
obs_properties_add_float_slider(group, S_CURVE_MATCH,
obs_module_text("Curve"), -2.0, 2.0,
0.01);
obs_properties_add_group(ppts, S_MOVE_MATCH,
obs_module_text("MoveMatch"), OBS_GROUP_NORMAL,
group);
//Move in
group = obs_properties_create();
p = obs_properties_add_list(group, S_EASING_IN,
obs_module_text("Easing"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easings(p);
p = obs_properties_add_list(group, S_EASING_FUNCTION_IN,
obs_module_text("EasingFunction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easing_functions(p);
obs_properties_add_bool(group, S_ZOOM_IN, obs_module_text("Zoom"));
p = obs_properties_add_list(group, S_POSITION_IN,
obs_module_text("Position"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_positions(p);
p = obs_properties_add_list(group, S_TRANSITION_IN,
obs_module_text("Transition"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
prop_list_add_transitions(p);
obs_properties_add_float_slider(
group, S_CURVE_IN, obs_module_text("Curve"), -2.0, 2.0, 0.01);
obs_properties_add_group(ppts, S_MOVE_IN, obs_module_text("MoveIn"),
OBS_GROUP_NORMAL, group);
//Move out
group = obs_properties_create();
p = obs_properties_add_list(group, S_EASING_OUT,
obs_module_text("Easing"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easings(p);
p = obs_properties_add_list(group, S_EASING_FUNCTION_OUT,
obs_module_text("EasingFunction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easing_functions(p);
obs_properties_add_bool(group, S_ZOOM_OUT, obs_module_text("Zoom"));
p = obs_properties_add_list(group, S_POSITION_OUT,
obs_module_text("Position"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_positions(p);
p = obs_properties_add_list(group, S_TRANSITION_OUT,
obs_module_text("Transition"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
prop_list_add_transitions(p);
obs_properties_add_float_slider(
group, S_CURVE_OUT, obs_module_text("Curve"), -2.0, 2.0, 0.01);
obs_properties_add_group(ppts, S_MOVE_OUT, obs_module_text("MoveOut"),
OBS_GROUP_NORMAL, group);
UNUSED_PARAMETER(data);
return ppts;
}
void move_defaults(obs_data_t *settings)
{
obs_data_set_default_int(settings, S_EASING_MATCH, EASE_IN_OUT);
obs_data_set_default_int(settings, S_EASING_IN, EASE_IN_OUT);
obs_data_set_default_int(settings, S_EASING_OUT, EASE_IN_OUT);
obs_data_set_default_int(settings, S_EASING_FUNCTION_MATCH,
EASING_CUBIC);
obs_data_set_default_int(settings, S_EASING_FUNCTION_IN, EASING_CUBIC);
obs_data_set_default_int(settings, S_EASING_FUNCTION_OUT, EASING_CUBIC);
obs_data_set_default_int(settings, S_POSITION_IN, POS_EDGE | POS_LEFT);
obs_data_set_default_bool(settings, S_ZOOM_IN, true);
obs_data_set_default_int(settings, S_POSITION_OUT,
POS_EDGE | POS_RIGHT);
obs_data_set_default_bool(settings, S_ZOOM_OUT, true);
obs_data_set_default_double(settings, S_CURVE_MATCH, 0.0);
obs_data_set_default_double(settings, S_CURVE_IN, 0.0);
obs_data_set_default_double(settings, S_CURVE_OUT, 0.0);
obs_data_set_default_int(settings, S_SWITCH_PERCENTAGE, 50);
}
static void move_start(void *data)
{
struct move_info *move = data;
move->start_init = true;
}
static void move_stop(void *data)
{
struct move_info *move = data;
clear_items(move, false);
}
struct obs_source_info move_transition = {.id = "move_transition",
.type = OBS_SOURCE_TYPE_TRANSITION,
.get_name = move_get_name,
.create = move_create,
.destroy = move_destroy,
.update = move_update,
.video_render = move_video_render,
.audio_render = move_audio_render,
.get_properties = move_properties,
.get_defaults = move_defaults,
.transition_start = move_start,
.transition_stop = move_stop};
OBS_DECLARE_MODULE()
OBS_MODULE_AUTHOR("Exeldro");
OBS_MODULE_USE_DEFAULT_LOCALE("move-transition", "en-US")
MODULE_EXPORT const char *obs_module_description(void)
{
return obs_module_text("Description");
}
MODULE_EXPORT const char *obs_module_name(void)
{
return obs_module_text("MoveTransition");
}
extern struct obs_source_info move_transition_override_filter;
extern struct obs_source_info move_source_filter;
extern struct obs_source_info move_value_filter;
extern struct obs_source_info move_audio_value_filter;
extern struct obs_source_info audio_move_filter;
bool obs_module_load(void)
{
blog(LOG_INFO, "[Move Transition] loaded version %s", PROJECT_VERSION);
obs_register_source(&move_transition);
obs_register_source(&move_transition_override_filter);
obs_register_source(&move_source_filter);
obs_register_source(&move_value_filter);
obs_register_source(&move_audio_value_filter);
obs_register_source(&audio_move_filter);
return true;
}
obs-move-transition-2.5.7/move-transition.h 0000664 0000000 0000000 00000022622 14177464325 0020774 0 ustar 00root root 0000000 0000000 #pragma once
#include
#include
#define MOVE_SOURCE_FILTER_ID "move_source_filter"
#define MOVE_VALUE_FILTER_ID "move_value_filter"
#define MOVE_AUDIO_VALUE_FILTER_ID "move_audio_value_filter"
#define AUDIO_MOVE_FILTER_ID "audio_move_filter"
#define S_MATCH "match"
#define S_MOVE_ALL "move_all"
#define S_MOVE_MATCH "move_match"
#define S_MOVE_IN "move_in"
#define S_MOVE_OUT "move_out"
#define S_NAME_PART_MATCH "name_part_match"
#define S_NAME_NUMBER_MATCH "name_number_match"
#define S_NAME_LAST_WORD_MATCH "name_last_word_match"
#define S_GENERAL "general"
#define S_SOURCE "source"
#define S_POSITION_IN "position_in"
#define S_POSITION_OUT "position_out"
#define S_ZOOM_IN "zoom_in"
#define S_ZOOM_OUT "zoom_out"
#define S_EASING_MATCH "easing_match"
#define S_EASING_IN "easing_in"
#define S_EASING_OUT "easing_out"
#define S_EASING_FUNCTION_MATCH "easing_function_match"
#define S_EASING_FUNCTION_IN "easing_function_in"
#define S_EASING_FUNCTION_OUT "easing_function_out"
#define S_CURVE_MATCH "curve_match"
#define S_CURVE_IN "curve_in"
#define S_CURVE_OUT "curve_out"
#define S_CURVE_OVERRIDE_MATCH "curve_override_match"
#define S_CURVE_OVERRIDE_IN "curve_override_in"
#define S_CURVE_OVERRIDE_OUT "curve_override_out"
#define S_TRANSITION_MATCH "transition_match"
#define S_TRANSITION_SCALE "transition_scale_match"
#define S_TRANSITION_IN "transition_in"
#define S_TRANSITION_OUT "transition_out"
#define S_START_DELAY_MATCH_FROM "start_delay_match_from"
#define S_START_DELAY_MATCH_TO "start_delay_match_to"
#define S_START_DELAY_IN "start_delay_in"
#define S_START_DELAY_OUT "start_delay_out"
#define S_END_DELAY_MATCH_FROM "end_delay_match_from"
#define S_END_DELAY_MATCH_TO "end_delay_match_to"
#define S_END_DELAY_IN "end_delay_in"
#define S_END_DELAY_OUT "end_delay_out"
#define S_START_MOVE_MATCH_FROM "start_move_match_from"
#define S_START_MOVE_MATCH_TO "start_move_match_to"
#define S_START_MOVE_IN "start_move_match_in"
#define S_START_MOVE_OUT "start_move_match_out"
#define S_CUSTOM_DURATION "custom_duration"
#define S_DURATION "duration"
#define S_ROT "rot"
#define S_POS "pos"
#define S_SCALE "scale"
#define S_BOUNDS "bounds"
#define S_CROP "crop"
#define S_TRANSFORM_TEXT "transform_text"
#define S_SWITCH_PERCENTAGE "switch_percentage"
#define S_CACHE_TRANSITIONS "cache_transitions"
#define S_START_TRIGGER "start_trigger"
#define S_STOP_TRIGGER "stop_trigger"
#define S_START_DELAY "start_delay"
#define S_END_DELAY "end_delay"
#define S_ACTIONS "actions"
#define S_SIMULTANEOUS_MOVE "simultaneous_move"
#define S_NEXT_MOVE "next_move"
#define S_NEXT_MOVE_ON "next_move_on"
#define S_FILTER "filter"
#define S_SINGLE_SETTING "single_setting"
#define S_MOVE_VALUE_TYPE "move_value_type"
#define S_SETTING_VALUE "setting_value"
#define S_SETTING_RANDOM "setting_random"
#define S_SETTING_NAME "setting_name"
#define S_SETTING_INT "setting_int"
#define S_SETTING_INT_MIN "setting_int_min"
#define S_SETTING_INT_MAX "setting_int_max"
#define S_SETTING_FLOAT "setting_float"
#define S_SETTING_FLOAT_MIN "setting_float_min"
#define S_SETTING_FLOAT_MAX "setting_float_max"
#define S_SETTING_DECIMALS "setting_decimals"
#define S_SETTING_FORMAT_TYPE "setting_format_type"
#define S_SETTING_FORMAT "setting_format"
#define S_SETTING_COLOR "setting_color"
#define S_SETTING_COLOR_MIN "setting_color_min"
#define S_SETTING_COLOR_MAX "setting_color_max"
#define S_SETTING_TEXT "setting_text"
#define S_SETTINGS "settings"
#define S_SETTING_FROM "setting_from"
#define S_SETTING_TO "setting_to"
#define S_VALUE_TYPE "value_type"
#define S_TRANSFORM "transform"
#define S_TRANSFORM_RELATIVE "transform_relative"
#define S_VISIBILITY_ORDER "visibility_order"
#define S_CHANGE_VISIBILITY "change_visibility"
#define S_CHANGE_ORDER "change_order"
#define S_ORDER_POSITION "order_position"
#define S_MEDIA_ACTION "media_action"
#define S_MEDIA_ACTION_START "media_action_start"
#define S_MEDIA_ACTION_START_TIME "media_action_start_time"
#define S_MEDIA_ACTION_END "media_action_end"
#define S_MEDIA_ACTION_END_TIME "media_action_end_time"
#define S_AUDIO_ACTION "audio_action"
#define S_MUTE_ACTION "mute_action"
#define S_AUDIO_FADE "audio_fade"
#define S_AUDIO_FADE_PERCENT "audio_fade_percent"
#define S_ENABLED_MATCH_MOVING "enabled_match_moving"
#define S_MATCH_SOURCE "match_source"
#define NO_OVERRIDE (-1)
#define ZOOM_NO 0
#define ZOOM_YES 1
#define EASE_NONE 0
#define EASE_IN 1
#define EASE_OUT 2
#define EASE_IN_OUT 3
#define EASING_QUADRATIC 1
#define EASING_CUBIC 2
#define EASING_QUARTIC 3
#define EASING_QUINTIC 4
#define EASING_SINE 5
#define EASING_CIRCULAR 6
#define EASING_EXPONENTIAL 7
#define EASING_ELASTIC 8
#define EASING_BOUNCE 9
#define EASING_BACK 10
#define POS_NONE 0
#define POS_CENTER (1 << 0)
#define POS_EDGE (1 << 1)
#define POS_LEFT (1 << 2)
#define POS_RIGHT (1 << 3)
#define POS_TOP (1 << 4)
#define POS_BOTTOM (1 << 5)
#define POS_SWIPE (1 << 6)
#define START_TRIGGER_NONE 0
#define START_TRIGGER_ACTIVATE 1
#define START_TRIGGER_DEACTIVATE 2
#define START_TRIGGER_SHOW 3
#define START_TRIGGER_HIDE 4
#define START_TRIGGER_ENABLE 5
#define START_TRIGGER_SOURCE_ACTIVATE 6
#define START_TRIGGER_SOURCE_DEACTIVATE 7
#define START_TRIGGER_SOURCE_SHOW 8
#define START_TRIGGER_SOURCE_HIDE 9
#define START_TRIGGER_ENABLE_DISABLE_OLD 10
#define START_TRIGGER_MEDIA_STARTED 11
#define START_TRIGGER_MEDIA_ENDED 12
#define START_TRIGGER_LOAD 13
#define MOVE_VALUE_UNKNOWN 0
#define MOVE_VALUE_INT 1
#define MOVE_VALUE_FLOAT 2
#define MOVE_VALUE_COLOR 3
#define MOVE_VALUE_TEXT 4
#define MOVE_VALUE_FORMAT_DECIMALS 0
#define MOVE_VALUE_FORMAT_FLOAT 1
#define MOVE_VALUE_FORMAT_TIME 2
#define NEXT_MOVE_ON_END 0
#define NEXT_MOVE_ON_HOTKEY 1
#define NEXT_MOVE_REVERSE "Reverse"
#define CHANGE_VISIBILITY_NONE 0
#define CHANGE_VISIBILITY_SHOW_START 1
#define CHANGE_VISIBILITY_HIDE_END 2
#define CHANGE_VISIBILITY_TOGGLE 3
#define CHANGE_VISIBILITY_SHOW_END 4
#define CHANGE_VISIBILITY_HIDE_START 5
#define CHANGE_VISIBILITY_TOGGLE_START 6
#define CHANGE_VISIBILITY_TOGGLE_END 7
#define CHANGE_VISIBILITY_SHOW_START_END 8
#define CHANGE_VISIBILITY_HIDE_START_END 9
#define CHANGE_ORDER_NONE 0
#define CHANGE_ORDER_RELATIVE (1 << 0)
#define CHANGE_ORDER_ABSOLUTE (1 << 1)
#define CHANGE_ORDER_START (1 << 2)
#define CHANGE_ORDER_END (1 << 3)
#define MEDIA_ACTION_NONE 0
#define MEDIA_ACTION_PLAY 1
#define MEDIA_ACTION_PAUSE 2
#define MEDIA_ACTION_STOP 3
#define MEDIA_ACTION_RESTART 4
#define MEDIA_ACTION_NEXT 5
#define MEDIA_ACTION_PREVIOUS 6
#define MEDIA_ACTION_PLAY_FROM 7
#define MEDIA_ACTION_PAUSE_AT 8
#define MUTE_ACTION_NONE 0
#define MUTE_ACTION_MUTE_START 1
#define MUTE_ACTION_UNMUTE_START 2
#define MUTE_ACTION_MUTE_END 3
#define MUTE_ACTION_UNMUTE_END 4
#define MUTE_ACTION_MUTE_DURING 5
#define MUTE_ACTION_UNMUTE_DURING 6
#define MOVE_VALUE_TYPE_SINGLE_SETTING 0
#define MOVE_VALUE_TYPE_SETTINGS 1
#define MOVE_VALUE_TYPE_RANDOM 2
#define MOVE_VALUE_TYPE_SETTING_ADD 3
#define MOVE_VALUE_TYPE_TYPING 4
struct move_value_info {
obs_source_t *source;
char *filter_name;
obs_source_t *filter;
char *setting_filter_name;
char *setting_name;
obs_hotkey_id move_start_hotkey;
bool custom_duration;
uint64_t duration;
uint64_t start_delay;
uint64_t end_delay;
uint32_t start_trigger;
uint32_t stop_trigger;
bool moving;
float running_duration;
char *simultaneous_move_name;
char *next_move_name;
bool enabled;
long long easing;
long long easing_function;
long long int_to;
long long int_value;
long long int_from;
long long int_min;
long long int_max;
int decimals;
double double_to;
double double_value;
double double_from;
double double_min;
double double_max;
struct vec4 color_to;
struct vec4 color_value;
struct vec4 color_from;
struct vec4 color_min;
struct vec4 color_max;
char *text_from;
size_t text_from_len;
char *text_to;
size_t text_to_len;
size_t text_same;
size_t text_step;
size_t text_steps;
obs_data_array_t *settings;
long long move_value_type;
long long value_type;
long long format_type;
char *format;
DARRAY(obs_source_t *) filters_done;
long long next_move_on;
bool reverse;
bool enabled_match_moving;
};
struct move_source_info {
obs_source_t *source;
char *source_name;
char *filter_name;
obs_sceneitem_t *scene_item;
obs_hotkey_id move_start_hotkey;
long long easing;
long long easing_function;
float curve;
bool transform;
struct vec2 pos_from;
struct vec2 pos_to;
float rot_from;
float rot_to;
struct vec2 scale_from;
struct vec2 scale_to;
struct vec2 bounds_from;
struct vec2 bounds_to;
struct obs_sceneitem_crop crop_from;
struct obs_sceneitem_crop crop_to;
bool custom_duration;
uint64_t duration;
uint64_t start_delay;
uint64_t end_delay;
bool moving;
float running_duration;
uint32_t canvas_width;
uint32_t canvas_height;
uint32_t start_trigger;
uint32_t stop_trigger;
bool enabled;
char *simultaneous_move_name;
char *next_move_name;
DARRAY(obs_source_t *) filters_done;
long long next_move_on;
long long change_visibility;
bool visibility_toggled;
bool reverse;
long long change_order;
long long order_position;
long long media_action_start;
int64_t media_time_start;
long long media_action_end;
int64_t media_time_end;
bool audio_fade;
float audio_fade_from;
float audio_fade_to;
long long mute_action;
bool enabled_match_moving;
};
void move_value_start(struct move_value_info *move_value);
void move_source_start(struct move_source_info *move_source);
void prop_list_add_move_source_filter(obs_source_t *parent, obs_source_t *child,
void *data);
obs-move-transition-2.5.7/move-value-filter.c 0000664 0000000 0000000 00000205621 14177464325 0021176 0 ustar 00root root 0000000 0000000 #include "move-transition.h"
#include
#include
#include
#include
#include
#include
#define TEXT_BUFFER_SIZE 256
#define VOLUME_SETTING "source_volume"
#define VOLUME_MIN 0.0
#define VOLUME_MAX 100.0
#define VOLUME_STEP 1.0
static void load_properties(obs_properties_t *props_from,
obs_data_array_t *array, obs_data_t *settings_to,
obs_data_t *settings_from)
{
obs_property_t *prop_from = obs_properties_first(props_from);
for (; prop_from != NULL; obs_property_next(&prop_from)) {
const char *name = obs_property_name(prop_from);
if (!obs_property_visible(prop_from))
continue;
obs_data_t *setting = NULL;
const size_t count = obs_data_array_count(array);
for (size_t i = 0; i < count; i++) {
obs_data_t *item2 = obs_data_array_item(array, i);
const char *setting_name2 =
obs_data_get_string(item2, S_SETTING_NAME);
if (strcmp(setting_name2, name) == 0) {
setting = item2;
}
}
const enum obs_property_type prop_type =
obs_property_get_type(prop_from);
if (prop_type == OBS_PROPERTY_GROUP) {
load_properties(obs_property_group_content(prop_from),
array, settings_to, settings_from);
} else if (prop_type == OBS_PROPERTY_INT) {
if (!setting) {
setting = obs_data_create();
obs_data_set_string(setting, S_SETTING_NAME,
name);
obs_data_array_push_back(array, setting);
}
obs_data_set_int(setting, S_VALUE_TYPE, MOVE_VALUE_INT);
if (obs_data_has_default_value(settings_from, name))
obs_data_set_default_int(
settings_to, name,
obs_data_get_default_int(settings_from,
name));
const long long to =
obs_data_get_int(settings_to, name);
obs_data_set_int(setting, S_SETTING_TO, to);
const long long from =
obs_data_get_int(settings_from, name);
obs_data_set_int(setting, S_SETTING_FROM, from);
} else if (prop_type == OBS_PROPERTY_FLOAT) {
if (!setting) {
setting = obs_data_create();
obs_data_set_string(setting, S_SETTING_NAME,
name);
obs_data_array_push_back(array, setting);
}
obs_data_set_int(setting, S_VALUE_TYPE,
MOVE_VALUE_FLOAT);
if (obs_data_has_default_value(settings_from, name))
obs_data_set_default_double(
settings_to, name,
obs_data_get_default_double(
settings_from, name));
const double to =
obs_data_get_double(settings_to, name);
obs_data_set_double(setting, S_SETTING_TO, to);
const double from =
obs_data_get_double(settings_from, name);
obs_data_set_double(setting, S_SETTING_FROM, from);
} else if (prop_type == OBS_PROPERTY_COLOR ||
prop_type == OBS_PROPERTY_COLOR_ALPHA) {
if (!setting) {
setting = obs_data_create();
obs_data_set_string(setting, S_SETTING_NAME,
name);
obs_data_array_push_back(array, setting);
}
obs_data_set_int(setting, S_VALUE_TYPE,
MOVE_VALUE_COLOR);
if (obs_data_has_default_value(settings_from, name))
obs_data_set_default_int(
settings_to, name,
obs_data_get_default_int(settings_from,
name));
obs_data_set_int(setting, S_SETTING_TO,
obs_data_get_int(settings_to, name));
const long long from =
obs_data_get_int(settings_from, name);
obs_data_set_int(setting, S_SETTING_FROM, from);
}
}
}
void move_values_load_properties(struct move_value_info *move_value,
obs_source_t *source, obs_data_t *settings)
{
if (source && source != move_value->source) {
obs_properties_t *sps = obs_source_properties(source);
size_t index = 0;
while (index < obs_data_array_count(move_value->settings)) {
obs_data_t *item = obs_data_array_item(
move_value->settings, index);
const char *setting_name =
obs_data_get_string(item, S_SETTING_NAME);
if (obs_properties_get(sps, setting_name) == NULL) {
obs_data_array_erase(move_value->settings,
index);
} else {
index++;
}
}
obs_data_t *data_from = obs_source_get_settings(source);
load_properties(sps, move_value->settings, settings, data_from);
obs_data_release(data_from);
obs_properties_destroy(sps);
} else {
while (obs_data_array_count(move_value->settings)) {
obs_data_array_erase(move_value->settings, 0);
}
}
}
long long rand_between(long long a, long long b)
{
return b > a ? a + rand() % (b - a) : b + rand() % (a - b);
}
float rand_between_float(float a, float b)
{
return b > a ? a + (b - a) * (float)rand() / (float)RAND_MAX
: b + (a - b) * (float)rand() / (float)RAND_MAX;
}
double rand_between_double(double a, double b)
{
return b > a ? a + (b - a) * (double)rand() / (double)RAND_MAX
: b + (a - b) * (double)rand() / (double)RAND_MAX;
}
double parse_text(long long format_type, const char *format, const char *text)
{
double value = 0.0;
if (format_type == MOVE_VALUE_FORMAT_FLOAT) {
sscanf(text, format, &value);
} else if (format_type == MOVE_VALUE_FORMAT_TIME) {
char *pos;
unsigned int sec = 0;
unsigned int min = 0;
unsigned int hour = 0;
if ((pos = strstr(format, "%X")) ||
(pos = strstr(format, "%H:%M:%S"))) {
if ((pos - format) < strlen(text))
sscanf(text + (pos - format), "%u:%u:%u", &hour,
&min, &sec);
} else if ((pos = strstr(format, "%R")) ||
(pos = strstr(format, "%H:%M"))) {
if ((pos - format) < strlen(text))
sscanf(text + (pos - format), "%u:%u", &hour,
&min);
} else if (pos = strstr(format, "%M:%S")) {
if ((pos - format) < strlen(text))
sscanf(text + (pos - format), "%u:%u", &min,
&sec);
} else {
if (pos = strstr(format, "%S")) {
sscanf(text + (pos - format), "%u", &sec);
}
if (pos = strstr(format, "%M")) {
sscanf(text + (pos - format), "%u", &min);
}
if (pos = strstr(format, "%H")) {
sscanf(text + (pos - format), "%u", &hour);
}
}
value = hour * 3600 + min * 60 + sec;
} else {
value = strtod(text, NULL);
}
return value;
}
void move_value_start(struct move_value_info *move_value)
{
if (!move_value->filter && move_value->setting_filter_name &&
strlen(move_value->setting_filter_name)) {
obs_source_t *parent =
obs_filter_get_parent(move_value->source);
if (parent) {
move_value->filter = obs_source_get_filter_by_name(
parent, move_value->setting_filter_name);
} else {
return;
}
}
if (move_value->reverse) {
move_value->running_duration = 0.0f;
move_value->moving = true;
return;
}
if (!move_value->custom_duration)
move_value->duration = obs_frontend_get_transition_duration();
if (move_value->moving && move_value->enabled) {
if (move_value->next_move_on == NEXT_MOVE_ON_HOTKEY &&
move_value->next_move_name &&
strcmp(move_value->next_move_name, NEXT_MOVE_REVERSE) ==
0) {
move_value->reverse = !move_value->reverse;
move_value->running_duration =
(float)(move_value->duration +
move_value->start_delay +
move_value->end_delay) /
1000.0f -
move_value->running_duration;
}
return;
}
if (!move_value->setting_filter_name) {
obs_source_update(move_value->source, NULL);
}
obs_source_t *source =
move_value->setting_filter_name &&
strlen(move_value->setting_filter_name)
? move_value->filter
: obs_filter_get_parent(move_value->source);
obs_data_t *ss = obs_source_get_settings(source);
if (move_value->settings) {
obs_data_t *settings =
obs_source_get_settings(move_value->source);
move_values_load_properties(move_value, source, settings);
obs_data_release(settings);
move_value->running_duration = 0.0f;
move_value->moving = true;
} else if (move_value->value_type == MOVE_VALUE_INT) {
if (strcmp(move_value->setting_name, VOLUME_SETTING) == 0) {
move_value->int_from =
obs_source_get_volume(source) * 100.0f;
} else {
move_value->int_from =
obs_data_get_int(ss, move_value->setting_name);
}
if (move_value->move_value_type == MOVE_VALUE_TYPE_RANDOM) {
move_value->int_to = rand_between(move_value->int_min,
move_value->int_max);
} else if (move_value->move_value_type ==
MOVE_VALUE_TYPE_SETTING_ADD) {
move_value->int_to =
move_value->int_from + move_value->int_value;
} else {
move_value->int_to = move_value->int_value;
}
move_value->running_duration = 0.0f;
move_value->moving = true;
} else if (move_value->value_type == MOVE_VALUE_FLOAT) {
if (strcmp(move_value->setting_name, VOLUME_SETTING) == 0) {
move_value->double_from =
obs_source_get_volume(source) * 100.0f;
} else {
move_value->double_from = obs_data_get_double(
ss, move_value->setting_name);
}
if (move_value->move_value_type == MOVE_VALUE_TYPE_RANDOM) {
move_value->double_to = rand_between_double(
move_value->double_min, move_value->double_max);
} else if (move_value->move_value_type ==
MOVE_VALUE_TYPE_SETTING_ADD) {
move_value->double_to = move_value->double_from +
move_value->double_value;
} else {
move_value->double_to = move_value->double_value;
}
move_value->running_duration = 0.0f;
move_value->moving = true;
} else if (move_value->value_type == MOVE_VALUE_COLOR) {
vec4_from_rgba(&move_value->color_from,
(uint32_t)obs_data_get_int(
ss, move_value->setting_name));
gs_float3_srgb_nonlinear_to_linear(move_value->color_from.ptr);
if (move_value->move_value_type == MOVE_VALUE_TYPE_RANDOM) {
move_value->color_to.w =
rand_between_float(move_value->color_min.w,
move_value->color_max.w);
move_value->color_to.x =
rand_between_float(move_value->color_min.x,
move_value->color_max.x);
move_value->color_to.y =
rand_between_float(move_value->color_min.y,
move_value->color_max.y);
move_value->color_to.z =
rand_between_float(move_value->color_min.z,
move_value->color_max.z);
} else if (move_value->move_value_type ==
MOVE_VALUE_TYPE_SETTING_ADD) {
move_value->color_to.w = move_value->color_from.w +
move_value->color_value.w;
move_value->color_to.x = move_value->color_from.x +
move_value->color_value.x;
move_value->color_to.y = move_value->color_from.y +
move_value->color_value.y;
move_value->color_to.z = move_value->color_from.z +
move_value->color_value.z;
} else {
vec4_copy(&move_value->color_to,
&move_value->color_value);
}
gs_float3_srgb_nonlinear_to_linear(move_value->color_to.ptr);
move_value->running_duration = 0.0f;
move_value->moving = true;
} else if (move_value->value_type == MOVE_VALUE_TEXT) {
const char *text_from =
obs_data_get_string(ss, move_value->setting_name);
move_value->double_from = parse_text(
move_value->format_type, move_value->format, text_from);
if (move_value->move_value_type == MOVE_VALUE_TYPE_RANDOM) {
move_value->double_to = rand_between_double(
move_value->double_min, move_value->double_max);
} else if (move_value->move_value_type ==
MOVE_VALUE_TYPE_SETTING_ADD) {
move_value->double_to = move_value->double_from +
move_value->double_value;
} else if (move_value->move_value_type ==
MOVE_VALUE_TYPE_TYPING) {
bfree(move_value->text_from);
move_value->text_from = bstrdup(text_from);
move_value->text_from_len = strlen(text_from);
move_value->text_step = 0;
move_value->text_same = 0;
while (move_value->text_same <
move_value->text_from_len &&
move_value->text_same <
move_value->text_to_len &&
move_value->text_from[move_value->text_same] ==
move_value
->text_to[move_value->text_same])
move_value->text_same++;
move_value->text_steps = (move_value->text_from_len -
move_value->text_same) +
(move_value->text_to_len -
move_value->text_same);
} else {
move_value->double_to = move_value->double_value;
}
move_value->running_duration = 0.0f;
move_value->moving = true;
} else {
if (strcmp(move_value->setting_name, VOLUME_SETTING) == 0) {
move_value->int_from =
obs_source_get_volume(source) * 100.0f;
move_value->double_from =
obs_source_get_volume(source) * 100.0;
} else {
move_value->int_from =
obs_data_get_int(ss, move_value->setting_name);
move_value->double_from = obs_data_get_double(
ss, move_value->setting_name);
}
move_value->int_to = move_value->int_value;
move_value->double_to = move_value->double_value;
move_value->running_duration = 0.0f;
move_value->moving = true;
}
if (move_value->enabled_match_moving &&
obs_source_enabled(move_value->source) != move_value->moving) {
move_value->enabled = move_value->moving;
obs_source_set_enabled(move_value->source, move_value->moving);
}
obs_data_release(ss);
if (move_value->moving && move_value->simultaneous_move_name &&
strlen(move_value->simultaneous_move_name) &&
(!move_value->filter_name ||
strcmp(move_value->filter_name,
move_value->simultaneous_move_name) != 0)) {
obs_source_t *parent =
obs_filter_get_parent(move_value->source);
if (parent) {
obs_source_t *filter = obs_source_get_filter_by_name(
parent, move_value->simultaneous_move_name);
if (filter &&
(strcmp(obs_source_get_unversioned_id(filter),
MOVE_VALUE_FILTER_ID) == 0 ||
strcmp(obs_source_get_unversioned_id(filter),
MOVE_AUDIO_VALUE_FILTER_ID) == 0)) {
struct move_value_info *filter_data =
obs_obj_get_data(filter);
if (!filter_data->moving) {
move_value_start(filter_data);
}
}
obs_source_release(filter);
}
}
}
bool move_value_start_button(obs_properties_t *props, obs_property_t *property,
void *data)
{
struct move_value_info *move_value = data;
move_value_start(move_value);
UNUSED_PARAMETER(props);
UNUSED_PARAMETER(property);
return false;
}
void move_value_start_hotkey(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
bool pressed)
{
if (!pressed)
return;
struct move_value_info *move_value = data;
if (move_value->next_move_on != NEXT_MOVE_ON_HOTKEY ||
!move_value->next_move_name ||
!strlen(move_value->next_move_name)) {
move_value_start(move_value);
return;
}
if (!move_value->filters_done.num) {
move_value_start(move_value);
da_push_back(move_value->filters_done, &move_value->source);
return;
}
obs_source_t *parent = obs_filter_get_parent(move_value->source);
if (!parent)
return;
struct move_value_info *filter_data = move_value;
size_t i = 0;
while (i < move_value->filters_done.num) {
if (!filter_data->next_move_name ||
!strlen(filter_data->next_move_name)) {
move_value_start(move_value);
move_value->filters_done.num = 0;
da_push_back(move_value->filters_done,
&move_value->source);
return;
}
obs_source_t *filter = obs_source_get_filter_by_name(
parent, filter_data->next_move_name);
if (!filter || (strcmp(obs_source_get_unversioned_id(filter),
MOVE_VALUE_FILTER_ID) != 0 &&
strcmp(obs_source_get_unversioned_id(filter),
MOVE_AUDIO_VALUE_FILTER_ID) != 0)) {
obs_source_release(filter);
move_value_start(move_value);
move_value->filters_done.num = 0;
da_push_back(move_value->filters_done,
&move_value->source);
return;
}
if (filter_data->moving &&
obs_source_enabled(filter_data->source) &&
(filter_data->reverse || !filter_data->next_move_name ||
strcmp(filter_data->next_move_name, NEXT_MOVE_REVERSE) !=
0)) {
filter_data->moving = false;
if (filter_data->enabled_match_moving)
obs_source_set_enabled(filter_data->source,
false);
}
if (filter_data->next_move_on != NEXT_MOVE_ON_HOTKEY) {
filter_data = obs_obj_get_data(filter);
da_push_back(move_value->filters_done,
&filter_data->source);
} else {
filter_data = obs_obj_get_data(filter);
}
obs_source_release(filter);
i++;
}
for (i = 0; i < move_value->filters_done.num; i++) {
if (move_value->filters_done.array[i] == filter_data->source) {
move_value_start(move_value);
move_value->filters_done.num = 0;
da_push_back(move_value->filters_done,
&move_value->source);
return;
}
}
move_value_start(filter_data);
da_push_back(move_value->filters_done, &filter_data->source);
UNUSED_PARAMETER(id);
UNUSED_PARAMETER(hotkey);
}
void move_value_update(void *data, obs_data_t *settings)
{
struct move_value_info *move_value = data;
obs_source_t *parent = obs_filter_get_parent(move_value->source);
const char *filter_name = obs_source_get_name(move_value->source);
if (!move_value->filter_name ||
strcmp(move_value->filter_name, filter_name) != 0) {
bfree(move_value->filter_name);
move_value->filter_name = NULL;
if (move_value->move_start_hotkey != OBS_INVALID_HOTKEY_ID) {
obs_hotkey_unregister(move_value->move_start_hotkey);
move_value->move_start_hotkey = OBS_INVALID_HOTKEY_ID;
}
if (parent) {
move_value->filter_name = bstrdup(filter_name);
move_value->move_start_hotkey =
obs_hotkey_register_source(
parent, filter_name, filter_name,
move_value_start_hotkey, data);
}
}
const char *setting_filter_name =
obs_data_get_string(settings, S_FILTER);
if (!move_value->setting_filter_name ||
strcmp(move_value->setting_filter_name, setting_filter_name) != 0) {
obs_source_release(move_value->filter);
move_value->filter = NULL;
if (parent) {
bfree(move_value->setting_filter_name);
move_value->setting_filter_name =
bstrdup(setting_filter_name);
move_value->filter = obs_source_get_filter_by_name(
parent, setting_filter_name);
}
}
const char *setting_name =
obs_data_get_string(settings, S_SETTING_NAME);
if (!move_value->setting_name ||
strcmp(move_value->setting_name, setting_name) != 0) {
bfree(move_value->setting_name);
move_value->setting_name = bstrdup(setting_name);
}
if (obs_data_has_user_value(settings, S_SINGLE_SETTING)) {
obs_data_set_int(settings, S_MOVE_VALUE_TYPE,
obs_data_get_bool(settings, S_SINGLE_SETTING)
? MOVE_VALUE_TYPE_SINGLE_SETTING
: MOVE_VALUE_TYPE_SETTINGS);
obs_data_unset_user_value(settings, S_SINGLE_SETTING);
}
if (obs_data_get_int(settings, S_MOVE_VALUE_TYPE) !=
MOVE_VALUE_TYPE_SETTINGS) {
obs_data_array_release(move_value->settings);
move_value->settings = NULL;
} else if (parent) {
if (!move_value->settings)
move_value->settings = obs_data_array_create();
obs_source_t *source =
move_value->setting_filter_name &&
strlen(move_value->setting_filter_name)
? move_value->filter
: parent;
move_values_load_properties(move_value, source, settings);
}
move_value->move_value_type =
obs_data_get_int(settings, S_MOVE_VALUE_TYPE);
move_value->value_type = obs_data_get_int(settings, S_VALUE_TYPE);
move_value->format_type =
obs_data_get_int(settings, S_SETTING_FORMAT_TYPE);
char *format = obs_data_get_string(settings, S_SETTING_FORMAT);
if (move_value->format_type == MOVE_VALUE_FORMAT_FLOAT &&
strlen(format) == 0) {
format = "%f";
obs_data_set_string(settings, S_SETTING_FORMAT, format);
}
if (move_value->format_type == MOVE_VALUE_FORMAT_TIME &&
strlen(format) == 0) {
format = "%X";
obs_data_set_string(settings, S_SETTING_FORMAT, format);
}
if (!move_value->format || strcmp(move_value->format, format) != 0) {
bfree(move_value->format);
move_value->format = bstrdup(format);
}
move_value->decimals = obs_data_get_int(settings, S_SETTING_DECIMALS);
move_value->int_value = obs_data_get_int(settings, S_SETTING_INT);
move_value->int_min = obs_data_get_int(settings, S_SETTING_INT_MIN);
move_value->int_max = obs_data_get_int(settings, S_SETTING_INT_MAX);
move_value->double_value =
obs_data_get_double(settings, S_SETTING_FLOAT);
move_value->double_min =
obs_data_get_double(settings, S_SETTING_FLOAT_MIN);
move_value->double_max =
obs_data_get_double(settings, S_SETTING_FLOAT_MAX);
vec4_from_rgba(&move_value->color_value,
(uint32_t)obs_data_get_int(settings, S_SETTING_COLOR));
vec4_from_rgba(&move_value->color_min,
(uint32_t)obs_data_get_int(settings,
S_SETTING_COLOR_MIN));
vec4_from_rgba(&move_value->color_max,
(uint32_t)obs_data_get_int(settings,
S_SETTING_COLOR_MAX));
const char *text_to = obs_data_get_string(settings, S_SETTING_TEXT);
if (!move_value->text_to || strcmp(move_value->text_to, text_to) != 0) {
bfree(move_value->text_to);
move_value->text_to = bstrdup(text_to);
move_value->text_to_len = strlen(text_to);
}
move_value->custom_duration =
obs_data_get_bool(settings, S_CUSTOM_DURATION);
if (move_value->custom_duration)
move_value->duration = obs_data_get_int(settings, S_DURATION);
move_value->start_delay = obs_data_get_int(settings, S_START_DELAY);
move_value->end_delay = obs_data_get_int(settings, S_END_DELAY);
move_value->easing = obs_data_get_int(settings, S_EASING_MATCH);
move_value->easing_function =
obs_data_get_int(settings, S_EASING_FUNCTION_MATCH);
move_value->enabled_match_moving =
obs_data_get_bool(settings, S_ENABLED_MATCH_MOVING);
if (move_value->enabled_match_moving && !move_value->moving &&
obs_source_enabled(move_value->source))
move_value_start(move_value);
move_value->start_trigger =
(uint32_t)obs_data_get_int(settings, S_START_TRIGGER);
move_value->stop_trigger =
(uint32_t)obs_data_get_int(settings, S_STOP_TRIGGER);
const char *simultaneous_move_name =
obs_data_get_string(settings, S_SIMULTANEOUS_MOVE);
if (!move_value->simultaneous_move_name ||
strcmp(move_value->simultaneous_move_name,
simultaneous_move_name) != 0) {
bfree(move_value->simultaneous_move_name);
move_value->simultaneous_move_name =
bstrdup(simultaneous_move_name);
}
const char *next_move_name = obs_data_get_string(settings, S_NEXT_MOVE);
if (!move_value->next_move_name ||
strcmp(move_value->next_move_name, next_move_name) != 0) {
bfree(move_value->next_move_name);
move_value->next_move_name = bstrdup(next_move_name);
move_value->reverse = false;
}
move_value->next_move_on = obs_data_get_int(settings, S_NEXT_MOVE_ON);
if (move_value->start_trigger == START_TRIGGER_LOAD) {
move_value_start(move_value);
}
}
static void *move_value_create(obs_data_t *settings, obs_source_t *source)
{
struct move_value_info *move_value =
bzalloc(sizeof(struct move_value_info));
move_value->source = source;
move_value->move_start_hotkey = OBS_INVALID_HOTKEY_ID;
move_value_update(move_value, settings);
return move_value;
}
static void move_value_destroy(void *data)
{
struct move_value_info *move_value = data;
obs_source_release(move_value->filter);
move_value->filter = NULL;
if (move_value->move_start_hotkey != OBS_INVALID_HOTKEY_ID)
obs_hotkey_unregister(move_value->move_start_hotkey);
bfree(move_value->format);
bfree(move_value->text_from);
bfree(move_value->text_to);
bfree(move_value->filter_name);
bfree(move_value->setting_filter_name);
bfree(move_value->setting_name);
bfree(move_value->simultaneous_move_name);
bfree(move_value->next_move_name);
obs_data_array_release(move_value->settings);
da_free(move_value->filters_done);
bfree(move_value);
}
void prop_list_add_easings(obs_property_t *p);
void prop_list_add_easing_functions(obs_property_t *p);
void prop_list_add_filter(obs_source_t *parent, obs_source_t *child, void *data)
{
UNUSED_PARAMETER(parent);
obs_property_t *p = data;
const char *name = obs_source_get_name(child);
obs_property_list_add_string(p, name, name);
}
void prop_list_add_move_value_filter(obs_source_t *parent, obs_source_t *child,
void *data)
{
UNUSED_PARAMETER(parent);
if (strcmp(obs_source_get_unversioned_id(child),
MOVE_VALUE_FILTER_ID) != 0 &&
strcmp(obs_source_get_unversioned_id(child),
MOVE_AUDIO_VALUE_FILTER_ID) != 0)
return;
obs_property_t *p = data;
const char *name = obs_source_get_name(child);
obs_property_list_add_string(p, name, name);
}
bool move_value_get_value(obs_properties_t *props, obs_property_t *property,
void *data)
{
UNUSED_PARAMETER(props);
UNUSED_PARAMETER(property);
struct move_value_info *move_value = data;
bool settings_changed = false;
obs_source_t *source =
move_value->filter ? move_value->filter
: obs_filter_get_parent(move_value->source);
if (source == NULL || source == move_value->source)
return settings_changed;
obs_data_t *settings = obs_source_get_settings(move_value->source);
if (strcmp(move_value->setting_name, VOLUME_SETTING) == 0) {
const double value =
(double)obs_source_get_volume(source) * 100.0;
obs_data_set_double(settings, S_SETTING_FLOAT, value);
obs_data_set_double(settings, S_SETTING_FLOAT_MIN, value);
obs_data_set_double(settings, S_SETTING_FLOAT_MAX, value);
obs_data_release(settings);
return true;
}
obs_properties_t *sps = obs_source_properties(source);
obs_property_t *sp = obs_properties_get(sps, move_value->setting_name);
obs_data_t *ss = obs_source_get_settings(source);
const enum obs_property_type prop_type = obs_property_get_type(sp);
if (prop_type == OBS_PROPERTY_INT) {
const long long value =
obs_data_get_int(ss, move_value->setting_name);
obs_data_set_int(settings, S_SETTING_INT, value);
obs_data_set_int(settings, S_SETTING_INT_MIN, value);
obs_data_set_int(settings, S_SETTING_INT_MAX, value);
settings_changed = true;
} else if (prop_type == OBS_PROPERTY_FLOAT) {
const double value =
obs_data_get_double(ss, move_value->setting_name);
obs_data_set_double(settings, S_SETTING_FLOAT, value);
obs_data_set_double(settings, S_SETTING_FLOAT_MIN, value);
obs_data_set_double(settings, S_SETTING_FLOAT_MAX, value);
settings_changed = true;
} else if (prop_type == OBS_PROPERTY_COLOR ||
prop_type == OBS_PROPERTY_COLOR_ALPHA) {
const long long color =
obs_data_get_int(ss, move_value->setting_name);
obs_data_set_int(settings, S_SETTING_COLOR, color);
obs_data_set_int(settings, S_SETTING_COLOR_MIN, color);
obs_data_set_int(settings, S_SETTING_COLOR_MAX, color);
settings_changed = true;
} else if (prop_type == OBS_PROPERTY_TEXT) {
const char *text =
obs_data_get_string(ss, move_value->setting_name);
if (move_value->move_value_type == MOVE_VALUE_TYPE_TYPING) {
obs_data_set_string(settings, S_SETTING_TEXT, text);
} else {
const double value = parse_text(move_value->format_type,
move_value->format,
text);
obs_data_set_double(settings, S_SETTING_FLOAT, value);
obs_data_set_double(settings, S_SETTING_FLOAT_MIN,
value);
obs_data_set_double(settings, S_SETTING_FLOAT_MAX,
value);
}
settings_changed = true;
}
obs_data_release(settings);
obs_properties_destroy(sps);
return settings_changed;
}
bool move_value_get_values(obs_properties_t *props, obs_property_t *property,
void *data)
{
struct move_value_info *move_value = data;
obs_source_t *source =
move_value->filter ? move_value->filter
: obs_filter_get_parent(move_value->source);
if (source == NULL || source == move_value->source)
return false;
obs_data_t *settings = obs_source_get_settings(move_value->source);
obs_data_t *ss = obs_source_get_settings(source);
const size_t count = obs_data_array_count(move_value->settings);
for (size_t i = 0; i < count; i++) {
obs_data_t *item = obs_data_array_item(move_value->settings, i);
const char *name = obs_data_get_string(item, S_SETTING_NAME);
const long long value_type =
obs_data_get_int(item, S_VALUE_TYPE);
if (value_type == MOVE_VALUE_INT) {
const long long value = obs_data_get_int(ss, name);
obs_data_set_int(settings, name, value);
} else if (value_type == MOVE_VALUE_FLOAT) {
const double value = obs_data_get_double(ss, name);
obs_data_set_double(settings, name, value);
} else if (value_type == MOVE_VALUE_COLOR) {
const long long color = obs_data_get_int(ss, name);
obs_data_set_int(settings, name, color);
} else if (value_type == MOVE_VALUE_TEXT) {
const char *text = obs_data_get_string(ss, name);
const double value = parse_text(move_value->format_type,
move_value->format,
text);
obs_data_set_double(settings, name, value);
}
}
if (count > 0) {
obs_properties_t *sps = obs_source_properties(source);
load_properties(sps, move_value->settings, settings, ss);
obs_properties_destroy(sps);
}
obs_data_release(ss);
obs_data_release(settings);
return count > 0;
}
void copy_properties(obs_properties_t *props_from, obs_properties_t *props_to,
obs_data_t *data_from, obs_data_t *data_to,
obs_property_t *setting_list)
{
obs_property_t *prop_from = obs_properties_first(props_from);
for (; prop_from != NULL; obs_property_next(&prop_from)) {
const char *name = obs_property_name(prop_from);
const char *description = obs_property_description(prop_from);
if (!obs_property_visible(prop_from))
continue;
obs_property_t *prop_to = NULL;
const enum obs_property_type prop_type =
obs_property_get_type(prop_from);
if (prop_type == OBS_PROPERTY_GROUP) {
obs_properties_t *group_to = obs_properties_create();
copy_properties(obs_property_group_content(prop_from),
group_to, data_from, data_to,
setting_list);
if (obs_properties_first(group_to) == NULL) {
obs_properties_destroy(group_to);
} else {
prop_to = obs_properties_add_group(
props_to, name, description,
obs_property_group_type(prop_from),
group_to);
}
} else if (prop_type == OBS_PROPERTY_INT) {
obs_property_list_add_string(setting_list, description,
name);
if (obs_property_int_type(prop_from) ==
OBS_NUMBER_SLIDER) {
prop_to = obs_properties_add_int_slider(
props_to, name, description,
obs_property_int_min(prop_from),
obs_property_int_max(prop_from),
obs_property_int_step(prop_from));
} else {
prop_to = obs_properties_add_int(
props_to, name, description,
obs_property_int_min(prop_from),
obs_property_int_max(prop_from),
obs_property_int_step(prop_from));
}
if (obs_data_has_default_value(data_from, name))
obs_data_set_default_int(
data_to, name,
obs_data_get_default_int(data_from,
name));
obs_property_int_set_suffix(
prop_to, obs_property_int_suffix(prop_from));
} else if (prop_type == OBS_PROPERTY_FLOAT) {
obs_property_list_add_string(setting_list, description,
name);
if (obs_property_float_type(prop_from) ==
OBS_NUMBER_SLIDER) {
prop_to = obs_properties_add_float_slider(
props_to, name, description,
obs_property_float_min(prop_from),
obs_property_float_max(prop_from),
obs_property_float_step(prop_from));
} else {
prop_to = obs_properties_add_float(
props_to, name, description,
obs_property_float_min(prop_from),
obs_property_float_max(prop_from),
obs_property_float_step(prop_from));
}
if (obs_data_has_default_value(data_from, name))
obs_data_set_default_double(
data_to, name,
obs_data_get_default_double(data_from,
name));
obs_property_float_set_suffix(
prop_to, obs_property_float_suffix(prop_from));
} else if (prop_type == OBS_PROPERTY_COLOR ||
prop_type == OBS_PROPERTY_COLOR_ALPHA) {
obs_property_list_add_string(setting_list, description,
name);
prop_to = obs_properties_add_color(props_to, name,
description);
if (obs_data_has_default_value(data_from, name))
obs_data_set_default_int(
data_to, name,
obs_data_get_default_int(data_from,
name));
} else if (prop_type == OBS_PROPERTY_TEXT) {
obs_property_list_add_string(setting_list, description,
name);
}
}
}
bool move_value_filter_changed(void *data, obs_properties_t *props,
obs_property_t *property, obs_data_t *settings)
{
UNUSED_PARAMETER(property);
struct move_value_info *move_value = data;
bool refresh = false;
obs_source_t *parent = obs_filter_get_parent(move_value->source);
const char *filter_name = obs_data_get_string(settings, S_FILTER);
if (!move_value->setting_filter_name ||
strcmp(move_value->setting_filter_name, filter_name) != 0 ||
(!move_value->filter && strlen(filter_name))) {
bfree(move_value->setting_filter_name);
move_value->setting_filter_name = bstrdup(filter_name);
obs_source_release(move_value->filter);
move_value->filter =
obs_source_get_filter_by_name(parent, filter_name);
}
refresh = true;
obs_property_t *p = obs_properties_get(props, S_SETTING_NAME);
obs_property_list_clear(p);
obs_property_list_add_string(p, obs_module_text("Setting.None"), "");
obs_property_t *ps = obs_properties_get(props, S_SETTINGS);
obs_properties_t *g = obs_property_group_content(ps);
obs_property_t *i = obs_properties_first(g);
while (i != NULL) {
const char *name = obs_property_name(i);
obs_property_next(&i);
if (strcmp(name, "values_get") == 0)
continue;
obs_properties_remove_by_name(g, name);
}
obs_source_t *source = move_value->filter ? move_value->filter : parent;
obs_data_t *s = obs_source_get_settings(source);
if (!s || source == move_value->source)
return refresh;
if (obs_source_get_type(source) == OBS_SOURCE_TYPE_INPUT &&
(obs_source_get_output_flags(source) & OBS_SOURCE_AUDIO))
obs_property_list_add_string(
p, obs_module_text("Setting.Volume"), VOLUME_SETTING);
obs_properties_t *sps = obs_source_properties(source);
copy_properties(sps, g, s, settings, p);
obs_properties_destroy(sps);
obs_data_release(s);
return refresh;
}
bool move_value_format_type_changed(void *data, obs_properties_t *props,
obs_property_t *property,
obs_data_t *settings)
{
obs_property_t *prop_format =
obs_properties_get(props, S_SETTING_FORMAT);
obs_property_t *prop_decimals =
obs_properties_get(props, S_SETTING_DECIMALS);
obs_property_set_visible(prop_format, false);
obs_property_set_visible(prop_decimals, false);
if (obs_data_get_int(settings, S_VALUE_TYPE) == MOVE_VALUE_TEXT &&
obs_data_get_int(settings, S_MOVE_VALUE_TYPE) !=
MOVE_VALUE_TYPE_TYPING) {
const long long format_type =
obs_data_get_int(settings, S_SETTING_FORMAT_TYPE);
if (format_type == MOVE_VALUE_FORMAT_DECIMALS) {
obs_property_set_visible(prop_decimals, true);
} else {
obs_property_set_visible(prop_format, true);
}
}
return true;
}
bool move_value_setting_changed(void *data, obs_properties_t *props,
obs_property_t *property, obs_data_t *settings)
{
UNUSED_PARAMETER(property);
struct move_value_info *move_value = data;
bool refresh = false;
const char *setting_name =
obs_data_get_string(settings, S_SETTING_NAME);
if (!move_value->setting_name ||
strcmp(move_value->setting_name, setting_name) != 0) {
refresh = true;
bfree(move_value->setting_name);
move_value->setting_name = bstrdup(setting_name);
}
obs_source_t *source =
move_value->filter ? move_value->filter
: obs_filter_get_parent(move_value->source);
if (source == move_value->source)
return refresh;
obs_property_t *prop_int = obs_properties_get(props, S_SETTING_INT);
obs_property_t *prop_int_min =
obs_properties_get(props, S_SETTING_INT_MIN);
obs_property_t *prop_int_max =
obs_properties_get(props, S_SETTING_INT_MAX);
obs_property_t *prop_float = obs_properties_get(props, S_SETTING_FLOAT);
obs_property_t *prop_float_min =
obs_properties_get(props, S_SETTING_FLOAT_MIN);
obs_property_t *prop_float_max =
obs_properties_get(props, S_SETTING_FLOAT_MAX);
obs_property_t *prop_format_type =
obs_properties_get(props, S_SETTING_FORMAT_TYPE);
obs_property_t *prop_color = obs_properties_get(props, S_SETTING_COLOR);
obs_property_t *prop_color_min =
obs_properties_get(props, S_SETTING_COLOR_MIN);
obs_property_t *prop_color_max =
obs_properties_get(props, S_SETTING_COLOR_MAX);
obs_property_t *prop_text = obs_properties_get(props, S_SETTING_TEXT);
obs_property_set_visible(prop_int, false);
obs_property_set_visible(prop_int_min, false);
obs_property_set_visible(prop_int_max, false);
obs_property_set_visible(prop_float, false);
obs_property_set_visible(prop_float_min, false);
obs_property_set_visible(prop_float_max, false);
obs_property_set_visible(prop_format_type, false);
obs_property_set_visible(prop_color, false);
obs_property_set_visible(prop_color_min, false);
obs_property_set_visible(prop_color_max, false);
obs_property_set_visible(prop_text, false);
const long long move_value_type =
obs_data_get_int(settings, S_MOVE_VALUE_TYPE);
if (strcmp(move_value->setting_name, VOLUME_SETTING) == 0) {
if (move_value_type == MOVE_VALUE_TYPE_SINGLE_SETTING) {
obs_property_set_visible(prop_float, true);
obs_property_float_set_limits(prop_float, VOLUME_MIN,
VOLUME_MAX, VOLUME_STEP);
obs_property_float_set_suffix(prop_float, "%");
if (refresh)
obs_data_set_double(
settings, S_SETTING_FLOAT,
obs_source_get_volume(source) * 100.0);
} else if (move_value_type == MOVE_VALUE_TYPE_SETTING_ADD) {
obs_property_set_visible(prop_float, true);
obs_property_float_set_limits(prop_float, -VOLUME_MAX,
VOLUME_MAX, VOLUME_STEP);
obs_property_float_set_suffix(prop_float, "%");
} else if (move_value_type == MOVE_VALUE_TYPE_RANDOM) {
obs_property_set_visible(prop_float_min, true);
obs_property_set_visible(prop_float_max, true);
obs_property_float_set_limits(prop_float_min,
VOLUME_MIN, VOLUME_MAX,
VOLUME_STEP);
obs_property_float_set_limits(prop_float_max,
VOLUME_MIN, VOLUME_MAX,
VOLUME_STEP);
obs_property_float_set_suffix(prop_float_min, "%");
obs_property_float_set_suffix(prop_float_max, "%");
if (refresh) {
obs_data_set_double(
settings, S_SETTING_FLOAT_MIN,
obs_source_get_volume(source) * 100.0);
obs_data_set_double(
settings, S_SETTING_FLOAT_MAX,
obs_source_get_volume(source) * 100.0);
}
}
obs_data_set_int(settings, S_VALUE_TYPE, MOVE_VALUE_FLOAT);
return true;
}
obs_data_t *ss = obs_source_get_settings(source);
obs_properties_t *sps = obs_source_properties(source);
obs_property_t *sp = obs_properties_get(sps, setting_name);
const enum obs_property_type prop_type = obs_property_get_type(sp);
if (prop_type == OBS_PROPERTY_INT) {
if (move_value_type == MOVE_VALUE_TYPE_SINGLE_SETTING) {
obs_property_set_visible(prop_int, true);
obs_property_int_set_limits(prop_int,
obs_property_int_min(sp),
obs_property_int_max(sp),
obs_property_int_step(sp));
obs_property_int_set_suffix(
prop_int, obs_property_int_suffix(sp));
if (refresh)
obs_data_set_int(
settings, S_SETTING_INT,
obs_data_get_int(ss, setting_name));
} else if (move_value_type == MOVE_VALUE_TYPE_SETTING_ADD) {
obs_property_set_visible(prop_int, true);
obs_property_int_set_limits(prop_int, -1000, 1000,
obs_property_int_step(sp));
obs_property_int_set_suffix(
prop_int, obs_property_int_suffix(sp));
} else if (move_value_type == MOVE_VALUE_TYPE_RANDOM) {
obs_property_set_visible(prop_int_min, true);
obs_property_set_visible(prop_int_max, true);
obs_property_int_set_limits(prop_int_min,
obs_property_int_min(sp),
obs_property_int_max(sp),
obs_property_int_step(sp));
obs_property_int_set_limits(prop_int_max,
obs_property_int_min(sp),
obs_property_int_max(sp),
obs_property_int_step(sp));
obs_property_int_set_suffix(
prop_int_min, obs_property_int_suffix(sp));
obs_property_int_set_suffix(
prop_int_max, obs_property_int_suffix(sp));
if (refresh) {
obs_data_set_int(
settings, S_SETTING_INT_MIN,
obs_data_get_int(ss, setting_name));
obs_data_set_int(
settings, S_SETTING_INT_MAX,
obs_data_get_int(ss, setting_name));
}
}
obs_data_set_int(settings, S_VALUE_TYPE, MOVE_VALUE_INT);
} else if (prop_type == OBS_PROPERTY_FLOAT) {
if (move_value_type == MOVE_VALUE_TYPE_SINGLE_SETTING) {
obs_property_set_visible(prop_float, true);
obs_property_float_set_limits(
prop_float, obs_property_float_min(sp),
obs_property_float_max(sp),
obs_property_float_step(sp));
obs_property_float_set_suffix(
prop_float, obs_property_float_suffix(sp));
if (refresh)
obs_data_set_double(
settings, S_SETTING_FLOAT,
obs_data_get_double(ss, setting_name));
} else if (move_value_type == MOVE_VALUE_TYPE_SETTING_ADD) {
obs_property_set_visible(prop_float, true);
obs_property_float_set_limits(
prop_float, -1000.0, 1000.0,
obs_property_float_step(sp));
obs_property_float_set_suffix(
prop_float, obs_property_float_suffix(sp));
} else if (move_value_type == MOVE_VALUE_TYPE_RANDOM) {
obs_property_set_visible(prop_float_min, true);
obs_property_set_visible(prop_float_max, true);
obs_property_float_set_limits(
prop_float_min, obs_property_float_min(sp),
obs_property_float_max(sp),
obs_property_float_step(sp));
obs_property_float_set_limits(
prop_float_max, obs_property_float_min(sp),
obs_property_float_max(sp),
obs_property_float_step(sp));
obs_property_float_set_suffix(
prop_float_min, obs_property_float_suffix(sp));
obs_property_float_set_suffix(
prop_float_max, obs_property_float_suffix(sp));
if (refresh) {
obs_data_set_double(
settings, S_SETTING_FLOAT_MIN,
obs_data_get_double(ss, setting_name));
obs_data_set_double(
settings, S_SETTING_FLOAT_MAX,
obs_data_get_double(ss, setting_name));
}
}
obs_data_set_int(settings, S_VALUE_TYPE, MOVE_VALUE_FLOAT);
} else if (prop_type == OBS_PROPERTY_COLOR ||
prop_type == OBS_PROPERTY_COLOR_ALPHA) {
if (move_value_type == MOVE_VALUE_TYPE_SINGLE_SETTING) {
obs_property_set_visible(prop_color, true);
if (refresh)
obs_data_set_int(
settings, S_SETTING_COLOR,
obs_data_get_int(ss, setting_name));
} else if (move_value_type == MOVE_VALUE_TYPE_SETTING_ADD) {
obs_property_set_visible(prop_color, true);
} else if (move_value_type == MOVE_VALUE_TYPE_RANDOM) {
obs_property_set_visible(prop_color_min, true);
obs_property_set_visible(prop_color_max, true);
if (refresh) {
obs_data_set_int(
settings, S_SETTING_COLOR_MIN,
obs_data_get_int(ss, setting_name));
obs_data_set_int(
settings, S_SETTING_COLOR_MAX,
obs_data_get_int(ss, setting_name));
}
}
obs_data_set_int(settings, S_VALUE_TYPE, MOVE_VALUE_COLOR);
} else if (prop_type == OBS_PROPERTY_TEXT) {
if (move_value_type == MOVE_VALUE_TYPE_SINGLE_SETTING) {
obs_property_set_visible(prop_format_type, true);
obs_property_set_visible(prop_float, true);
obs_property_float_set_limits(prop_float, -DBL_MAX,
DBL_MAX, 1.0);
obs_property_float_set_suffix(prop_float, NULL);
if (refresh) {
const char *text_val =
obs_data_get_string(ss, setting_name);
const double val = strtod(text_val, NULL);
obs_data_set_double(settings, S_SETTING_FLOAT,
val);
}
} else if (move_value_type == MOVE_VALUE_TYPE_SETTING_ADD) {
obs_property_set_visible(prop_format_type, true);
obs_property_set_visible(prop_float, true);
obs_property_float_set_limits(prop_float, -DBL_MAX,
DBL_MAX, 1.0);
obs_property_float_set_suffix(prop_float, NULL);
} else if (move_value_type == MOVE_VALUE_TYPE_RANDOM) {
obs_property_set_visible(prop_format_type, true);
obs_property_set_visible(prop_float_min, true);
obs_property_set_visible(prop_float_max, true);
obs_property_float_set_limits(prop_float_min, -DBL_MAX,
DBL_MAX, 1.0);
obs_property_float_set_limits(prop_float_max, -DBL_MAX,
DBL_MAX, 1.0);
obs_property_float_set_suffix(prop_float_min, NULL);
obs_property_float_set_suffix(prop_float_max, NULL);
if (refresh) {
const char *text_val =
obs_data_get_string(ss, setting_name);
const double val = strtod(text_val, NULL);
obs_data_set_double(settings,
S_SETTING_FLOAT_MIN, val);
obs_data_set_double(settings,
S_SETTING_FLOAT_MAX, val);
}
} else if (move_value_type == MOVE_VALUE_TYPE_TYPING) {
obs_property_set_visible(prop_text, true);
}
obs_data_set_int(settings, S_VALUE_TYPE, MOVE_VALUE_TEXT);
} else {
obs_data_set_int(settings, S_VALUE_TYPE, MOVE_VALUE_UNKNOWN);
}
obs_data_release(ss);
obs_properties_destroy(sps);
move_value_format_type_changed(data, props, property, settings);
return true;
}
bool move_value_type_changed(void *data, obs_properties_t *props,
obs_property_t *property, obs_data_t *settings)
{
bool refresh = false;
const long long move_value_type =
obs_data_get_int(settings, S_MOVE_VALUE_TYPE);
obs_property_t *p = obs_properties_get(props, S_SETTING_VALUE);
if (obs_property_visible(p) !=
(move_value_type != MOVE_VALUE_TYPE_SETTINGS)) {
obs_property_set_visible(p, move_value_type !=
MOVE_VALUE_TYPE_SETTINGS);
refresh = true;
}
p = obs_properties_get(props, S_SETTINGS);
if (obs_property_visible(p) !=
(move_value_type == MOVE_VALUE_TYPE_SETTINGS)) {
obs_property_set_visible(p, move_value_type ==
MOVE_VALUE_TYPE_SETTINGS);
refresh = true;
}
return move_value_setting_changed(data, props, property, settings) ||
refresh;
}
bool move_value_decimals_changed(void *data, obs_properties_t *props,
obs_property_t *property, obs_data_t *settings)
{
const int decimals =
(int)obs_data_get_int(settings, S_SETTING_DECIMALS);
const double step = pow(10.0, -1.0 * (double)decimals);
obs_property_t *prop_float = obs_properties_get(props, S_SETTING_FLOAT);
obs_property_t *prop_float_min =
obs_properties_get(props, S_SETTING_FLOAT_MIN);
obs_property_t *prop_float_max =
obs_properties_get(props, S_SETTING_FLOAT_MAX);
obs_property_float_set_limits(prop_float, -DBL_MAX, DBL_MAX, step);
obs_property_float_set_limits(prop_float_min, -DBL_MAX, DBL_MAX, step);
obs_property_float_set_limits(prop_float_max, -DBL_MAX, DBL_MAX, step);
return true;
}
static obs_properties_t *move_value_properties(void *data)
{
obs_properties_t *ppts = obs_properties_create();
const struct move_value_info *move_value = data;
obs_source_t *parent = obs_filter_get_parent(move_value->source);
obs_property_t *p = obs_properties_add_list(ppts, S_FILTER,
obs_module_text("Filter"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, obs_module_text("Filter.None"), "");
obs_source_enum_filters(parent, prop_list_add_filter, p);
obs_property_set_modified_callback2(p, move_value_filter_changed, data);
p = obs_properties_add_list(ppts, S_MOVE_VALUE_TYPE,
obs_module_text("MoveValueType"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(
p, obs_module_text("MoveValueType.SingleSetting"),
MOVE_VALUE_TYPE_SINGLE_SETTING);
obs_property_list_add_int(p, obs_module_text("MoveValueType.Settings"),
MOVE_VALUE_TYPE_SETTINGS);
obs_property_list_add_int(p, obs_module_text("MoveValueType.Random"),
MOVE_VALUE_TYPE_RANDOM);
obs_property_list_add_int(p,
obs_module_text("MoveValueType.SettingAdd"),
MOVE_VALUE_TYPE_SETTING_ADD);
obs_property_list_add_int(p, obs_module_text("MoveValueType.Type"),
MOVE_VALUE_TYPE_TYPING);
obs_property_set_modified_callback2(p, move_value_type_changed, data);
obs_properties_t *setting_value = obs_properties_create();
p = obs_properties_add_list(setting_value, S_SETTING_NAME,
obs_module_text("Setting"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, obs_module_text("Setting.None"), "");
obs_property_set_modified_callback2(p, move_value_setting_changed,
data);
p = obs_properties_add_list(setting_value, S_SETTING_FORMAT_TYPE,
obs_module_text("FormatType"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("FormatType.Decimals"),
MOVE_VALUE_FORMAT_DECIMALS);
obs_property_list_add_int(p, obs_module_text("FormatType.Float"),
MOVE_VALUE_FORMAT_FLOAT);
obs_property_list_add_int(p, obs_module_text("FormatType.Time"),
MOVE_VALUE_FORMAT_TIME);
obs_property_set_visible(p, false);
obs_property_set_modified_callback2(p, move_value_format_type_changed,
data);
p = obs_properties_add_text(setting_value, S_SETTING_FORMAT,
obs_module_text("Format"),
OBS_TEXT_DEFAULT);
obs_property_set_visible(p, false);
p = obs_properties_add_int(setting_value, S_SETTING_DECIMALS,
obs_module_text("Decimals"), -10, 10, 1);
obs_property_set_visible(p, false);
obs_property_set_modified_callback2(p, move_value_decimals_changed,
data);
p = obs_properties_add_int(setting_value, S_SETTING_INT,
obs_module_text("Value"), 0, 0, 0);
obs_property_set_visible(p, false);
p = obs_properties_add_int(setting_value, S_SETTING_INT_MIN,
obs_module_text("MinValue"), 0, 0, 0);
obs_property_set_visible(p, false);
p = obs_properties_add_int(setting_value, S_SETTING_INT_MAX,
obs_module_text("MaxValue"), 0, 0, 0);
obs_property_set_visible(p, false);
p = obs_properties_add_float(setting_value, S_SETTING_FLOAT,
obs_module_text("Value"), 0, 0, 0);
obs_property_set_visible(p, false);
p = obs_properties_add_float(setting_value, S_SETTING_FLOAT_MIN,
obs_module_text("MinValue"), 0, 0, 0);
obs_property_set_visible(p, false);
p = obs_properties_add_float(setting_value, S_SETTING_FLOAT_MAX,
obs_module_text("MaxValue"), 0, 0, 0);
obs_property_set_visible(p, false);
p = obs_properties_add_color(setting_value, S_SETTING_COLOR,
obs_module_text("Value"));
obs_property_set_visible(p, false);
p = obs_properties_add_color(setting_value, S_SETTING_COLOR_MIN,
obs_module_text("MinValue"));
obs_property_set_visible(p, false);
p = obs_properties_add_color(setting_value, S_SETTING_COLOR_MAX,
obs_module_text("MaxValue"));
obs_property_set_visible(p, false);
p = obs_properties_add_text(setting_value, S_SETTING_TEXT,
obs_module_text("Text"),
OBS_TEXT_MULTILINE);
obs_property_set_visible(p, false);
obs_properties_add_button(setting_value, "value_get",
obs_module_text("GetValue"),
move_value_get_value);
obs_properties_add_group(ppts, S_SETTING_VALUE,
obs_module_text("Setting"), OBS_GROUP_NORMAL,
setting_value);
obs_properties_t *settings = obs_properties_create();
obs_properties_add_button(settings, "values_get",
obs_module_text("GetValues"),
move_value_get_values);
obs_properties_add_group(ppts, S_SETTINGS, obs_module_text("Settings"),
OBS_GROUP_NORMAL, settings);
p = obs_properties_add_int(ppts, S_START_DELAY,
obs_module_text("StartDelay"), 0, 10000000,
100);
obs_property_int_set_suffix(p, "ms");
obs_properties_t *duration = obs_properties_create();
p = obs_properties_add_int(duration, S_DURATION, "", 10, 10000000, 100);
obs_property_int_set_suffix(p, "ms");
p = obs_properties_add_group(ppts, S_CUSTOM_DURATION,
obs_module_text("CustomDuration"),
OBS_GROUP_CHECKABLE, duration);
p = obs_properties_add_int(ppts, S_END_DELAY,
obs_module_text("EndDelay"), 0, 10000000,
100);
obs_property_int_set_suffix(p, "ms");
p = obs_properties_add_list(ppts, S_EASING_MATCH,
obs_module_text("Easing"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easings(p);
p = obs_properties_add_list(ppts, S_EASING_FUNCTION_MATCH,
obs_module_text("EasingFunction"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
prop_list_add_easing_functions(p);
p = obs_properties_add_bool(ppts, S_ENABLED_MATCH_MOVING,
obs_module_text("EnabledMatchMoving"));
p = obs_properties_add_list(ppts, S_START_TRIGGER,
obs_module_text("StartTrigger"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("StartTrigger.None"),
START_TRIGGER_NONE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Activate"),
START_TRIGGER_ACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Deactivate"),
START_TRIGGER_DEACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Show"),
START_TRIGGER_SHOW);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Hide"),
START_TRIGGER_HIDE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Enable"),
START_TRIGGER_ENABLE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Load"),
START_TRIGGER_LOAD);
p = obs_properties_add_list(ppts, S_STOP_TRIGGER,
obs_module_text("StopTrigger"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("StopTrigger.None"),
START_TRIGGER_NONE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Activate"),
START_TRIGGER_ACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Deactivate"),
START_TRIGGER_DEACTIVATE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Show"),
START_TRIGGER_SHOW);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Hide"),
START_TRIGGER_HIDE);
obs_property_list_add_int(p, obs_module_text("StartTrigger.Enable"),
START_TRIGGER_ENABLE);
p = obs_properties_add_list(ppts, S_SIMULTANEOUS_MOVE,
obs_module_text("SimultaneousMove"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(
p, obs_module_text("SimultaneousMove.None"), "");
obs_source_enum_filters(parent, prop_list_add_move_value_filter, p);
p = obs_properties_add_list(ppts, S_NEXT_MOVE,
obs_module_text("NextMove"),
OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, obs_module_text("NextMove.None"), "");
obs_property_list_add_string(p, obs_module_text("NextMove.Reverse"),
NEXT_MOVE_REVERSE);
obs_source_enum_filters(parent, prop_list_add_move_value_filter, p);
p = obs_properties_add_list(ppts, S_NEXT_MOVE_ON,
obs_module_text("NextMoveOn"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, obs_module_text("NextMoveOn.End"),
NEXT_MOVE_ON_END);
obs_property_list_add_int(p, obs_module_text("NextMoveOn.Hotkey"),
NEXT_MOVE_ON_HOTKEY);
obs_properties_add_button(ppts, "move_value_start",
obs_module_text("Start"),
move_value_start_button);
return ppts;
}
void move_value_defaults(obs_data_t *settings)
{
obs_data_set_default_bool(settings, S_SINGLE_SETTING, true);
obs_data_set_default_bool(settings, S_CUSTOM_DURATION, true);
obs_data_set_default_int(settings, S_DURATION, 300);
obs_data_set_default_int(settings, S_EASING_MATCH, EASE_IN_OUT);
obs_data_set_default_int(settings, S_EASING_FUNCTION_MATCH,
EASING_CUBIC);
obs_data_set_default_bool(settings, S_ENABLED_MATCH_MOVING, true);
}
void move_value_video_render(void *data, gs_effect_t *effect)
{
UNUSED_PARAMETER(effect);
struct move_value_info *filter = data;
obs_source_skip_video_filter(filter->source);
}
static const char *move_value_get_name(void *type_data)
{
UNUSED_PARAMETER(type_data);
return obs_module_text("MoveValueFilter");
}
float get_eased(float f, long long easing, long long easing_function);
void vec2_bezier(struct vec2 *dst, struct vec2 *begin, struct vec2 *control,
struct vec2 *end, const float t);
void move_value_stop(struct move_value_info *move_value)
{
move_value->moving = false;
if (move_value->enabled_match_moving &&
obs_source_enabled(move_value->source)) {
obs_source_set_enabled(move_value->source, false);
}
}
void move_value_tick(void *data, float seconds)
{
struct move_value_info *move_value = data;
if (move_value->move_start_hotkey == OBS_INVALID_HOTKEY_ID &&
move_value->filter_name && strlen(move_value->filter_name)) {
obs_source_t *parent =
obs_filter_get_parent(move_value->source);
if (parent)
move_value->move_start_hotkey =
obs_hotkey_register_source(
parent, move_value->filter_name,
move_value->filter_name,
move_value_start_hotkey, data);
}
const bool enabled = obs_source_enabled(move_value->source);
if (move_value->enabled != enabled) {
if (enabled &&
(move_value->start_trigger == START_TRIGGER_ENABLE ||
(move_value->enabled_match_moving && !move_value->moving)))
move_value_start(move_value);
if (enabled && move_value->stop_trigger == START_TRIGGER_ENABLE)
move_value_stop(move_value);
move_value->enabled = enabled;
}
if (!move_value->moving || !enabled)
return;
if (!move_value->duration) {
move_value->moving = false;
return;
}
move_value->running_duration += seconds;
if (move_value->running_duration * 1000.0f <
(move_value->reverse ? move_value->end_delay
: move_value->start_delay)) {
if (move_value->reverse)
return;
obs_source_t *source =
move_value->filter
? move_value->filter
: obs_filter_get_parent(move_value->source);
if (strcmp(move_value->setting_name, VOLUME_SETTING) == 0) {
move_value->int_from =
obs_source_get_volume(source) * 100.0;
move_value->double_from =
obs_source_get_volume(source) * 100.0;
return;
}
obs_data_t *ss = obs_source_get_settings(source);
move_value->int_from =
obs_data_get_int(ss, move_value->setting_name);
move_value->double_from =
obs_data_get_double(ss, move_value->setting_name);
obs_data_release(ss);
return;
}
if (move_value->running_duration * 1000.0f >=
(float)(move_value->start_delay + move_value->duration +
move_value->end_delay)) {
move_value->moving = false;
}
float t = (move_value->running_duration * 1000.0f -
(float)(move_value->reverse ? move_value->end_delay
: move_value->start_delay)) /
(float)move_value->duration;
if (t >= 1.0f) {
t = 1.0f;
}
if (move_value->reverse) {
t = 1.0f - t;
}
t = get_eased(t, move_value->easing, move_value->easing_function);
obs_source_t *source =
move_value->filter ? move_value->filter
: obs_filter_get_parent(move_value->source);
if (!source)
return;
obs_data_t *ss = obs_source_get_settings(source);
bool update = true;
if (move_value->settings) {
const size_t count = obs_data_array_count(move_value->settings);
for (size_t i = 0; i < count; i++) {
obs_data_t *item =
obs_data_array_item(move_value->settings, i);
const char *setting_name =
obs_data_get_string(item, S_SETTING_NAME);
const long long value_type =
obs_data_get_int(item, S_VALUE_TYPE);
if (value_type == MOVE_VALUE_INT) {
const long long int_from =
obs_data_get_int(item, S_SETTING_FROM);
const long long int_to =
obs_data_get_int(item, S_SETTING_TO);
const long long value_int =
(long long)((1.0 - t) *
(double)int_from +
t * (double)int_to);
obs_data_set_int(ss, setting_name, value_int);
} else if (value_type == MOVE_VALUE_FLOAT) {
const double double_from = obs_data_get_double(
item, S_SETTING_FROM);
const double double_to =
obs_data_get_double(item, S_SETTING_TO);
const double value_double =
((1.0 - t) * double_from +
t * double_to);
obs_data_set_double(ss, setting_name,
value_double);
} else if (value_type == MOVE_VALUE_COLOR) {
struct vec4 color_from;
vec4_from_rgba(&color_from,
(uint32_t)obs_data_get_int(
item, S_SETTING_FROM));
gs_float3_srgb_nonlinear_to_linear(
color_from.ptr);
struct vec4 color_to;
vec4_from_rgba(&color_to,
(uint32_t)obs_data_get_int(
item, S_SETTING_TO));
gs_float3_srgb_nonlinear_to_linear(
color_to.ptr);
struct vec4 color;
color.w = (1.0f - t) * color_from.w +
t * color_to.w;
color.x = (1.0f - t) * color_from.x +
t * color_to.x;
color.y = (1.0f - t) * color_from.y +
t * color_to.y;
color.z = (1.0f - t) * color_from.z +
t * color_to.z;
gs_float3_srgb_linear_to_nonlinear(color.ptr);
const long long value_int =
vec4_to_rgba(&color);
obs_data_set_int(ss, setting_name, value_int);
}
}
} else if (move_value->value_type == MOVE_VALUE_INT) {
const long long value_int =
(long long)((1.0 - t) * (double)move_value->int_from +
t * (double)move_value->int_to);
if (strcmp(move_value->setting_name, VOLUME_SETTING) == 0) {
obs_source_set_volume(source,
(float)value_int / 100.0f);
update = false;
} else {
obs_data_set_int(ss, move_value->setting_name,
value_int);
}
} else if (move_value->value_type == MOVE_VALUE_FLOAT) {
const double value_double =
(1.0 - t) * move_value->double_from +
t * move_value->double_to;
if (strcmp(move_value->setting_name, VOLUME_SETTING) == 0) {
obs_source_set_volume(source, value_double / 100.0);
update = false;
} else {
obs_data_set_double(ss, move_value->setting_name,
value_double);
}
} else if (move_value->value_type == MOVE_VALUE_COLOR) {
struct vec4 color;
color.w = (1.0f - t) * move_value->color_from.w +
t * move_value->color_to.w;
color.x = (1.0f - t) * move_value->color_from.x +
t * move_value->color_to.x;
color.y = (1.0f - t) * move_value->color_from.y +
t * move_value->color_to.y;
color.z = (1.0f - t) * move_value->color_from.z +
t * move_value->color_to.z;
gs_float3_srgb_linear_to_nonlinear(color.ptr);
const long long value_int = vec4_to_rgba(&color);
obs_data_set_int(ss, move_value->setting_name, value_int);
} else if (move_value->value_type == MOVE_VALUE_TEXT &&
move_value->move_value_type == MOVE_VALUE_TYPE_TYPING) {
if (t * move_value->text_steps <= move_value->text_step &&
move_value->moving) {
obs_data_release(ss);
return;
}
move_value->text_step = t * move_value->text_steps;
char *text = NULL;
if (move_value->text_step <
move_value->text_from_len - move_value->text_same) {
text = bstrdup_n(move_value->text_from,
move_value->text_from_len -
move_value->text_step);
} else {
text = bstrdup_n(move_value->text_to,
move_value->text_same +
move_value->text_step -
(move_value->text_from_len -
move_value->text_same));
}
obs_data_set_string(ss, move_value->setting_name, text);
bfree(text);
} else if (move_value->value_type == MOVE_VALUE_TEXT) {
double value_double = (1.0 - t) * move_value->double_from +
t * move_value->double_to;
char text[TEXT_BUFFER_SIZE];
if (move_value->format_type == MOVE_VALUE_FORMAT_FLOAT) {
if (snprintf(text, TEXT_BUFFER_SIZE, move_value->format,
value_double) == 0)
text[0] = '\0';
} else if (move_value->format_type == MOVE_VALUE_FORMAT_TIME) {
long long t = value_double;
struct tm *tm_info = gmtime(&t);
if (strftime(text, TEXT_BUFFER_SIZE, move_value->format,
tm_info) == 0)
text[0] = '\0';
} else {
if (move_value->decimals >= 0) {
char format[10];
snprintf(format, 10, "%%.%df",
move_value->decimals);
snprintf(text, TEXT_BUFFER_SIZE, format,
value_double);
} else {
double factor = pow(
10,
-1.0 * (double)move_value->decimals);
value_double =
floor(value_double / factor) * factor;
snprintf(text, TEXT_BUFFER_SIZE, "%.0f",
value_double);
}
}
obs_data_set_string(ss, move_value->setting_name, text);
} else {
obs_data_item_t *item =
obs_data_item_byname(ss, move_value->setting_name);
const enum obs_data_number_type item_type =
obs_data_item_numtype(item);
if (item_type == OBS_DATA_NUM_INT) {
const long long value_int =
(long long)((1.0 -
t) * (double)move_value->int_from +
t * (double)move_value->int_to);
if (strcmp(move_value->setting_name, VOLUME_SETTING) ==
0) {
obs_source_set_volume(source, (float)value_int /
100.0f);
update = false;
} else {
obs_data_set_int(ss, move_value->setting_name,
value_int);
}
} else if (item_type == OBS_DATA_NUM_DOUBLE) {
const double value_double =
(1.0 - t) * move_value->double_from +
t * move_value->double_to;
if (strcmp(move_value->setting_name, VOLUME_SETTING) ==
0) {
obs_source_set_volume(source,
value_double / 100.0);
update = false;
} else {
obs_data_set_double(ss,
move_value->setting_name,
value_double);
}
}
obs_data_item_release(&item);
}
obs_data_release(ss);
if (update)
obs_source_update(source, NULL);
if (!move_value->moving) {
if (move_value->enabled_match_moving &&
(move_value->reverse || !move_value->next_move_name ||
strcmp(move_value->next_move_name, NEXT_MOVE_REVERSE) !=
0)) {
obs_source_set_enabled(move_value->source, false);
}
if (move_value->next_move_on == NEXT_MOVE_ON_END &&
move_value->next_move_name &&
strlen(move_value->next_move_name) &&
(!move_value->filter_name ||
strcmp(move_value->filter_name,
move_value->next_move_name) != 0)) {
if (strcmp(move_value->next_move_name,
NEXT_MOVE_REVERSE) == 0) {
move_value->reverse = !move_value->reverse;
if (move_value->reverse)
move_value_start(move_value);
} else {
obs_source_t *parent = obs_filter_get_parent(
move_value->source);
if (parent) {
obs_source_t *filter =
obs_source_get_filter_by_name(
parent,
move_value
->next_move_name);
if (filter &&
(strcmp(obs_source_get_unversioned_id(
filter),
MOVE_VALUE_FILTER_ID) ==
0 ||
strcmp(obs_source_get_unversioned_id(
filter),
MOVE_AUDIO_VALUE_FILTER_ID) ==
0)) {
struct move_value_info
*filter_data =
obs_obj_get_data(
filter);
move_value_start(filter_data);
}
obs_source_release(filter);
}
}
} else if (move_value->next_move_on == NEXT_MOVE_ON_HOTKEY &&
move_value->next_move_name &&
strcmp(move_value->next_move_name,
NEXT_MOVE_REVERSE) == 0) {
move_value->reverse = !move_value->reverse;
}
}
}
void move_value_activate(void *data)
{
struct move_value_info *move_value = data;
if (move_value->start_trigger == START_TRIGGER_ACTIVATE)
move_value_start(move_value);
if (move_value->stop_trigger == START_TRIGGER_ACTIVATE)
move_value_stop(move_value);
}
void move_value_deactivate(void *data)
{
struct move_value_info *move_value = data;
if (move_value->start_trigger == START_TRIGGER_DEACTIVATE)
move_value_start(move_value);
if (move_value->stop_trigger == START_TRIGGER_DEACTIVATE)
move_value_stop(move_value);
}
void move_value_show(void *data)
{
struct move_value_info *move_value = data;
if (move_value->start_trigger == START_TRIGGER_SHOW)
move_value_start(move_value);
if (move_value->stop_trigger == START_TRIGGER_SHOW)
move_value_stop(move_value);
}
void move_value_hide(void *data)
{
struct move_value_info *move_value = data;
if (move_value->start_trigger == START_TRIGGER_HIDE)
move_value_start(move_value);
if (move_value->stop_trigger == START_TRIGGER_HIDE)
move_value_stop(move_value);
}
struct obs_source_info move_value_filter = {
.id = MOVE_VALUE_FILTER_ID,
.type = OBS_SOURCE_TYPE_FILTER,
.output_flags = OBS_SOURCE_VIDEO,
.get_name = move_value_get_name,
.create = move_value_create,
.destroy = move_value_destroy,
.get_properties = move_value_properties,
.get_defaults = move_value_defaults,
.video_render = move_value_video_render,
.video_tick = move_value_tick,
.update = move_value_update,
.load = move_value_update,
.activate = move_value_activate,
.deactivate = move_value_deactivate,
.show = move_value_show,
.hide = move_value_hide,
};
struct obs_source_info move_audio_value_filter = {
.id = MOVE_AUDIO_VALUE_FILTER_ID,
.type = OBS_SOURCE_TYPE_FILTER,
.output_flags = OBS_SOURCE_AUDIO,
.get_name = move_value_get_name,
.create = move_value_create,
.destroy = move_value_destroy,
.get_properties = move_value_properties,
.get_defaults = move_value_defaults,
.video_render = move_value_video_render,
.video_tick = move_value_tick,
.update = move_value_update,
.load = move_value_update,
.activate = move_value_activate,
.deactivate = move_value_deactivate,
.show = move_value_show,
.hide = move_value_hide,
};
obs-move-transition-2.5.7/resource.rc.in 0000664 0000000 0000000 00000001653 14177464325 0020250 0 ustar 00root root 0000000 0000000 1 VERSIONINFO
FILEVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0
PRODUCTVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0
FILEFLAGSMASK 0x0L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x0L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Exeldro"
VALUE "FileDescription", "${PROJECT_FULL_NAME}"
VALUE "FileVersion", "${PROJECT_VERSION}"
VALUE "InternalName", "${PROJECT_NAME}"
VALUE "LegalCopyright", "(C) Exeldro"
VALUE "OriginalFilename", "${PROJECT_NAME}"
VALUE "ProductName", "${PROJECT_FULL_NAME}"
VALUE "ProductVersion", "${PROJECT_VERSION}"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
obs-move-transition-2.5.7/version.h.in 0000664 0000000 0000000 00000000340 14177464325 0017721 0 ustar 00root root 0000000 0000000 #pragma once
#define PROJECT_VERSION "${PROJECT_VERSION}"
#define PROJECT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}
#define PROJECT_VERSION_MINOR ${PROJECT_VERSION_MINOR}
#define PROJECT_VERSION_PATCH ${PROJECT_VERSION_PATCH}