Compare commits

...

34 Commits

Author SHA1 Message Date
Skyth 17d7b97dd6 Update version milestone to Beta 1. 2025-01-23 23:20:28 +03:00
Hyper 79b966586d version.cmake: don't show Git info or build type for Release 2025-01-23 20:00:48 +00:00
Hyper 686ef22c4d Implemented D-Pad support for the World Map, Gaia Colossus, Super Sonic and the Bobsleigh (#150)
* Implemented D-Pad support for World Map, Super Sonic (WIP) and Bobsleigh

* Implemented D-Pad support for Gaia Colossus and Super Sonic

* Improved touchpad sensitivity
2025-01-23 17:43:08 +00:00
Skyth (Asilkan) ca6b42e20e Interpolate barrels in Spagonia Night to fix softlock at high frame rates. (#153) 2025-01-23 19:41:15 +03:00
Skyth (Asilkan) 372c04fedd Implement ImGui additive rendering. (#152) 2025-01-23 16:25:31 +03:00
Skyth (Asilkan) b4de79720c Remove lzcnt instruction usage. (#151) 2025-01-23 15:18:19 +03:00
Hyper e10eb80e38 config: move Voice Language and Subtitles to System 2025-01-22 23:50:10 +00:00
Skyth (Asilkan) 4e149b0640 Implement proper post process scaling based on aspect ratio. (#148)
* Fix post process scaling for narrow aspect ratios.

* Compare width to pick gaussian blur quality for narrow aspect ratios.

* Account for world map disabling VERT+ for post process scaling.
2025-01-22 19:14:40 +03:00
Skyth (Asilkan) 85b5ebf9a7 Fix pause menu selection cast being visible while exiting options menu. (#139) 2025-01-22 19:13:53 +03:00
Skyth (Asilkan) bdbdd42bd0 Implement config option to toggle surround sound. (#144) 2025-01-22 18:51:51 +03:00
Skyth (Asilkan) fbc4bfa4d6 Fix save files not getting redirected without include directories. (#146) 2025-01-22 17:01:37 +03:00
Skyth 010c0a9fdf Use clamp texture addressing by default. 2025-01-22 15:49:30 +03:00
João Moura e6251bdbc3 Add GitHub Actions workflow files for Flatpak and Windows (#142)
Co-authored-by: SuperSonic16 <25761885+thesupersonic16@users.noreply.github.com>
Co-authored-by: Dario <dariosamo@gmail.com>
2025-01-22 14:29:02 +03:00
Skyth (Asilkan) fefd177b3a Replace indirect guest function calls with direct ones. (#141) 2025-01-20 18:18:20 +03:00
Skyth e8d36998a5 Fix gameplay UI scaling at narrow aspect ratios. 2025-01-20 02:08:43 +03:00
Skyth (Asilkan) 1efb4943b3 Replace uses of SWA with UnleashedRecomp & rebrand the recompilers. (#138) 2025-01-19 23:21:05 +03:00
Skyth (Asilkan) 312f913a92 Remove detail namespaces. (#137) 2025-01-19 21:09:47 +03:00
NextinHKRY d10f4bac3c Change Xbox Color Correction option to have 1 image (#136)
* Options: Color Correction with 1 thumbnail

* Update UnleashedRecompResources

* Update UnleashedRecompResources
2025-01-19 20:56:51 +03:00
Skyth (Asilkan) 535bca7d9f Move config implementations to a .cpp file. (#133) 2025-01-19 19:05:44 +03:00
Hyper 614106c868 input_patches: add missing hook functions 2025-01-19 15:58:02 +00:00
Hyper fde108178d CTitleStateIntro_patches: make g_quitMessageOpen not static 2025-01-19 15:42:05 +00:00
Hyper b56c0b8209 Implemented safer hooks for D-Pad movement (#129) 2025-01-19 15:01:11 +00:00
Hyper cdd801dcec Fix quit message not blocking advertise movie (#127) 2025-01-19 13:06:38 +00:00
Hyper e7919da1bd game_window: change window title to "Unleashed Recompiled" 2025-01-18 23:51:00 +00:00
Hyper 513a66657f xam: only print XamShowMessageBoxUI info on Win32 2025-01-18 22:51:49 +00:00
Hyper b9f0742ff9 CTitleStateIntro_patches: don't worry about it 2025-01-18 21:38:09 +00:00
Hyper 7c72146705 CTitleStateIntro_patches: fix save data validation hook 2025-01-18 21:34:20 +00:00
Skyth (Asilkan) 40a8bf557b Scale 2D coordinates to backbuffer resolution. (#124)
* Starting with backbuffer scaling refactor.

* CSD & primitive 2Ds refactored.

* More refactoring.

* Fix primitive 2D, and on screen 3D items.

* Fix right side offset scaling.

* Fix Inspire letterbox.

* Fix offset scaling in world map.

* Fix custom menus.

* Remove debugging code.
2025-01-18 23:56:47 +03:00
Hyper 1cf12fa97f installer_wizard: fix credits not fading out upon exit 2025-01-18 19:39:58 +00:00
Hyper aacb9d259c Added error message for corrupted save data, removed Win32 message box on XamShowMessageBoxUI (#122)
* xam: remove Win32 message box on XamShowMessageBoxUI

* CTitleStateIntro_patches: display error message on corrupted save data

TitleMenuRemoveContinueOnCorruptSaveMidAsmHook by @DeaTh-G

Co-Authored-By: DeaTh-G <55578911+DeaTh-G@users.noreply.github.com>

---------

Co-authored-by: DeaTh-G <55578911+DeaTh-G@users.noreply.github.com>
2025-01-18 22:32:37 +03:00
Skyth (Asilkan) c53df15578 Fix movie patches not accounting for half pixel properly. (#119) 2025-01-18 16:52:51 +03:00
SuperSonic16 53331d5760 Added scheme handler for Linux Flatpak (#118) 2025-01-18 15:09:37 +03:00
Skyth 0b675628ea Fix compilation error on Linux. 2025-01-18 13:42:59 +03:00
Skyth d3edee1945 Fix Vulkan dynamic depth bias validation error. 2025-01-18 12:58:02 +03:00
115 changed files with 2417 additions and 1432 deletions
+73
View File
@@ -0,0 +1,73 @@
name: Build Project (Flatpak)
on:
workflow_dispatch:
env:
FLATPAK_ID: io.github.hedge_dev.unleashedrecomp
FREEDESKTOP_VERSION: 23.08
LLVM_VERSION: 18
jobs:
build-flatpak:
name: Build Flatpak
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.ORG_TOKEN }}
- name: Checkout private repository
uses: actions/checkout@v4
with:
repository: ${{ secrets.ASSET_REPO }}
token: ${{ secrets.ASSET_REPO_TOKEN }}
path: flatpak/private
- name: Install dependencies
run: |-
sudo apt update
sudo apt install -y flatpak-builder ccache
- name: Cache ccache directory
uses: actions/cache@v4
with:
path: /tmp/ccache
key: ccache-${{ runner.os }}
- name: Prepare Flatpak
run: |
flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak --user install -y flathub org.freedesktop.Sdk//${{ env.FREEDESKTOP_VERSION }}
flatpak --user install -y flathub org.freedesktop.Sdk.Extension.llvm${{ env.LLVM_VERSION }}//${{ env.FREEDESKTOP_VERSION }}
- name: Build Flatpak
run: |
echo "commit_message=$(git log -1 --pretty=%s)" >> $GITHUB_ENV
export CCACHE_DIR=/tmp/ccache
flatpak-builder --user --force-clean --install-deps-from=flathub --repo=repo --install --ccache builddir ./flatpak/${{ env.FLATPAK_ID }}.json
flatpak build-bundle repo ./${{ env.FLATPAK_ID }}.flatpak ${{ env.FLATPAK_ID }} --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
# Uploads the built flatpak bundle to GitHub
# - name: Upload artifact
# uses: actions/upload-artifact@v4
# with:
# name: UnleashedRecomp-flatpak
# path: ./${{ env.FLATPAK_ID }}.flatpak
- name: Upload artifact to Discord
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
if: ${{ env.DISCORD_WEBHOOK != '' }}
uses: tsickert/discord-webhook@v6.0.0
with:
webhook-url: ${{ env.DISCORD_WEBHOOK }}
content: |
OS: Linux
Summary: ${{ env.commit_message }}
Commit: ${{ github.sha }}
Branch: ${{ github.ref_name }}
filename: ./${{ env.FLATPAK_ID }}.flatpak
+94
View File
@@ -0,0 +1,94 @@
name: Build Project (Windows)
on:
workflow_dispatch:
env:
CMAKE_PRESET: x64-Clang-Release
jobs:
build:
name: Build Windows
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.ORG_TOKEN }}
- name: Checkout private repository
uses: actions/checkout@v4
with:
repository: ${{ secrets.ASSET_REPO }}
token: ${{ secrets.ASSET_REPO_TOKEN }}
path: .\private
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ccache-${{ runner.os }}
- name: Cache vcpkg
uses: actions/cache@v4
with:
path: |
./thirdparty/vcpkg/downloads
./thirdparty/vcpkg/packages
key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json') }}
restore-keys: |
vcpkg-${{ runner.os }}-
- name: Install dependencies
run: |
choco install ninja
Remove-Item -Path "C:\ProgramData\Chocolatey\bin\ccache.exe" -Force -ErrorAction SilentlyContinue
- name: Configure Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
- name: Prepare Project
run: |
$commitMessage = git log -1 --pretty=%s
Add-Content -Path $env:GITHUB_ENV -Value "commit_message=$commitMessage"
copy .\private\* .\UnleashedRecompLib\private
- name: Configure Project
run: cmake . --preset ${{ env.CMAKE_PRESET }} -DSDL2MIXER_VORBIS=VORBISFILE -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache
- name: Build Project
run: cmake --build .\out\build\${{ env.CMAKE_PRESET }} --target UnleashedRecomp
- name: Pack Release
run: |
New-Item -ItemType Directory -Path .\release
New-Item -ItemType Directory -Path .\release\D3D12
Move-Item -Path ".\out\build\${{ env.CMAKE_PRESET }}\UnleashedRecomp\D3D12\D3D12Core.dll" -Destination ".\release\D3D12\D3D12Core.dll"
Move-Item -Path ".\out\build\${{ env.CMAKE_PRESET }}\UnleashedRecomp\dxcompiler.dll" -Destination ".\release\dxcompiler.dll"
Move-Item -Path ".\out\build\${{ env.CMAKE_PRESET }}\UnleashedRecomp\dxil.dll" -Destination ".\release\dxil.dll"
Move-Item -Path ".\out\build\${{ env.CMAKE_PRESET }}\UnleashedRecomp\UnleashedRecomp.exe" -Destination ".\release\UnleashedRecomp.exe"
Compress-Archive -Path .\release\* -DestinationPath .\UnleashedRecomp-Windows.zip
# Uploads the packed zip file to GitHub
# - name: Upload artifact
# uses: actions/upload-artifact@v4
# with:
# name: UnleashedRecomp-Windows
# path: .\UnleashedRecomp-Windows.zip
- name: Upload artifact to Discord
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
if: ${{ env.DISCORD_WEBHOOK != '' }}
uses: tsickert/discord-webhook@v6.0.0
with:
webhook-url: ${{ env.DISCORD_WEBHOOK }}
content: |
OS: Windows
Summary: ${{ env.commit_message }}
Commit: ${{ github.sha }}
Branch: ${{ github.ref_name }}
filename: .\UnleashedRecomp-Windows.zip
+6 -6
View File
@@ -1,12 +1,12 @@
[submodule "thirdparty/PowerRecomp"] [submodule "tools/XenonRecomp"]
path = tools/PowerRecomp path = tools/XenonRecomp
url = https://github.com/hedge-dev/PowerRecomp url = https://github.com/hedge-dev/XenonRecomp.git
[submodule "thirdparty/ddspp"] [submodule "thirdparty/ddspp"]
path = thirdparty/ddspp path = thirdparty/ddspp
url = https://github.com/redorav/ddspp.git url = https://github.com/redorav/ddspp.git
[submodule "thirdparty/ShaderRecomp"] [submodule "tools/XenosRecomp"]
path = tools/ShaderRecomp path = tools/XenosRecomp
url = https://github.com/hedge-dev/ShaderRecomp.git url = https://github.com/hedge-dev/XenosRecomp.git
[submodule "thirdparty/libmspack"] [submodule "thirdparty/libmspack"]
path = thirdparty/libmspack path = thirdparty/libmspack
url = https://github.com/kyz/libmspack url = https://github.com/kyz/libmspack
+9 -4
View File
@@ -5,8 +5,8 @@ if(NOT DEFINED ENV{VCPKG_ROOT})
endif() endif()
include($ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake) include($ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
set(SWA_THIRDPARTY_ROOT ${CMAKE_SOURCE_DIR}/thirdparty) set(UNLEASHED_RECOMP_THIRDPARTY_ROOT ${CMAKE_SOURCE_DIR}/thirdparty)
set(SWA_TOOLS_ROOT ${CMAKE_SOURCE_DIR}/tools) set(UNLEASHED_RECOMP_TOOLS_ROOT ${CMAKE_SOURCE_DIR}/tools)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
@@ -18,8 +18,13 @@ endif()
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
add_subdirectory(${SWA_THIRDPARTY_ROOT}) # Target Sandy Bridge for all projects
add_subdirectory(${SWA_TOOLS_ROOT}) add_compile_options(
-march=sandybridge
)
add_subdirectory(${UNLEASHED_RECOMP_THIRDPARTY_ROOT})
add_subdirectory(${UNLEASHED_RECOMP_TOOLS_ROOT})
project("UnleashedRecomp-ALL") project("UnleashedRecomp-ALL")
+1 -2
View File
@@ -23,8 +23,7 @@
"type": "equals", "type": "equals",
"lhs": "${hostSystemName}", "lhs": "${hostSystemName}",
"rhs": "Windows" "rhs": "Windows"
}, }
"toolset": "ClangCL"
}, },
{ {
"name": "x64-Clang-Debug", "name": "x64-Clang-Debug",
+83 -104
View File
@@ -1,16 +1,13 @@
project("UnleashedRecomp") project("UnleashedRecomp")
set(TARGET_NAME "SWA")
if (WIN32) if (WIN32)
option(SWA_D3D12 "Add D3D12 support for rendering" ON) option(UNLEASHED_RECOMP_D3D12 "Add D3D12 support for rendering" ON)
endif() endif()
if (CMAKE_SYSTEM_NAME MATCHES "Linux") if (CMAKE_SYSTEM_NAME MATCHES "Linux")
option(SWA_FLATPAK "Configure the build for Flatpak compatibility." OFF) option(UNLEASHED_RECOMP_FLATPAK "Configure the build for Flatpak compatibility." OFF)
endif() endif()
option(SWA_XAUDIO2 "Use XAudio2 for audio playback" OFF)
function(BIN2C) function(BIN2C)
cmake_parse_arguments(BIN2C_ARGS "" "TARGET_OBJ;SOURCE_FILE;DEST_FILE;ARRAY_NAME;COMPRESSION_TYPE" "" ${ARGN}) cmake_parse_arguments(BIN2C_ARGS "" "TARGET_OBJ;SOURCE_FILE;DEST_FILE;ARRAY_NAME;COMPRESSION_TYPE" "" ${ARGN})
@@ -42,9 +39,7 @@ function(BIN2C)
endfunction() endfunction()
add_compile_options( add_compile_options(
-march=sandybridge
-fno-strict-aliasing -fno-strict-aliasing
-Wno-switch -Wno-switch
-Wno-unused-function -Wno-unused-function
-Wno-unused-variable -Wno-unused-variable
@@ -64,16 +59,15 @@ else()
endif() endif()
add_compile_definitions( add_compile_definitions(
SWA_IMPL
SDL_MAIN_HANDLED SDL_MAIN_HANDLED
_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR # Microsoft wtf? _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR # Microsoft wtf?
_CRT_SECURE_NO_WARNINGS) _CRT_SECURE_NO_WARNINGS)
set(SWA_PRECOMPILED_HEADERS set(UNLEASHED_RECOMP_PRECOMPILED_HEADERS
"stdafx.h" "stdafx.h"
) )
set(SWA_KERNEL_CXX_SOURCES set(UNLEASHED_RECOMP_KERNEL_CXX_SOURCES
"kernel/imports.cpp" "kernel/imports.cpp"
"kernel/xdm.cpp" "kernel/xdm.cpp"
"kernel/heap.cpp" "kernel/heap.cpp"
@@ -82,21 +76,13 @@ set(SWA_KERNEL_CXX_SOURCES
"kernel/io/file_system.cpp" "kernel/io/file_system.cpp"
) )
set(SWA_LOCALE_CXX_SOURCES set(UNLEASHED_RECOMP_LOCALE_CXX_SOURCES
"locale/config_locale.cpp" "locale/config_locale.cpp"
"locale/locale.cpp" "locale/locale.cpp"
) )
set(SWA_OS_CXX_SOURCES
"os/logger.cpp"
"os/media.cpp"
"os/process.cpp"
"os/user.cpp"
"os/version.cpp"
)
if (WIN32) if (WIN32)
list(APPEND SWA_OS_CXX_SOURCES set(UNLEASHED_RECOMP_OS_CXX_SOURCES
"os/win32/logger_win32.cpp" "os/win32/logger_win32.cpp"
"os/win32/media_win32.cpp" "os/win32/media_win32.cpp"
"os/win32/process_win32.cpp" "os/win32/process_win32.cpp"
@@ -104,7 +90,7 @@ if (WIN32)
"os/win32/version_win32.cpp" "os/win32/version_win32.cpp"
) )
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux") elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
list(APPEND SWA_OS_CXX_SOURCES set(UNLEASHED_RECOMP_OS_CXX_SOURCES
"os/linux/logger_linux.cpp" "os/linux/logger_linux.cpp"
"os/linux/media_linux.cpp" "os/linux/media_linux.cpp"
"os/linux/process_linux.cpp" "os/linux/process_linux.cpp"
@@ -113,11 +99,11 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
) )
endif() endif()
set(SWA_CPU_CXX_SOURCES set(UNLEASHED_RECOMP_CPU_CXX_SOURCES
"cpu/guest_thread.cpp" "cpu/guest_thread.cpp"
) )
set(SWA_GPU_CXX_SOURCES set(UNLEASHED_RECOMP_GPU_CXX_SOURCES
"gpu/video.cpp" "gpu/video.cpp"
"gpu/imgui/imgui_common.cpp" "gpu/imgui/imgui_common.cpp"
"gpu/imgui/imgui_font_builder.cpp" "gpu/imgui/imgui_font_builder.cpp"
@@ -125,29 +111,24 @@ set(SWA_GPU_CXX_SOURCES
"gpu/rhi/plume_vulkan.cpp" "gpu/rhi/plume_vulkan.cpp"
) )
if (SWA_D3D12) if (UNLEASHED_RECOMP_D3D12)
list(APPEND SWA_GPU_CXX_SOURCES list(APPEND UNLEASHED_RECOMP_GPU_CXX_SOURCES
"gpu/rhi/plume_d3d12.cpp" "gpu/rhi/plume_d3d12.cpp"
) )
endif() endif()
set(SWA_APU_CXX_SOURCES set(UNLEASHED_RECOMP_APU_CXX_SOURCES
"apu/audio.cpp" "apu/audio.cpp"
"apu/embedded_player.cpp" "apu/embedded_player.cpp"
"apu/driver/sdl2_driver.cpp"
) )
if (SWA_XAUDIO2) set(UNLEASHED_RECOMP_HID_CXX_SOURCES
list(APPEND SWA_APU_CXX_SOURCES "apu/driver/xaudio_driver.cpp")
else()
list(APPEND SWA_APU_CXX_SOURCES "apu/driver/sdl2_driver.cpp")
endif()
set(SWA_HID_CXX_SOURCES
"hid/hid.cpp" "hid/hid.cpp"
"hid/driver/sdl_hid.cpp" "hid/driver/sdl_hid.cpp"
) )
set(SWA_PATCHES_CXX_SOURCES set(UNLEASHED_RECOMP_PATCHES_CXX_SOURCES
"patches/ui/CHudPause_patches.cpp" "patches/ui/CHudPause_patches.cpp"
"patches/ui/CTitleStateIntro_patches.cpp" "patches/ui/CTitleStateIntro_patches.cpp"
"patches/ui/CTitleStateMenu_patches.cpp" "patches/ui/CTitleStateMenu_patches.cpp"
@@ -155,7 +136,9 @@ set(SWA_PATCHES_CXX_SOURCES
"patches/aspect_ratio_patches.cpp" "patches/aspect_ratio_patches.cpp"
"patches/audio_patches.cpp" "patches/audio_patches.cpp"
"patches/camera_patches.cpp" "patches/camera_patches.cpp"
"patches/CGameModeStageTitle_patches.cpp"
"patches/fps_patches.cpp" "patches/fps_patches.cpp"
"patches/input_patches.cpp"
"patches/inspire_patches.cpp" "patches/inspire_patches.cpp"
"patches/misc_patches.cpp" "patches/misc_patches.cpp"
"patches/object_patches.cpp" "patches/object_patches.cpp"
@@ -164,7 +147,7 @@ set(SWA_PATCHES_CXX_SOURCES
"patches/video_patches.cpp" "patches/video_patches.cpp"
) )
set(SWA_UI_CXX_SOURCES set(UNLEASHED_RECOMP_UI_CXX_SOURCES
"ui/achievement_menu.cpp" "ui/achievement_menu.cpp"
"ui/achievement_overlay.cpp" "ui/achievement_overlay.cpp"
"ui/installer_wizard.cpp" "ui/installer_wizard.cpp"
@@ -177,7 +160,7 @@ set(SWA_UI_CXX_SOURCES
"ui/game_window.cpp" "ui/game_window.cpp"
) )
set(SWA_INSTALL_CXX_SOURCES set(UNLEASHED_RECOMP_INSTALL_CXX_SOURCES
"install/installer.cpp" "install/installer.cpp"
"install/iso_file_system.cpp" "install/iso_file_system.cpp"
"install/memory_mapped_file.cpp" "install/memory_mapped_file.cpp"
@@ -193,56 +176,56 @@ set(SWA_INSTALL_CXX_SOURCES
"install/hashes/update.cpp" "install/hashes/update.cpp"
) )
set(SWA_USER_CXX_SOURCES set(UNLEASHED_RECOMP_USER_CXX_SOURCES
"user/achievement_data.cpp" "user/achievement_data.cpp"
"user/config.cpp" "user/config.cpp"
) )
set(SWA_MOD_CXX_SOURCES set(UNLEASHED_RECOMP_MOD_CXX_SOURCES
"mod/mod_loader.cpp" "mod/mod_loader.cpp"
) )
set(SWA_THIRDPARTY_SOURCES set(UNLEASHED_RECOMP_THIRDPARTY_SOURCES
"${SWA_THIRDPARTY_ROOT}/imgui/backends/imgui_impl_sdl2.cpp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui/backends/imgui_impl_sdl2.cpp"
"${SWA_THIRDPARTY_ROOT}/imgui/imgui.cpp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui/imgui.cpp"
"${SWA_THIRDPARTY_ROOT}/imgui/imgui_demo.cpp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui/imgui_demo.cpp"
"${SWA_THIRDPARTY_ROOT}/imgui/imgui_draw.cpp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui/imgui_draw.cpp"
"${SWA_THIRDPARTY_ROOT}/imgui/imgui_tables.cpp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui/imgui_tables.cpp"
"${SWA_THIRDPARTY_ROOT}/imgui/imgui_widgets.cpp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui/imgui_widgets.cpp"
"${SWA_THIRDPARTY_ROOT}/implot/implot.cpp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot.cpp"
"${SWA_THIRDPARTY_ROOT}/implot/implot_demo.cpp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot_demo.cpp"
"${SWA_THIRDPARTY_ROOT}/implot/implot_items.cpp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot_items.cpp"
"${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack/lzxd.c" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/libmspack/libmspack/mspack/lzxd.c"
"${SWA_THIRDPARTY_ROOT}/tiny-AES-c/aes.c" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/tiny-AES-c/aes.c"
"${SWA_TOOLS_ROOT}/ShaderRecomp/thirdparty/smol-v/source/smolv.cpp" "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/thirdparty/smol-v/source/smolv.cpp"
) )
set(SWA_THIRDPARTY_INCLUDES set(UNLEASHED_RECOMP_THIRDPARTY_INCLUDES
"${SWA_THIRDPARTY_ROOT}/concurrentqueue" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/concurrentqueue"
"${SWA_THIRDPARTY_ROOT}/ddspp" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/ddspp"
"${SWA_THIRDPARTY_ROOT}/imgui" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui"
"${SWA_THIRDPARTY_ROOT}/implot" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot"
"${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/libmspack/libmspack/mspack"
"${SWA_THIRDPARTY_ROOT}/magic_enum/include" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include"
"${SWA_THIRDPARTY_ROOT}/stb" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/stb"
"${SWA_THIRDPARTY_ROOT}/tiny-AES-c" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/tiny-AES-c"
"${SWA_THIRDPARTY_ROOT}/TinySHA1" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/TinySHA1"
"${SWA_THIRDPARTY_ROOT}/unordered_dense/include" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/unordered_dense/include"
"${SWA_THIRDPARTY_ROOT}/volk" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/volk"
"${SWA_THIRDPARTY_ROOT}/Vulkan-Headers/include" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/Vulkan-Headers/include"
"${SWA_THIRDPARTY_ROOT}/VulkanMemoryAllocator/include" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/VulkanMemoryAllocator/include"
"${SWA_TOOLS_ROOT}/bc_diff" "${UNLEASHED_RECOMP_TOOLS_ROOT}/bc_diff"
"${SWA_TOOLS_ROOT}/ShaderRecomp/thirdparty/smol-v/source" "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/thirdparty/smol-v/source"
) )
if (SWA_D3D12) if (UNLEASHED_RECOMP_D3D12)
list(APPEND SWA_THIRDPARTY_INCLUDES "${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/include") list(APPEND UNLEASHED_RECOMP_THIRDPARTY_INCLUDES "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/D3D12MemoryAllocator/include")
list(APPEND SWA_THIRDPARTY_SOURCES "${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/src/D3D12MemAlloc.cpp") list(APPEND UNLEASHED_RECOMP_THIRDPARTY_SOURCES "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/D3D12MemoryAllocator/src/D3D12MemAlloc.cpp")
endif() endif()
set_source_files_properties(${SWA_THIRDPARTY_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) set_source_files_properties(${UNLEASHED_RECOMP_THIRDPARTY_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
set(SWA_CXX_SOURCES set(UNLEASHED_RECOMP_CXX_SOURCES
"app.cpp" "app.cpp"
"exports.cpp" "exports.cpp"
"main.cpp" "main.cpp"
@@ -250,40 +233,38 @@ set(SWA_CXX_SOURCES
"stdafx.cpp" "stdafx.cpp"
"version.cpp" "version.cpp"
${SWA_KERNEL_CXX_SOURCES} ${UNLEASHED_RECOMP_KERNEL_CXX_SOURCES}
${SWA_LOCALE_CXX_SOURCES} ${UNLEASHED_RECOMP_LOCALE_CXX_SOURCES}
${SWA_OS_CXX_SOURCES} ${UNLEASHED_RECOMP_OS_CXX_SOURCES}
${SWA_CPU_CXX_SOURCES} ${UNLEASHED_RECOMP_CPU_CXX_SOURCES}
${SWA_GPU_CXX_SOURCES} ${UNLEASHED_RECOMP_GPU_CXX_SOURCES}
${SWA_APU_CXX_SOURCES} ${UNLEASHED_RECOMP_APU_CXX_SOURCES}
${SWA_HID_CXX_SOURCES} ${UNLEASHED_RECOMP_HID_CXX_SOURCES}
${SWA_PATCHES_CXX_SOURCES} ${UNLEASHED_RECOMP_PATCHES_CXX_SOURCES}
${SWA_UI_CXX_SOURCES} ${UNLEASHED_RECOMP_UI_CXX_SOURCES}
${SWA_INSTALL_CXX_SOURCES} ${UNLEASHED_RECOMP_INSTALL_CXX_SOURCES}
${SWA_USER_CXX_SOURCES} ${UNLEASHED_RECOMP_USER_CXX_SOURCES}
${SWA_MOD_CXX_SOURCES} ${UNLEASHED_RECOMP_MOD_CXX_SOURCES}
${SWA_THIRDPARTY_SOURCES} ${UNLEASHED_RECOMP_THIRDPARTY_SOURCES}
) )
if (WIN32) if (WIN32)
# Set up Win32 resources for application icon. # Set up Win32 resources for application icon.
set(ICON_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources/images/game_icon.ico") set(ICON_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources/images/game_icon.ico")
configure_file("res/win32/res.rc.template" "${CMAKE_BINARY_DIR}/res.rc" @ONLY) configure_file("res/win32/res.rc.template" "${CMAKE_BINARY_DIR}/res.rc" @ONLY)
add_executable(UnleashedRecomp ${SWA_CXX_SOURCES} "${CMAKE_BINARY_DIR}/res.rc") add_executable(UnleashedRecomp ${UNLEASHED_RECOMP_CXX_SOURCES} "${CMAKE_BINARY_DIR}/res.rc")
else() else()
add_executable(UnleashedRecomp ${SWA_CXX_SOURCES}) add_executable(UnleashedRecomp ${UNLEASHED_RECOMP_CXX_SOURCES})
endif() endif()
set_target_properties(UnleashedRecomp PROPERTIES OUTPUT_NAME ${TARGET_NAME}) if (UNLEASHED_RECOMP_FLATPAK)
if (SWA_FLATPAK)
target_compile_definitions(UnleashedRecomp PRIVATE "GAME_INSTALL_DIRECTORY=\"/var/data\"") target_compile_definitions(UnleashedRecomp PRIVATE "GAME_INSTALL_DIRECTORY=\"/var/data\"")
endif() endif()
if (SWA_D3D12) if (UNLEASHED_RECOMP_D3D12)
find_package(directx-headers CONFIG REQUIRED) find_package(directx-headers CONFIG REQUIRED)
find_package(directx12-agility CONFIG REQUIRED) find_package(directx12-agility CONFIG REQUIRED)
target_compile_definitions(UnleashedRecomp PRIVATE SWA_D3D12) target_compile_definitions(UnleashedRecomp PRIVATE UNLEASHED_RECOMP_D3D12)
endif() endif()
if (CMAKE_SYSTEM_NAME MATCHES "Linux") if (CMAKE_SYSTEM_NAME MATCHES "Linux")
@@ -292,7 +273,7 @@ endif()
find_package(directx-dxc REQUIRED) find_package(directx-dxc REQUIRED)
if (SWA_D3D12) if (UNLEASHED_RECOMP_D3D12)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
add_custom_command(TARGET UnleashedRecomp POST_BUILD add_custom_command(TARGET UnleashedRecomp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Core,IMPORTED_LOCATION_RELEASE> ${CMAKE_CURRENT_BINARY_DIR}/D3D12 COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Core,IMPORTED_LOCATION_RELEASE> ${CMAKE_CURRENT_BINARY_DIR}/D3D12
@@ -330,7 +311,7 @@ target_link_libraries(UnleashedRecomp PRIVATE
msdf-atlas-gen::msdf-atlas-gen msdf-atlas-gen::msdf-atlas-gen
nfd::nfd nfd::nfd
o1heap o1heap
PowerUtils XenonUtils
SDL2::SDL2-static SDL2::SDL2-static
SDL2_mixer SDL2_mixer
tomlplusplus::tomlplusplus tomlplusplus::tomlplusplus
@@ -341,7 +322,7 @@ target_link_libraries(UnleashedRecomp PRIVATE
target_include_directories(UnleashedRecomp PRIVATE target_include_directories(UnleashedRecomp PRIVATE
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
"${CMAKE_CURRENT_SOURCE_DIR}/api" "${CMAKE_CURRENT_SOURCE_DIR}/api"
${SWA_THIRDPARTY_INCLUDES} ${UNLEASHED_RECOMP_THIRDPARTY_INCLUDES}
) )
if (CMAKE_SYSTEM_NAME MATCHES "Linux") if (CMAKE_SYSTEM_NAME MATCHES "Linux")
@@ -350,12 +331,12 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
target_link_libraries(UnleashedRecomp PRIVATE ${X11_LIBRARIES}) target_link_libraries(UnleashedRecomp PRIVATE ${X11_LIBRARIES})
endif() endif()
target_precompile_headers(UnleashedRecomp PUBLIC ${SWA_PRECOMPILED_HEADERS}) target_precompile_headers(UnleashedRecomp PUBLIC ${UNLEASHED_RECOMP_PRECOMPILED_HEADERS})
function(compile_shader FILE_PATH TARGET_NAME) function(compile_shader FILE_PATH TARGET_NAME)
set(FILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/gpu/shader/${FILE_PATH}.hlsl) set(FILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/gpu/shader/${FILE_PATH}.hlsl)
cmake_path(GET FILE_PATH STEM VARIABLE_NAME) cmake_path(GET FILE_PATH STEM VARIABLE_NAME)
if (SWA_D3D12) if (UNLEASHED_RECOMP_D3D12)
add_custom_command( add_custom_command(
OUTPUT ${FILE_PATH}.dxil.h OUTPUT ${FILE_PATH}.dxil.h
COMMAND ${DIRECTX_DXC_TOOL} -T ${TARGET_NAME} -HV 2021 -all-resources-bound -Wno-ignored-attributes -Fh ${FILE_PATH}.dxil.h ${FILE_PATH} -Vn g_${VARIABLE_NAME}_dxil COMMAND ${DIRECTX_DXC_TOOL} -T ${TARGET_NAME} -HV 2021 -all-resources-bound -Wno-ignored-attributes -Fh ${FILE_PATH}.dxil.h ${FILE_PATH} -Vn g_${VARIABLE_NAME}_dxil
@@ -427,9 +408,9 @@ generate_aggregate_header(
) )
# Only show build type if not Release. # Only show build type if not Release.
set(IS_BUILD_TYPE_IN_VER_STRING 0) set(SHOW_GIT_INFO_AND_BUILD_TYPE 0)
if (NOT ${CMAKE_BUILD_TYPE} MATCHES "Release") if (NOT ${CMAKE_BUILD_TYPE} MATCHES "Release")
set(IS_BUILD_TYPE_IN_VER_STRING 1) set(SHOW_GIT_INFO_AND_BUILD_TYPE 1)
endif() endif()
include("version.cmake") include("version.cmake")
@@ -439,8 +420,8 @@ GenerateVersionSources(
H_TEMPLATE "${PROJECT_SOURCE_DIR}/res/version.h.template" H_TEMPLATE "${PROJECT_SOURCE_DIR}/res/version.h.template"
CXX_TEMPLATE "${PROJECT_SOURCE_DIR}/res/version.cpp.template" CXX_TEMPLATE "${PROJECT_SOURCE_DIR}/res/version.cpp.template"
BUILD_TYPE ${CMAKE_BUILD_TYPE} BUILD_TYPE ${CMAKE_BUILD_TYPE}
IS_BUILD_TYPE_IN_VER_STRING ${IS_BUILD_TYPE_IN_VER_STRING} SHOW_GIT_INFO ${SHOW_GIT_INFO_AND_BUILD_TYPE}
IS_GIT_REPO 1 SHOW_BUILD_TYPE ${SHOW_GIT_INFO_AND_BUILD_TYPE}
) )
set(RESOURCES_SOURCE_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources") set(RESOURCES_SOURCE_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources")
@@ -469,7 +450,6 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/in
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/pulse_install.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/pulse_install.dds" ARRAY_NAME "g_pulse_install" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/pulse_install.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/pulse_install.dds" ARRAY_NAME "g_pulse_install" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" ARRAY_NAME "g_achievement_notifications" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" ARRAY_NAME "g_achievement_notifications" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input.dds" ARRAY_NAME "g_allow_background_input" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input.dds" ARRAY_NAME "g_allow_background_input" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_dpad_movement.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_dpad_movement.dds" ARRAY_NAME "g_allow_dpad_movement" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing.dds" ARRAY_NAME "g_antialiasing" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing.dds" ARRAY_NAME "g_antialiasing" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/aspect_ratio.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/aspect_ratio.dds" ARRAY_NAME "g_aspect_ratio" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/aspect_ratio.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/aspect_ratio.dds" ARRAY_NAME "g_aspect_ratio" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/battle_theme.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/battle_theme.dds" ARRAY_NAME "g_battle_theme" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/battle_theme.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/battle_theme.dds" ARRAY_NAME "g_battle_theme" COMPRESSION_TYPE "zstd")
@@ -511,8 +491,7 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration.dds" ARRAY_NAME "g_vibration" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration.dds" ARRAY_NAME "g_vibration" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vsync.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vsync.dds" ARRAY_NAME "g_vsync" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vsync.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vsync.dds" ARRAY_NAME "g_vsync" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/window_size.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/window_size.dds" ARRAY_NAME "g_window_size" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/window_size.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/window_size.dds" ARRAY_NAME "g_window_size" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/xbox_color_correction_false.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/xbox_color_correction_false.dds" ARRAY_NAME "g_xbox_color_correction_false" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/xbox_color_correction.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/xbox_color_correction.dds" ARRAY_NAME "g_xbox_color_correction" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/xbox_color_correction_true.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/xbox_color_correction_true.dds" ARRAY_NAME "g_xbox_color_correction_true" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/miles_electric.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/miles_electric.dds" ARRAY_NAME "g_miles_electric" COMPRESSION_TYPE "zstd") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/miles_electric.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/miles_electric.dds" ARRAY_NAME "g_miles_electric" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon.bmp" ARRAY_NAME "g_game_icon") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon.bmp" ARRAY_NAME "g_game_icon")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon_night.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon_night.bmp" ARRAY_NAME "g_game_icon_night") BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon_night.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon_night.bmp" ARRAY_NAME "g_game_icon_night")
+8 -8
View File
@@ -9,41 +9,41 @@ namespace Chao::CSD
inline void CNode::SetText(const char* in_pText) inline void CNode::SetText(const char* in_pText)
{ {
GuestToHostFunction<int>(0x830BF640, this, in_pText); GuestToHostFunction<int>(sub_830BF640, this, in_pText);
} }
inline void CNode::SetText(const wchar_t* in_pText) inline void CNode::SetText(const wchar_t* in_pText)
{ {
GuestToHostFunction<int>(0x830BF640, this, in_pText); GuestToHostFunction<int>(sub_830BF640, this, in_pText);
} }
inline void CNode::GetPosition(Hedgehog::Math::CVector2& out_rResult) const inline void CNode::GetPosition(Hedgehog::Math::CVector2& out_rResult) const
{ {
GuestToHostFunction<void>(0x830BF008, &out_rResult, this); GuestToHostFunction<void>(sub_830BF008, &out_rResult, this);
} }
inline void CNode::SetPosition(float in_X, float in_Y) inline void CNode::SetPosition(float in_X, float in_Y)
{ {
GuestToHostFunction<int>(0x830BF078, this, in_X, in_Y); GuestToHostFunction<int>(sub_830BF078, this, in_X, in_Y);
} }
inline void CNode::SetHideFlag(uint32_t in_HideFlag) inline void CNode::SetHideFlag(uint32_t in_HideFlag)
{ {
GuestToHostFunction<int>(0x830BF080, this, in_HideFlag); GuestToHostFunction<int>(sub_830BF080, this, in_HideFlag);
} }
inline void CNode::SetRotation(float in_Rotation) inline void CNode::SetRotation(float in_Rotation)
{ {
GuestToHostFunction<int>(0x830BF088, this, in_Rotation); GuestToHostFunction<int>(sub_830BF088, this, in_Rotation);
} }
inline void CNode::SetScale(float in_X, float in_Y) inline void CNode::SetScale(float in_X, float in_Y)
{ {
GuestToHostFunction<int>(0x830BF090, this, in_X, in_Y); GuestToHostFunction<int>(sub_830BF090, this, in_X, in_Y);
} }
inline void CNode::SetPatternIndex(uint32_t in_PatternIndex) inline void CNode::SetPatternIndex(uint32_t in_PatternIndex)
{ {
GuestToHostFunction<int>(0x830BF300, this, in_PatternIndex); GuestToHostFunction<int>(sub_830BF300, this, in_PatternIndex);
} }
} }
@@ -5,20 +5,20 @@ namespace Chao::CSD
inline RCPtr<CScene> CProject::CreateScene(const char* in_pName) const inline RCPtr<CScene> CProject::CreateScene(const char* in_pName) const
{ {
RCPtr<CScene> rcScene; RCPtr<CScene> rcScene;
GuestToHostFunction<void>(0x830BEE00, this, rcScene, in_pName, nullptr); GuestToHostFunction<void>(sub_830BEE00, this, rcScene, in_pName, nullptr);
return rcScene; return rcScene;
} }
inline RCPtr<CScene> CProject::CreateScene(const char* in_pName, const char* in_pMotionName) const inline RCPtr<CScene> CProject::CreateScene(const char* in_pName, const char* in_pMotionName) const
{ {
RCPtr<CScene> rcScene; RCPtr<CScene> rcScene;
GuestToHostFunction<void>(0x830BECE0, this, rcScene, in_pName, in_pMotionName, nullptr); GuestToHostFunction<void>(sub_830BECE0, this, rcScene, in_pName, in_pMotionName, nullptr);
return rcScene; return rcScene;
} }
inline void CProject::DestroyScene(CScene* in_pScene) inline void CProject::DestroyScene(CScene* in_pScene)
{ {
GuestToHostFunction<void>(0x830BE298, this, in_pScene); GuestToHostFunction<void>(sub_830BE298, this, in_pScene);
} }
inline void CProject::DestroyScene(RCPtr<CScene>& inout_rcScene) inline void CProject::DestroyScene(RCPtr<CScene>& inout_rcScene)
@@ -30,6 +30,6 @@ namespace Chao::CSD
inline void RCPtrAbs::RCObject::Release() inline void RCPtrAbs::RCObject::Release()
{ {
GuestToHostFunction<void>(0x830BA068, this); GuestToHostFunction<void>(sub_830BA068, this);
} }
} }
@@ -27,12 +27,12 @@ namespace Chao::CSD
inline void RCPtrAbs::AttachAbs(void* in_pMemory) inline void RCPtrAbs::AttachAbs(void* in_pMemory)
{ {
GuestToHostFunction<void>(0x830BA298, this, in_pMemory); GuestToHostFunction<void>(sub_830BA298, this, in_pMemory);
} }
inline void RCPtrAbs::SetAbs(const RCPtrAbs& in_rPtr) inline void RCPtrAbs::SetAbs(const RCPtrAbs& in_rPtr)
{ {
GuestToHostFunction<void>(0x830BA328, this, in_rPtr); GuestToHostFunction<void>(sub_830BA328, this, in_rPtr);
} }
inline void* RCPtrAbs::operator*() const inline void* RCPtrAbs::operator*() const
@@ -22,7 +22,7 @@ namespace Chao::CSD
inline bool CScene::SetMotion(const char* in_pName) inline bool CScene::SetMotion(const char* in_pName)
{ {
return GuestToHostFunction<bool>(0x830BA760, this, in_pName); return GuestToHostFunction<bool>(sub_830BA760, this, in_pName);
} }
inline void CScene::SetMotionFrame(float in_MotionFrame) inline void CScene::SetMotionFrame(float in_MotionFrame)
@@ -33,21 +33,21 @@ namespace Chao::CSD
inline void CScene::SetPosition(float in_X, float in_Y) inline void CScene::SetPosition(float in_X, float in_Y)
{ {
GuestToHostFunction<void>(0x830BB550, this, in_X, in_Y); GuestToHostFunction<void>(sub_830BB550, this, in_X, in_Y);
} }
inline void CScene::SetHideFlag(uint32_t in_HideFlag) inline void CScene::SetHideFlag(uint32_t in_HideFlag)
{ {
GuestToHostFunction<void>(0x830BB378, this, in_HideFlag); GuestToHostFunction<void>(sub_830BB378, this, in_HideFlag);
} }
inline void CScene::SetRotation(float in_Angle) inline void CScene::SetRotation(float in_Angle)
{ {
GuestToHostFunction<void>(0x830BB5F8, this, in_Angle); GuestToHostFunction<void>(sub_830BB5F8, this, in_Angle);
} }
inline void CScene::SetScale(float in_X, float in_Y) inline void CScene::SetScale(float in_X, float in_Y)
{ {
GuestToHostFunction<void>(0x830BB650, this, in_X, in_Y); GuestToHostFunction<void>(sub_830BB650, this, in_X, in_Y);
} }
} }
@@ -17,6 +17,7 @@ namespace Hedgehog::Math
be<float> X; be<float> X;
be<float> Y; be<float> Y;
be<float> Z; be<float> Z;
be<float> W;
}; };
class CVector4 class CVector4
@@ -0,0 +1,32 @@
#pragma once
#include <SWA.inl>
#include <Hedgehog/Base/hhObject.h>
#include <Hedgehog/Universe/Engine/hhMessageProcess.h>
#include <Hedgehog/Universe/Engine/hhStateMachineMessageReceiver.h>
namespace Hedgehog::Universe
{
class CStateMachineBase : public IStateMachineMessageReceiver, public Base::CObject
{
public:
class CStateBase : public IMessageProcess
{
public:
SWA_INSERT_PADDING(0x08);
xpointer<void> m_pContext;
xpointer<CStateMachineBase> m_pStateMachine;
be<float> m_Time;
SWA_INSERT_PADDING(0x4C);
void* GetContextBase() const;
template<typename T>
T* GetContextBase() const;
};
SWA_INSERT_PADDING(0x60);
};
}
#include <Hedgehog/Universe/Engine/hhStateMachineBase.inl>
@@ -0,0 +1,13 @@
namespace Hedgehog::Universe
{
inline void* CStateMachineBase::CStateBase::GetContextBase() const
{
return m_pContext;
}
template<typename T>
inline T* CStateMachineBase::CStateBase::GetContextBase() const
{
return (T*)m_pContext.get();
}
}
@@ -0,0 +1,12 @@
#pragma once
#include <SWA.inl>
namespace Hedgehog::Universe
{
class IStateMachineMessageReceiver
{
public:
IStateMachineMessageReceiver(const swa_null_ctor&) {}
};
}
+10
View File
@@ -47,6 +47,8 @@
#include "Hedgehog/Sparkle/hhParticleMaterial.h" #include "Hedgehog/Sparkle/hhParticleMaterial.h"
#include "Hedgehog/Universe/Engine/hhMessageActor.h" #include "Hedgehog/Universe/Engine/hhMessageActor.h"
#include "Hedgehog/Universe/Engine/hhMessageProcess.h" #include "Hedgehog/Universe/Engine/hhMessageProcess.h"
#include "Hedgehog/Universe/Engine/hhStateMachineBase.h"
#include "Hedgehog/Universe/Engine/hhStateMachineMessageReceiver.h"
#include "Hedgehog/Universe/Engine/hhUpdateInfo.h" #include "Hedgehog/Universe/Engine/hhUpdateInfo.h"
#include "Hedgehog/Universe/Engine/hhUpdateUnit.h" #include "Hedgehog/Universe/Engine/hhUpdateUnit.h"
#include "Hedgehog/Universe/Thread/hhParallelJob.h" #include "Hedgehog/Universe/Thread/hhParallelJob.h"
@@ -57,6 +59,8 @@
#include "SWA/CSD/CsdTexListMirage.h" #include "SWA/CSD/CsdTexListMirage.h"
#include "SWA/CSD/GameObjectCSD.h" #include "SWA/CSD/GameObjectCSD.h"
#include "SWA/Camera/Camera.h" #include "SWA/Camera/Camera.h"
#include "SWA/Camera/CameraController.h"
#include "SWA/CharacterUtility/CharacterProxy.h"
#include "SWA/HUD/GeneralWindow/GeneralWindow.h" #include "SWA/HUD/GeneralWindow/GeneralWindow.h"
#include "SWA/HUD/Loading/Loading.h" #include "SWA/HUD/Loading/Loading.h"
#include "SWA/HUD/Pause/HudPause.h" #include "SWA/HUD/Pause/HudPause.h"
@@ -71,6 +75,7 @@
#include "SWA/Inspire/InspireTextureAnimationInfo.h" #include "SWA/Inspire/InspireTextureAnimationInfo.h"
#include "SWA/Inspire/InspireTextureOverlay.h" #include "SWA/Inspire/InspireTextureOverlay.h"
#include "SWA/Inspire/InspireTextureOverlayInfo.h" #include "SWA/Inspire/InspireTextureOverlayInfo.h"
#include "SWA/Menu/MenuWindowBase.h"
#include "SWA/Movie/MovieDisplayer.h" #include "SWA/Movie/MovieDisplayer.h"
#include "SWA/Movie/MovieManager.h" #include "SWA/Movie/MovieManager.h"
#include "SWA/Player/Character/EvilSonic/EvilSonic.h" #include "SWA/Player/Character/EvilSonic/EvilSonic.h"
@@ -91,8 +96,13 @@
#include "SWA/System/GameMode/GameMode.h" #include "SWA/System/GameMode/GameMode.h"
#include "SWA/System/GameMode/GameModeStage.h" #include "SWA/System/GameMode/GameModeStage.h"
#include "SWA/System/GameMode/GameModeStageMovie.h" #include "SWA/System/GameMode/GameModeStageMovie.h"
#include "SWA/System/GameMode/GameModeStageTitle.h"
#include "SWA/System/GameMode/Title/TitleMenu.h" #include "SWA/System/GameMode/Title/TitleMenu.h"
#include "SWA/System/GameMode/Title/TitleStateBase.h" #include "SWA/System/GameMode/Title/TitleStateBase.h"
#include "SWA/System/GameMode/Title/TitleStateIntro.h"
#include "SWA/System/GameMode/Title/TitleStateWorldMap.h"
#include "SWA/System/GameMode/WorldMap/WorldMapCamera.h"
#include "SWA/System/GameMode/WorldMap/WorldMapCursor.h"
#include "SWA/System/GameObject.h" #include "SWA/System/GameObject.h"
#include "SWA/System/GameParameter.h" #include "SWA/System/GameParameter.h"
#include "SWA/System/GammaController.h" #include "SWA/System/GammaController.h"
@@ -3,7 +3,7 @@ namespace SWA
inline boost::shared_ptr<CCsdProject> CCsdDatabaseWrapper::GetCsdProject(const Hedgehog::Base::CSharedString& in_rName) inline boost::shared_ptr<CCsdProject> CCsdDatabaseWrapper::GetCsdProject(const Hedgehog::Base::CSharedString& in_rName)
{ {
boost::shared_ptr<CCsdProject> spCsdProject; boost::shared_ptr<CCsdProject> spCsdProject;
GuestToHostFunction<void>(0x825E2B40, &in_rName, this, &spCsdProject, 0); GuestToHostFunction<void>(sub_825E2B40, &in_rName, this, &spCsdProject, 0);
return spCsdProject; return spCsdProject;
} }
} }
@@ -0,0 +1,17 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CCameraController : public Hedgehog::Universe::CStateMachineBase::CStateBase
{
public:
SWA_INSERT_PADDING(0x04);
be<float> m_FieldOfView;
SWA_INSERT_PADDING(0x68);
};
SWA_ASSERT_OFFSETOF(CCameraController, m_FieldOfView, 0x64);
SWA_ASSERT_SIZEOF(CCameraController, 0xD0);
}
@@ -0,0 +1,14 @@
#pragma once
#include <Hedgehog/Math/Vector.h>
namespace SWA
{
class CCharacterProxy
{
public:
SWA_INSERT_PADDING(0x120);
Hedgehog::Math::CVector m_Position;
Hedgehog::Math::CVector m_Velocity;
};
}
@@ -0,0 +1,12 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CMenuWindowBase
{
public:
SWA_INSERT_PADDING(0x10);
};
}
@@ -4,10 +4,9 @@
namespace SWA namespace SWA
{ {
class CGameMode // : Hedgehog::Universe::TStateMachine<SWA::CGame>::TState class CGameMode : public Hedgehog::Universe::CStateMachineBase::CStateBase
{ {
public: public:
SWA_INSERT_PADDING(0x60); // base
SWA_INSERT_PADDING(0x08); SWA_INSERT_PADDING(0x08);
}; };
} }
@@ -0,0 +1,14 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CGameModeStageTitle : public CGameModeStage
{
public:
SWA_INSERT_PADDING(0x0E);
bool m_IsPlayingAdvertiseMovie;
be<float> m_AdvertiseMovieWaitTime;
};
}
@@ -4,19 +4,14 @@
namespace SWA namespace SWA
{ {
class CTitleStateBase // : Hedgehog::Universe::TStateMachine<SWA::CTitleManager>::TState class CTitleStateBase : public Hedgehog::Universe::CStateMachineBase::CStateBase
{ {
public: public:
class CMember class CTitleStateContext
{ {
public: public:
SWA_INSERT_PADDING(0x1E8); SWA_INSERT_PADDING(0x1E8);
xpointer<CTitleMenu> m_pTitleMenu; xpointer<CTitleMenu> m_pTitleMenu;
}; };
SWA_INSERT_PADDING(0x08);
xpointer<CMember> m_pMember;
SWA_INSERT_PADDING(0x5C);
be<uint32_t> m_State;
}; };
} }
@@ -0,0 +1,8 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CTitleStateIntro : public CTitleStateBase {};
}
@@ -0,0 +1,14 @@
#pragma once
#include <SWA.inl>
#include <SWA/System/GameMode/WorldMap/WorldMapCursor.h>
namespace SWA
{
class CTitleStateWorldMap : public CTitleStateBase
{
public:
SWA_INSERT_PADDING(0x08);
xpointer<CWorldMapCursor> m_pWorldMapCursor;
};
}
@@ -0,0 +1,26 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CWorldMapCamera : public CCameraController
{
public:
be<float> m_Pitch;
be<float> m_Yaw;
be<float> m_Distance;
be<float> m_RotationSpeed;
SWA_INSERT_PADDING(0x08);
bool m_CanMove;
SWA_INSERT_PADDING(0x34);
be<float> m_TiltToEarthTransitionSpeed;
};
SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_Pitch, 0xD0);
SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_Yaw, 0xD4);
SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_Distance, 0xD8);
SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_RotationSpeed, 0xDC);
SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_CanMove, 0xE8);
SWA_ASSERT_OFFSETOF(CWorldMapCamera, m_TiltToEarthTransitionSpeed, 0x120);
}
@@ -0,0 +1,24 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CWorldMapCursor : public CMenuWindowBase
{
public:
SWA_INSERT_PADDING(0x24);
be<float> m_LeftStickVertical;
be<float> m_LeftStickHorizontal;
bool m_IsCursorMoving;
SWA_INSERT_PADDING(0x07);
be<float> m_CursorY;
be<float> m_CursorX;
};
SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_LeftStickVertical, 0x34);
SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_LeftStickHorizontal, 0x38);
SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_IsCursorMoving, 0x3C);
SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_CursorY, 0x44);
SWA_ASSERT_OFFSETOF(CWorldMapCursor, m_CursorX, 0x48);
}
+1
View File
@@ -7,6 +7,7 @@
#include <patches/inspire_patches.h> #include <patches/inspire_patches.h>
#include <ui/game_window.h> #include <ui/game_window.h>
#include <user/config.h> #include <user/config.h>
#include <user/paths.h>
void App::Restart(std::vector<std::string> restartArgs) void App::Restart(std::vector<std::string> restartArgs)
{ {
+1
View File
@@ -9,6 +9,7 @@ public:
static inline bool s_isMissingDLC; static inline bool s_isMissingDLC;
static inline bool s_isLoading; static inline bool s_isLoading;
static inline bool s_isWerehog; static inline bool s_isWerehog;
static inline bool s_isSaveDataCorrupt;
static inline ELanguage s_language; static inline ELanguage s_language;
+1 -2
View File
@@ -7,11 +7,10 @@
// Number of samples in a frame // Number of samples in a frame
#define XAUDIO_NUM_SAMPLES 256 #define XAUDIO_NUM_SAMPLES 256
#ifdef SWA_IMPL
void XAudioInitializeSystem(); void XAudioInitializeSystem();
void XAudioRegisterClient(PPCFunc* callback, uint32_t param); void XAudioRegisterClient(PPCFunc* callback, uint32_t param);
void XAudioSubmitFrame(void* samples); void XAudioSubmitFrame(void* samples);
#endif void XAudioConfigValueChangedCallback(class IConfigDef* configDef);
uint32_t XAudioRegisterRenderDriverClient(be<uint32_t>* callback, be<uint32_t>* driver); uint32_t XAudioRegisterRenderDriverClient(be<uint32_t>* callback, be<uint32_t>* driver);
uint32_t XAudioUnregisterRenderDriverClient(uint32_t driver); uint32_t XAudioUnregisterRenderDriverClient(uint32_t driver);
+44 -11
View File
@@ -1,26 +1,29 @@
#include "sdl2_driver.h" #include <apu/audio.h>
#include <cpu/guest_thread.h> #include <cpu/guest_thread.h>
#include <kernel/heap.h> #include <kernel/heap.h>
#include <user/config.h>
static PPCFunc* g_clientCallback{}; static PPCFunc* g_clientCallback{};
static uint32_t g_clientCallbackParam{}; // pointer in guest memory static uint32_t g_clientCallbackParam{}; // pointer in guest memory
static SDL_AudioDeviceID g_audioDevice{}; static SDL_AudioDeviceID g_audioDevice{};
static bool g_downMixToStereo; static bool g_downMixToStereo;
void XAudioInitializeSystem() static void CreateAudioDevice()
{ {
SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback"); if (g_audioDevice != NULL)
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Unleashed Recompiled"); SDL_CloseAudioDevice(g_audioDevice);
SDL_InitSubSystem(SDL_INIT_AUDIO);
bool surround = Config::ChannelConfiguration == EChannelConfiguration::Surround;
int allowedChanges = surround ? SDL_AUDIO_ALLOW_CHANNELS_CHANGE : 0;
SDL_AudioSpec desired{}, obtained{}; SDL_AudioSpec desired{}, obtained{};
desired.freq = XAUDIO_SAMPLES_HZ; desired.freq = XAUDIO_SAMPLES_HZ;
desired.format = AUDIO_F32SYS; desired.format = AUDIO_F32SYS;
desired.channels = XAUDIO_NUM_CHANNELS; desired.channels = surround ? XAUDIO_NUM_CHANNELS : 2;
desired.samples = XAUDIO_NUM_SAMPLES; desired.samples = XAUDIO_NUM_SAMPLES;
g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, SDL_AUDIO_ALLOW_CHANNELS_CHANGE); g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, allowedChanges);
if (obtained.channels != 2 && obtained.channels != XAUDIO_NUM_CHANNELS) if (obtained.channels != 2 && obtained.channels != XAUDIO_NUM_CHANNELS) // This check may fail only when surround sound is enabled.
{ {
SDL_CloseAudioDevice(g_audioDevice); SDL_CloseAudioDevice(g_audioDevice);
g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0); g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0);
@@ -29,7 +32,16 @@ void XAudioInitializeSystem()
g_downMixToStereo = (obtained.channels == 2); g_downMixToStereo = (obtained.channels == 2);
} }
void XAudioInitializeSystem()
{
SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback");
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Unleashed Recompiled");
SDL_InitSubSystem(SDL_INIT_AUDIO);
CreateAudioDevice();
}
static std::unique_ptr<std::thread> g_audioThread; static std::unique_ptr<std::thread> g_audioThread;
static volatile bool g_audioThreadShouldExit;
static void AudioThread() static void AudioThread()
{ {
@@ -39,7 +51,7 @@ static void AudioThread()
size_t channels = g_downMixToStereo ? 2 : XAUDIO_NUM_CHANNELS; size_t channels = g_downMixToStereo ? 2 : XAUDIO_NUM_CHANNELS;
while (true) while (!g_audioThreadShouldExit)
{ {
uint32_t queuedAudioSize = SDL_GetQueuedAudioSize(g_audioDevice); uint32_t queuedAudioSize = SDL_GetQueuedAudioSize(g_audioDevice);
constexpr size_t MAX_LATENCY = 10; constexpr size_t MAX_LATENCY = 10;
@@ -62,6 +74,13 @@ static void AudioThread()
} }
} }
static void CreateAudioThread()
{
SDL_PauseAudioDevice(g_audioDevice, 0);
g_audioThreadShouldExit = false;
g_audioThread = std::make_unique<std::thread>(AudioThread);
}
void XAudioRegisterClient(PPCFunc* callback, uint32_t param) void XAudioRegisterClient(PPCFunc* callback, uint32_t param)
{ {
auto* pClientParam = static_cast<uint32_t*>(g_userHeap.Alloc(sizeof(param))); auto* pClientParam = static_cast<uint32_t*>(g_userHeap.Alloc(sizeof(param)));
@@ -70,8 +89,7 @@ void XAudioRegisterClient(PPCFunc* callback, uint32_t param)
g_clientCallbackParam = g_memory.MapVirtual(pClientParam); g_clientCallbackParam = g_memory.MapVirtual(pClientParam);
g_clientCallback = callback; g_clientCallback = callback;
SDL_PauseAudioDevice(g_audioDevice, 0); CreateAudioThread();
g_audioThread = std::make_unique<std::thread>(AudioThread);
} }
void XAudioSubmitFrame(void* samples) void XAudioSubmitFrame(void* samples)
@@ -119,3 +137,18 @@ void XAudioSubmitFrame(void* samples)
SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames)); SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames));
} }
} }
void XAudioConfigValueChangedCallback(IConfigDef* configDef)
{
if (configDef == &Config::ChannelConfiguration)
{
if (g_audioThread->joinable())
{
g_audioThreadShouldExit = true;
g_audioThread->join();
}
CreateAudioDevice();
CreateAudioThread();
}
}
-3
View File
@@ -1,3 +0,0 @@
#pragma once
#include <apu/audio.h>
@@ -1,121 +0,0 @@
#include <stdafx.h>
#include "xaudio_driver.h"
#include <xaudio2.h>
#include <cpu/guest_thread.h>
#include <cpu/ppc_context.h>
#include <kernel/heap.h>
#define XAUDIO_DRIVER_KEY (uint32_t)('XAUD')
PPCFunc* volatile g_clientCallback{};
DWORD g_clientCallbackParam{}; // pointer in guest memory
DWORD g_driverThread{};
// TODO: Should use a counted ptr
IXAudio2* g_audio{};
IXAudio2MasteringVoice* g_masteringVoice{};
IXAudio2SourceVoice* g_sourceVoice{};
constexpr uint32_t g_semaphoreCount = 16;
constexpr uint32_t g_audioFrameSize = 256 * 6;
HANDLE g_audioSemaphore{ CreateSemaphoreA(nullptr, g_semaphoreCount, g_semaphoreCount, nullptr) };
uint32_t g_audioFrames[g_audioFrameSize * g_semaphoreCount];
uint32_t g_audioFrameIndex = 0;
class VoiceCallback : public IXAudio2VoiceCallback
{
STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32 BytesRequired) override {}
STDMETHOD_(void, OnVoiceProcessingPassEnd)() override {}
STDMETHOD_(void, OnBufferStart)(void* pBufferContext) override {}
STDMETHOD_(void, OnBufferEnd)(void* pBufferContext) override
{
ReleaseSemaphore(g_audioSemaphore, 1, nullptr);
}
STDMETHOD_(void, OnStreamEnd)() override {}
STDMETHOD_(void, OnLoopEnd)(void* pBufferContext) override {}
STDMETHOD_(void, OnVoiceError)(void* pBufferContext, HRESULT Error) override {}
} gVoiceCallback;
PPC_FUNC(DriverLoop)
{
GuestThread::SetThreadName(GetCurrentThreadId(), "Audio Driver");
while (true)
{
if (!g_clientCallback)
{
continue;
}
WaitForSingleObject(g_audioSemaphore, INFINITE);
ctx.r3.u64 = g_clientCallbackParam;
g_clientCallback(ctx, g_memory.base);
}
}
void XAudioInitializeSystem()
{
if (g_audio)
{
return;
}
//reinterpret_cast<decltype(&XAudio2Create)>(
// GetProcAddress(LoadLibraryA("XAudio2_8.dll"), "XAudio2Create"))(&gAudio, 0, 1);
XAudio2Create(&g_audio);
g_audio->CreateMasteringVoice(&g_masteringVoice);
WAVEFORMATIEEEFLOATEX format{};
format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
format.Format.cbSize = sizeof(format) - sizeof(format.Format);
format.Format.nChannels = XAUDIO_NUM_CHANNELS;
format.Format.nSamplesPerSec = XAUDIO_SAMPLES_HZ;
format.Format.wBitsPerSample = XAUDIO_SAMPLE_BITS;
format.Format.nBlockAlign = (format.Format.nChannels * format.Format.wBitsPerSample) / 8;
format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec * format.Format.nBlockAlign;
format.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
format.Samples.wValidBitsPerSample = format.Format.wBitsPerSample;
format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT |
SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
g_audio->CreateSourceVoice(&g_sourceVoice, &format.Format, 0, 1024, &gVoiceCallback);
g_sourceVoice->Start();
KeInsertHostFunction(XAUDIO_DRIVER_KEY, DriverLoop);
GuestThread::Start({ XAUDIO_DRIVER_KEY, 0, 0 }, nullptr);
}
void XAudioRegisterClient(PPCFunc* callback, uint32_t param)
{
auto* pClientParam = static_cast<uint32_t*>(g_userHeap.Alloc(sizeof(param)));
ByteSwapInplace(param);
*pClientParam = param;
g_clientCallbackParam = g_memory.MapVirtual(pClientParam);
g_clientCallback = callback;
}
void XAudioSubmitFrame(void* samples)
{
uint32_t* audioFrame = &g_audioFrames[g_audioFrameSize * g_audioFrameIndex];
g_audioFrameIndex = (g_audioFrameIndex + 1) % g_semaphoreCount;
for (size_t i = 0; i < XAUDIO_NUM_SAMPLES; i++)
{
for (size_t j = 0; j < 6; j++)
audioFrame[i * XAUDIO_NUM_CHANNELS + j] = ByteSwap(((uint32_t*)samples)[j * XAUDIO_NUM_SAMPLES + i]);
}
XAUDIO2_BUFFER buffer{};
buffer.pAudioData = (BYTE*)audioFrame;
buffer.AudioBytes = XAUDIO_NUM_SAMPLES * XAUDIO_NUM_CHANNELS * sizeof(float);
buffer.PlayLength = XAUDIO_NUM_SAMPLES;
g_sourceVoice->SubmitSourceBuffer(&buffer);
}
@@ -1,2 +0,0 @@
#pragma once
#include <apu/audio.h>
+6
View File
@@ -22,6 +22,7 @@ enum class ImGuiCallback : int32_t
SetOutline = -6, SetOutline = -6,
SetProceduralOrigin = -7, SetProceduralOrigin = -7,
// -8 is ImDrawCallback_ResetRenderState, don't use! // -8 is ImDrawCallback_ResetRenderState, don't use!
SetAdditive = -9
}; };
union ImGuiCallbackData union ImGuiCallbackData
@@ -64,6 +65,11 @@ union ImGuiCallbackData
{ {
float proceduralOrigin[2]; float proceduralOrigin[2];
} setProceduralOrigin; } setProceduralOrigin;
struct
{
bool enabled;
} setAdditive;
}; };
extern ImGuiCallbackData* AddImGuiCallback(ImGuiCallback callback); extern ImGuiCallbackData* AddImGuiCallback(ImGuiCallback callback);
@@ -1127,7 +1127,7 @@ namespace plume {
desc.srcBlend = RenderBlend::SRC_ALPHA; desc.srcBlend = RenderBlend::SRC_ALPHA;
desc.dstBlend = RenderBlend::INV_SRC_ALPHA; desc.dstBlend = RenderBlend::INV_SRC_ALPHA;
desc.blendOp = RenderBlendOperation::ADD; desc.blendOp = RenderBlendOperation::ADD;
desc.srcBlendAlpha = RenderBlend::ONE; desc.srcBlendAlpha = RenderBlend::SRC_ALPHA;
desc.dstBlendAlpha = RenderBlend::INV_SRC_ALPHA; desc.dstBlendAlpha = RenderBlend::INV_SRC_ALPHA;
desc.blendOpAlpha = RenderBlendOperation::ADD; desc.blendOpAlpha = RenderBlendOperation::ADD;
return desc; return desc;
@@ -1269,9 +1269,9 @@ namespace plume {
RenderFilter minFilter = RenderFilter::LINEAR; RenderFilter minFilter = RenderFilter::LINEAR;
RenderFilter magFilter = RenderFilter::LINEAR; RenderFilter magFilter = RenderFilter::LINEAR;
RenderMipmapMode mipmapMode = RenderMipmapMode::LINEAR; RenderMipmapMode mipmapMode = RenderMipmapMode::LINEAR;
RenderTextureAddressMode addressU = RenderTextureAddressMode::WRAP; RenderTextureAddressMode addressU = RenderTextureAddressMode::CLAMP;
RenderTextureAddressMode addressV = RenderTextureAddressMode::WRAP; RenderTextureAddressMode addressV = RenderTextureAddressMode::CLAMP;
RenderTextureAddressMode addressW = RenderTextureAddressMode::WRAP; RenderTextureAddressMode addressW = RenderTextureAddressMode::CLAMP;
float mipLODBias = 0.0f; float mipLODBias = 0.0f;
uint32_t maxAnisotropy = 16; uint32_t maxAnisotropy = 16;
bool anisotropyEnabled = false; bool anisotropyEnabled = false;
@@ -1,4 +1,4 @@
#include "../../../tools/ShaderRecomp/ShaderRecomp/shader_common.h" #include "../../../tools/XenosRecomp/XenosRecomp/shader_common.h"
#ifdef __spirv__ #ifdef __spirv__
@@ -1,4 +1,4 @@
#include "../../../tools/ShaderRecomp/ShaderRecomp/shader_common.h" #include "../../../tools/XenosRecomp/XenosRecomp/shader_common.h"
#ifdef __spirv__ #ifdef __spirv__
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../../../tools/ShaderRecomp/ShaderRecomp/shader_common.h" #include "../../../tools/XenosRecomp/XenosRecomp/shader_common.h"
#ifdef __spirv__ #ifdef __spirv__
@@ -1,4 +1,4 @@
#include "../../../tools/ShaderRecomp/ShaderRecomp/shader_common.h" #include "../../../tools/XenosRecomp/XenosRecomp/shader_common.h"
#ifdef __spirv__ #ifdef __spirv__
@@ -1,4 +1,4 @@
#include "../../../tools/ShaderRecomp/ShaderRecomp/shader_common.h" #include "../../../tools/XenosRecomp/XenosRecomp/shader_common.h"
#ifdef __spirv__ #ifdef __spirv__
@@ -1,4 +1,4 @@
#include "../../../tools/ShaderRecomp/ShaderRecomp/shader_common.h" #include "../../../tools/XenosRecomp/XenosRecomp/shader_common.h"
#ifdef __spirv__ #ifdef __spirv__
@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "../../../tools/ShaderRecomp/ShaderRecomp/shader_common.h" #include "../../../tools/XenosRecomp/XenosRecomp/shader_common.h"
#ifdef __spirv__ #ifdef __spirv__
+81 -67
View File
@@ -10,7 +10,7 @@
#include <decompressor.h> #include <decompressor.h>
#include <kernel/function.h> #include <kernel/function.h>
#include <kernel/heap.h> #include <kernel/heap.h>
#include <hid/hid_detail.h> #include <hid/hid.h>
#include <kernel/memory.h> #include <kernel/memory.h>
#include <kernel/xdbf.h> #include <kernel/xdbf.h>
#include <res/bc_diff/button_bc_diff.bin.h> #include <res/bc_diff/button_bc_diff.bin.h>
@@ -34,9 +34,9 @@
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>
#endif #endif
#include "../../tools/ShaderRecomp/ShaderRecomp/shader_common.h" #include "../../tools/XenosRecomp/XenosRecomp/shader_common.h"
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
#include "shader/copy_vs.hlsl.dxil.h" #include "shader/copy_vs.hlsl.dxil.h"
#include "shader/csd_filter_ps.hlsl.dxil.h" #include "shader/csd_filter_ps.hlsl.dxil.h"
#include "shader/csd_no_tex_vs.hlsl.dxil.h" #include "shader/csd_no_tex_vs.hlsl.dxil.h"
@@ -84,7 +84,7 @@ extern "C"
namespace plume namespace plume
{ {
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
extern std::unique_ptr<RenderInterface> CreateD3D12Interface(); extern std::unique_ptr<RenderInterface> CreateD3D12Interface();
#endif #endif
#ifdef SDL_VULKAN_ENABLED #ifdef SDL_VULKAN_ENABLED
@@ -198,7 +198,7 @@ static void SetDirtyValue(bool& dirtyState, T& dest, const T& src)
} }
} }
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
static bool g_vulkan = false; static bool g_vulkan = false;
#else #else
static constexpr bool g_vulkan = true; static constexpr bool g_vulkan = true;
@@ -619,7 +619,7 @@ static void LoadEmbeddedResources()
g_shaderCache = std::make_unique<uint8_t[]>(g_spirvCacheDecompressedSize); g_shaderCache = std::make_unique<uint8_t[]>(g_spirvCacheDecompressedSize);
ZSTD_decompress(g_shaderCache.get(), g_spirvCacheDecompressedSize, g_compressedSpirvCache, g_spirvCacheCompressedSize); ZSTD_decompress(g_shaderCache.get(), g_spirvCacheDecompressedSize, g_compressedSpirvCache, g_spirvCacheCompressedSize);
} }
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
else else
{ {
g_shaderCache = std::make_unique<uint8_t[]>(g_dxilCacheDecompressedSize); g_shaderCache = std::make_unique<uint8_t[]>(g_dxilCacheDecompressedSize);
@@ -1111,7 +1111,7 @@ static GuestShader* g_csdShader;
static std::unique_ptr<GuestShader> g_enhancedMotionBlurShader; static std::unique_ptr<GuestShader> g_enhancedMotionBlurShader;
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
#define CREATE_SHADER(NAME) \ #define CREATE_SHADER(NAME) \
g_device->createShader( \ g_device->createShader( \
@@ -1123,7 +1123,7 @@ static std::unique_ptr<GuestShader> g_enhancedMotionBlurShader;
#else #else
#define CREATE_SHADER(NAME) \ #define CREATE_SHADER(NAME) \
g_device->createShader(g_##NAME##_spirv, sizeof(g_##NAME##_spirv), "main", RenderShaderFormat::SPIRV); g_device->createShader(g_##NAME##_spirv, sizeof(g_##NAME##_spirv), "main", RenderShaderFormat::SPIRV)
#endif #endif
@@ -1141,6 +1141,7 @@ static constexpr size_t SAMPLER_DESCRIPTOR_SIZE = 1024;
static std::unique_ptr<GuestTexture> g_imFontTexture; static std::unique_ptr<GuestTexture> g_imFontTexture;
static std::unique_ptr<RenderPipelineLayout> g_imPipelineLayout; static std::unique_ptr<RenderPipelineLayout> g_imPipelineLayout;
static std::unique_ptr<RenderPipeline> g_imPipeline; static std::unique_ptr<RenderPipeline> g_imPipeline;
static std::unique_ptr<RenderPipeline> g_imAdditivePipeline;
template<typename T> template<typename T>
static void ExecuteCopyCommandList(const T& function) static void ExecuteCopyCommandList(const T& function)
@@ -1309,6 +1310,9 @@ static void CreateImGuiBackend()
pipelineDesc.inputSlotsCount = 1; pipelineDesc.inputSlotsCount = 1;
g_imPipeline = g_device->createGraphicsPipeline(pipelineDesc); g_imPipeline = g_device->createGraphicsPipeline(pipelineDesc);
pipelineDesc.renderTargetBlend[0].dstBlend = RenderBlend::ONE;
g_imAdditivePipeline = g_device->createGraphicsPipeline(pipelineDesc);
#ifndef ENABLE_IM_FONT_ATLAS_SNAPSHOT #ifndef ENABLE_IM_FONT_ATLAS_SNAPSHOT
ImFontAtlasSnapshot snapshot; ImFontAtlasSnapshot snapshot;
snapshot.Snap(); snapshot.Snap();
@@ -1355,16 +1359,8 @@ static void CheckSwapChain()
if (g_needsResize) if (g_needsResize)
Video::ComputeViewportDimensions(); Video::ComputeViewportDimensions();
if (g_aspectRatio >= NARROW_ASPECT_RATIO) g_backBuffer->width = Video::s_viewportWidth;
{ g_backBuffer->height = Video::s_viewportHeight;
g_backBuffer->width = Video::s_viewportWidth * 720 / Video::s_viewportHeight;
g_backBuffer->height = 720;
}
else
{
g_backBuffer->width = 960;
g_backBuffer->height = Video::s_viewportHeight * 960 / Video::s_viewportWidth;
}
} }
static void BeginCommandList() static void BeginCommandList()
@@ -1448,7 +1444,7 @@ void Video::CreateHostDevice(const char *sdlVideoDriver)
GameWindow::Init(sdlVideoDriver); GameWindow::Init(sdlVideoDriver);
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
g_vulkan = DetectWine() || Config::GraphicsAPI == EGraphicsAPI::Vulkan; g_vulkan = DetectWine() || Config::GraphicsAPI == EGraphicsAPI::Vulkan;
#endif #endif
@@ -1460,7 +1456,7 @@ void Video::CreateHostDevice(const char *sdlVideoDriver)
#else #else
g_interface = CreateVulkanInterface(); g_interface = CreateVulkanInterface();
#endif #endif
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
else else
g_interface = CreateD3D12Interface(); g_interface = CreateD3D12Interface();
#endif #endif
@@ -2099,9 +2095,10 @@ static void ProcDrawImGui(const RenderCommand& cmd)
SetFramebuffer(g_backBuffer, nullptr, false); SetFramebuffer(g_backBuffer, nullptr, false);
auto& commandList = g_commandLists[g_frame]; auto& commandList = g_commandLists[g_frame];
auto pipeline = g_imPipeline.get();
commandList->setGraphicsPipelineLayout(g_imPipelineLayout.get()); commandList->setGraphicsPipelineLayout(g_imPipelineLayout.get());
commandList->setPipeline(g_imPipeline.get()); commandList->setPipeline(pipeline);
commandList->setGraphicsDescriptorSet(g_textureDescriptorSet.get(), 0); commandList->setGraphicsDescriptorSet(g_textureDescriptorSet.get(), 0);
commandList->setGraphicsDescriptorSet(g_samplerDescriptorSet.get(), 1); commandList->setGraphicsDescriptorSet(g_samplerDescriptorSet.get(), 1);
@@ -2175,6 +2172,16 @@ static void ProcDrawImGui(const RenderCommand& cmd)
case ImGuiCallback::SetProceduralOrigin: case ImGuiCallback::SetProceduralOrigin:
setPushConstants(&pushConstants.proceduralOrigin, &callbackData->setProceduralOrigin, sizeof(callbackData->setProceduralOrigin)); setPushConstants(&pushConstants.proceduralOrigin, &callbackData->setProceduralOrigin, sizeof(callbackData->setProceduralOrigin));
break; break;
case ImGuiCallback::SetAdditive:
{
auto pipelineToSet = callbackData->setAdditive.enabled ? g_imAdditivePipeline.get() : g_imPipeline.get();
if (pipeline != pipelineToSet)
{
commandList->setPipeline(pipelineToSet);
pipeline = pipelineToSet;
}
break;
}
default: default:
assert(false && "Unknown ImGui callback type."); assert(false && "Unknown ImGui callback type.");
break; break;
@@ -2456,11 +2463,6 @@ static GuestSurface* GetBackBuffer()
return g_backBuffer; return g_backBuffer;
} }
GuestSurface* Video::GetBackBuffer()
{
return g_backBuffer;
}
void Video::ComputeViewportDimensions() void Video::ComputeViewportDimensions()
{ {
uint32_t width = g_swapChain->getWidth(); uint32_t width = g_swapChain->getWidth();
@@ -2663,9 +2665,6 @@ static GuestSurface* CreateSurface(uint32_t width, uint32_t height, uint32_t for
static void FlushViewport() static void FlushViewport()
{ {
bool renderingToBackBuffer = g_renderTarget == g_backBuffer &&
g_backBuffer->texture != g_backBuffer->textureHolder.get();
auto& commandList = g_commandLists[g_frame]; auto& commandList = g_commandLists[g_frame];
if (g_dirtyStates.viewport) if (g_dirtyStates.viewport)
@@ -2677,17 +2676,6 @@ static void FlushViewport()
viewport.y += 0.5f; viewport.y += 0.5f;
} }
if (renderingToBackBuffer)
{
float width = Video::s_viewportWidth;
float height = Video::s_viewportHeight;
viewport.x *= width / g_backBuffer->width;
viewport.y *= height / g_backBuffer->height;
viewport.width *= width / g_backBuffer->width;
viewport.height *= height / g_backBuffer->height;
}
if (viewport.minDepth > viewport.maxDepth) if (viewport.minDepth > viewport.maxDepth)
std::swap(viewport.minDepth, viewport.maxDepth); std::swap(viewport.minDepth, viewport.maxDepth);
@@ -2704,17 +2692,6 @@ static void FlushViewport()
g_viewport.x + g_viewport.width, g_viewport.x + g_viewport.width,
g_viewport.y + g_viewport.height); g_viewport.y + g_viewport.height);
if (renderingToBackBuffer)
{
uint32_t width = Video::s_viewportWidth;
uint32_t height = Video::s_viewportHeight;
scissorRect.left = scissorRect.left * width / g_backBuffer->width;
scissorRect.top = scissorRect.top * height / g_backBuffer->height;
scissorRect.right = scissorRect.right * width / g_backBuffer->width;
scissorRect.bottom = scissorRect.bottom * height / g_backBuffer->height;
}
commandList->setScissors(scissorRect); commandList->setScissors(scissorRect);
g_dirtyStates.scissorRect = false; g_dirtyStates.scissorRect = false;
@@ -2818,7 +2795,10 @@ static void ProcStretchRect(const RenderCommand& cmd)
g_dirtyStates.pipelineState = true; g_dirtyStates.pipelineState = true;
if (g_vulkan) if (g_vulkan)
{
g_dirtyStates.depthBias = true; // Static depth bias in MSAA pipeline invalidates dynamic depth bias.
g_dirtyStates.vertexShaderConstants = true; g_dirtyStates.vertexShaderConstants = true;
}
SetHalfPixel(oldHalfPixel); SetHalfPixel(oldHalfPixel);
} }
@@ -3052,7 +3032,7 @@ static void SetTexture(GuestDevice* device, uint32_t index, GuestTexture* textur
auto isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation; auto isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation;
if (Config::ControllerIcons == EControllerIcons::Auto) if (Config::ControllerIcons == EControllerIcons::Auto)
isPlayStation = hid::detail::g_inputDeviceController == hid::detail::EInputDevice::PlayStation; isPlayStation = hid::g_inputDeviceController == hid::EInputDevice::PlayStation;
if (isPlayStation && texture != nullptr && texture->patchedTexture != nullptr) if (isPlayStation && texture != nullptr && texture->patchedTexture != nullptr)
texture = texture->patchedTexture.get(); texture = texture->patchedTexture.get();
@@ -3143,7 +3123,7 @@ static RenderShader* GetOrLinkShader(GuestShader* guestShader, uint32_t specCons
shader = guestShader->linkedShaders[specConstants].get(); shader = guestShader->linkedShaders[specConstants].get();
} }
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
if (shader == nullptr) if (shader == nullptr)
{ {
static Mutex g_compiledSpecConstantLibraryBlobMutex; static Mutex g_compiledSpecConstantLibraryBlobMutex;
@@ -4387,16 +4367,33 @@ static void ProcSetPixelShader(const RenderCommand& cmd)
default: default:
{ {
size_t height = round(Video::s_viewportHeight * Config::ResolutionScale); if (g_aspectRatio >= WIDE_ASPECT_RATIO)
{
size_t height = round(Video::s_viewportHeight * Config::ResolutionScale);
if (height > 1440) if (height > 1440)
shaderIndex = GAUSSIAN_BLUR_9X9; shaderIndex = GAUSSIAN_BLUR_9X9;
else if (height > 1080) else if (height > 1080)
shaderIndex = GAUSSIAN_BLUR_7X7; shaderIndex = GAUSSIAN_BLUR_7X7;
else if (height > 720) else if (height > 720)
shaderIndex = GAUSSIAN_BLUR_5X5; shaderIndex = GAUSSIAN_BLUR_5X5;
else
shaderIndex = GAUSSIAN_BLUR_3X3;
}
else else
shaderIndex = GAUSSIAN_BLUR_3X3; {
// Narrow aspect ratios should check for width to account for VERT+.
size_t width = round(Video::s_viewportWidth * Config::ResolutionScale);
if (width > 2560)
shaderIndex = GAUSSIAN_BLUR_9X9;
else if (width > 1920)
shaderIndex = GAUSSIAN_BLUR_7X7;
else if (width > 1280)
shaderIndex = GAUSSIAN_BLUR_5X5;
else
shaderIndex = GAUSSIAN_BLUR_3X3;
}
break; break;
} }
@@ -5124,23 +5121,40 @@ PPC_FUNC(sub_8258CAE0)
g_renderDirectorProfiler.End(); g_renderDirectorProfiler.End();
} }
// World map disables VERT+, so scaling by width does not work for it.
static uint32_t g_forceCheckHeightForPostProcessFix;
// SWA::CWorldMapCamera::CWorldMapCamera
PPC_FUNC_IMPL(__imp__sub_824860E0);
PPC_FUNC(sub_824860E0)
{
++g_forceCheckHeightForPostProcessFix;
__imp__sub_824860E0(ctx, base);
}
// SWA::CCameraController::~CCameraController
PPC_FUNC_IMPL(__imp__sub_824831D0);
PPC_FUNC(sub_824831D0)
{
if (PPC_LOAD_U32(ctx.r3.u32) == 0x8202BF1C) // SWA::CWorldMapCamera
--g_forceCheckHeightForPostProcessFix;
__imp__sub_824831D0(ctx, base);
}
void PostProcessResolutionFix(PPCRegister& r4, PPCRegister& f1, PPCRegister& f2) void PostProcessResolutionFix(PPCRegister& r4, PPCRegister& f1, PPCRegister& f2)
{ {
auto device = reinterpret_cast<be<uint32_t>*>(g_memory.Translate(r4.u32)); auto device = reinterpret_cast<be<uint32_t>*>(g_memory.Translate(r4.u32));
uint32_t width = device[46].get(); uint32_t width = device[46].get();
uint32_t height = device[47].get(); uint32_t height = device[47].get();
double aspectRatio = double(width) / double(height);
#if 0
// TODO: Figure out why this breaks for height > weight
double factor; double factor;
if (width > height) if ((aspectRatio >= WIDE_ASPECT_RATIO) || (g_forceCheckHeightForPostProcessFix != 0))
factor = 720.0 / double(height); factor = 720.0 / double(height);
else else
factor = 1280.0 / double(width); factor = 1280.0 / double(width);
#else
double factor = 720.0 / double(height);
#endif
f1.f64 *= factor; f1.f64 *= factor;
f2.f64 *= factor; f2.f64 *= factor;
+1 -2
View File
@@ -23,7 +23,6 @@ struct Video
static void Present(); static void Present();
static void StartPipelinePrecompilation(); static void StartPipelinePrecompilation();
static void WaitForGPU(); static void WaitForGPU();
static struct GuestSurface* GetBackBuffer();
static void ComputeViewportDimensions(); static void ComputeViewportDimensions();
}; };
@@ -286,7 +285,7 @@ struct GuestShader : GuestResource
std::unique_ptr<RenderShader> shader; std::unique_ptr<RenderShader> shader;
struct ShaderCacheEntry* shaderCacheEntry = nullptr; struct ShaderCacheEntry* shaderCacheEntry = nullptr;
ankerl::unordered_dense::map<uint32_t, std::unique_ptr<RenderShader>> linkedShaders; ankerl::unordered_dense::map<uint32_t, std::unique_ptr<RenderShader>> linkedShaders;
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
std::vector<ComPtr<IDxcBlob>> shaderBlobs; std::vector<ComPtr<IDxcBlob>> shaderBlobs;
ComPtr<IDxcBlobEncoding> libraryBlob; ComPtr<IDxcBlobEncoding> libraryBlob;
#endif #endif
+23 -12
View File
@@ -1,7 +1,8 @@
#include <stdafx.h> #include <stdafx.h>
#include <SDL.h> #include <SDL.h>
#include <user/config.h> #include <user/config.h>
#include <hid/hid_detail.h> #include <hid/hid.h>
#include <os/logger.h>
#include <ui/game_window.h> #include <ui/game_window.h>
#include <kernel/xdm.h> #include <kernel/xdm.h>
#include <app.h> #include <app.h>
@@ -40,17 +41,17 @@ public:
return SDL_GameControllerTypeForIndex(index); return SDL_GameControllerTypeForIndex(index);
} }
hid::detail::EInputDevice GetInputDevice() const hid::EInputDevice GetInputDevice() const
{ {
switch (GetControllerType()) switch (GetControllerType())
{ {
case SDL_CONTROLLER_TYPE_PS3: case SDL_CONTROLLER_TYPE_PS3:
case SDL_CONTROLLER_TYPE_PS4: case SDL_CONTROLLER_TYPE_PS4:
case SDL_CONTROLLER_TYPE_PS5: case SDL_CONTROLLER_TYPE_PS5:
return hid::detail::EInputDevice::PlayStation; return hid::EInputDevice::PlayStation;
} }
return hid::detail::EInputDevice::Xbox; return hid::EInputDevice::Xbox;
} }
void Close() void Close()
@@ -168,8 +169,17 @@ static void SetControllerInputDevice(Controller* controller)
if (App::s_isLoading) if (App::s_isLoading)
return; return;
hid::detail::g_inputDevice = controller->GetInputDevice(); hid::g_inputDevice = controller->GetInputDevice();
hid::detail::g_inputDeviceController = hid::detail::g_inputDevice; hid::g_inputDeviceController = hid::g_inputDevice;
auto controllerType = (hid::EInputDeviceExplicit)controller->GetControllerType();
if (hid::g_inputDeviceExplicit != controllerType)
{
hid::g_inputDeviceExplicit = controllerType;
LOGFN("Detected controller: {}", hid::GetInputDeviceName());
}
} }
int HID_OnSDLEvent(void*, SDL_Event* event) int HID_OnSDLEvent(void*, SDL_Event* event)
@@ -199,6 +209,7 @@ int HID_OnSDLEvent(void*, SDL_Event* event)
case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP: case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERAXISMOTION: case SDL_CONTROLLERAXISMOTION:
case SDL_CONTROLLERTOUCHPADDOWN:
{ {
auto* controller = FindController(event->cdevice.which); auto* controller = FindController(event->cdevice.which);
@@ -224,13 +235,13 @@ int HID_OnSDLEvent(void*, SDL_Event* event)
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: case SDL_KEYUP:
hid::detail::g_inputDevice = hid::detail::EInputDevice::Keyboard; hid::g_inputDevice = hid::EInputDevice::Keyboard;
break; break;
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
hid::detail::g_inputDevice = hid::detail::EInputDevice::Mouse; hid::g_inputDevice = hid::EInputDevice::Mouse;
break; break;
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
@@ -266,7 +277,7 @@ int HID_OnSDLEvent(void*, SDL_Event* event)
return 0; return 0;
} }
void hid::detail::Init() void hid::Init()
{ {
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1");
@@ -282,7 +293,7 @@ void hid::detail::Init()
SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
} }
uint32_t hid::detail::GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState) uint32_t hid::GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState)
{ {
static uint32_t packet; static uint32_t packet;
@@ -301,7 +312,7 @@ uint32_t hid::detail::GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState)
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
uint32_t hid::detail::SetState(uint32_t dwUserIndex, XAMINPUT_VIBRATION* pVibration) uint32_t hid::SetState(uint32_t dwUserIndex, XAMINPUT_VIBRATION* pVibration)
{ {
if (!pVibration) if (!pVibration)
return ERROR_BAD_ARGUMENTS; return ERROR_BAD_ARGUMENTS;
@@ -314,7 +325,7 @@ uint32_t hid::detail::SetState(uint32_t dwUserIndex, XAMINPUT_VIBRATION* pVibrat
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
uint32_t hid::detail::GetCapabilities(uint32_t dwUserIndex, XAMINPUT_CAPABILITIES* pCaps) uint32_t hid::GetCapabilities(uint32_t dwUserIndex, XAMINPUT_CAPABILITIES* pCaps)
{ {
if (!pCaps) if (!pCaps)
return ERROR_BAD_ARGUMENTS; return ERROR_BAD_ARGUMENTS;
+59 -24
View File
@@ -1,39 +1,74 @@
#include <stdafx.h>
#include "hid.h" #include "hid.h"
#include "hid_detail.h"
hid::detail::EInputDevice hid::detail::g_inputDevice; hid::EInputDevice hid::g_inputDevice;
hid::detail::EInputDevice hid::detail::g_inputDeviceController; hid::EInputDevice hid::g_inputDeviceController;
hid::EInputDeviceExplicit hid::g_inputDeviceExplicit;
uint16_t hid::detail::g_prohibitedButtons; uint16_t hid::g_prohibitedButtons;
void hid::Init()
{
detail::Init();
}
void hid::SetProhibitedButtons(uint16_t wButtons) void hid::SetProhibitedButtons(uint16_t wButtons)
{ {
hid::detail::g_prohibitedButtons = wButtons; hid::g_prohibitedButtons = wButtons;
} }
uint32_t hid::GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState) bool hid::IsInputDeviceController()
{ {
return detail::GetState(dwUserIndex, pState); return hid::g_inputDevice != hid::EInputDevice::Keyboard &&
hid::g_inputDevice != hid::EInputDevice::Mouse;
} }
uint32_t hid::SetState(uint32_t dwUserIndex, XAMINPUT_VIBRATION* pVibration) std::string hid::GetInputDeviceName()
{ {
return detail::SetState(dwUserIndex, pVibration); switch (g_inputDevice)
} {
case EInputDevice::Keyboard:
return "Keyboard";
uint32_t hid::GetCapabilities(uint32_t dwUserIndex, XAMINPUT_CAPABILITIES* pCaps) case EInputDevice::Mouse:
{ return "Mouse";
return detail::GetCapabilities(dwUserIndex, pCaps); }
}
bool hid::detail::IsInputDeviceController() switch (g_inputDeviceExplicit)
{ {
return hid::detail::g_inputDevice != hid::detail::EInputDevice::Keyboard && case EInputDeviceExplicit::Xbox360:
hid::detail::g_inputDevice != hid::detail::EInputDevice::Mouse; return "Xbox 360";
case EInputDeviceExplicit::XboxOne:
return "Xbox One";
case EInputDeviceExplicit::DualShock3:
return "DualShock 3";
case EInputDeviceExplicit::DualShock4:
return "DualShock 4";
case EInputDeviceExplicit::SwitchPro:
return "Nintendo Switch Pro";
case EInputDeviceExplicit::Virtual:
return "Virtual";
case EInputDeviceExplicit::DualSense:
return "DualSense";
case EInputDeviceExplicit::Luna:
return "Amazon Luna";
case EInputDeviceExplicit::Stadia:
return "Google Stadia";
case EInputDeviceExplicit::NvShield:
return "NVIDIA Shield";
case EInputDeviceExplicit::SwitchJCLeft:
return "Nintendo Switch Joy-Con (Left)";
case EInputDeviceExplicit::SwitchJCRight:
return "Nintendo Switch Joy-Con (Right)";
case EInputDeviceExplicit::SwitchJCPair:
return "Nintendo Switch Joy-Con (Pair)";
}
return "Unknown";
} }
+35 -2
View File
@@ -1,13 +1,46 @@
#pragma once #pragma once
union SDL_Event;
namespace hid namespace hid
{ {
enum class EInputDevice
{
Keyboard,
Mouse,
Xbox,
PlayStation
};
enum class EInputDeviceExplicit
{
Unknown,
Xbox360,
XboxOne,
DualShock3,
DualShock4,
SwitchPro,
Virtual,
DualSense,
Luna,
Stadia,
NvShield,
SwitchJCLeft,
SwitchJCRight,
SwitchJCPair
};
extern EInputDevice g_inputDevice;
extern EInputDevice g_inputDeviceController;
extern EInputDeviceExplicit g_inputDeviceExplicit;
extern uint16_t g_prohibitedButtons;
void Init(); void Init();
void SetProhibitedButtons(uint16_t wButtons); void SetProhibitedButtons(uint16_t wButtons);
uint32_t GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState); uint32_t GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState);
uint32_t SetState(uint32_t dwUserIndex, XAMINPUT_VIBRATION* pVibration); uint32_t SetState(uint32_t dwUserIndex, XAMINPUT_VIBRATION* pVibration);
uint32_t GetCapabilities(uint32_t dwUserIndex, XAMINPUT_CAPABILITIES* pCaps); uint32_t GetCapabilities(uint32_t dwUserIndex, XAMINPUT_CAPABILITIES* pCaps);
bool IsInputDeviceController();
std::string GetInputDeviceName();
} }
-25
View File
@@ -1,25 +0,0 @@
#pragma once
namespace hid::detail
{
enum class EInputDevice
{
Keyboard,
Mouse,
Xbox,
PlayStation
};
extern EInputDevice g_inputDevice;
extern EInputDevice g_inputDeviceController;
extern uint16_t g_prohibitedButtons;
void Init();
uint32_t GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState);
uint32_t SetState(uint32_t dwUserIndex, XAMINPUT_VIBRATION* pVibration);
uint32_t GetCapabilities(uint32_t dwUserIndex, XAMINPUT_CAPABILITIES* pCaps);
bool IsInputDeviceController();
}
+25 -24
View File
@@ -2,7 +2,6 @@
#include "xam.h" #include "xam.h"
#include "xdm.h" #include "xdm.h"
#include <hid/hid.h> #include <hid/hid.h>
#include <hid/hid_detail.h>
#include <ui/game_window.h> #include <ui/game_window.h>
#include <cpu/guest_thread.h> #include <cpu/guest_thread.h>
#include <ranges> #include <ranges>
@@ -11,12 +10,6 @@
#include <user/paths.h> #include <user/paths.h>
#include <SDL.h> #include <SDL.h>
#ifdef _WIN32
#include <CommCtrl.h>
// Needed for commctrl
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
struct XamListener : KernelObject struct XamListener : KernelObject
{ {
uint32_t id{}; uint32_t id{};
@@ -208,11 +201,15 @@ bool XNotifyGetNext(uint32_t hNotification, uint32_t dwMsgFilter, be<uint32_t>*
uint32_t XamShowMessageBoxUI(uint32_t dwUserIndex, be<uint16_t>* wszTitle, be<uint16_t>* wszText, uint32_t cButtons, uint32_t XamShowMessageBoxUI(uint32_t dwUserIndex, be<uint16_t>* wszTitle, be<uint16_t>* wszText, uint32_t cButtons,
xpointer<be<uint16_t>>* pwszButtons, uint32_t dwFocusButton, uint32_t dwFlags, be<uint32_t>* pResult, XXOVERLAPPED* pOverlapped) xpointer<be<uint16_t>>* pwszButtons, uint32_t dwFocusButton, uint32_t dwFlags, be<uint32_t>* pResult, XXOVERLAPPED* pOverlapped)
{ {
int button{}; *pResult = cButtons ? cButtons - 1 : 0;
#ifdef _WIN32 #if _DEBUG
assert("XamShowMessageBoxUI encountered!" && false);
#elif _WIN32
// This code is Win32-only as it'll most likely crash, misbehave or
// cause corruption due to using a different type of memory than what
// wchar_t is on Linux. Windows uses 2 bytes while Linux uses 4 bytes.
std::vector<std::wstring> texts{}; std::vector<std::wstring> texts{};
std::vector<TASKDIALOG_BUTTON> buttons{};
texts.emplace_back(reinterpret_cast<wchar_t*>(wszTitle)); texts.emplace_back(reinterpret_cast<wchar_t*>(wszTitle));
texts.emplace_back(reinterpret_cast<wchar_t*>(wszText)); texts.emplace_back(reinterpret_cast<wchar_t*>(wszText));
@@ -226,23 +223,27 @@ uint32_t XamShowMessageBoxUI(uint32_t dwUserIndex, be<uint16_t>* wszTitle, be<ui
ByteSwapInplace(text[i]); ByteSwapInplace(text[i]);
} }
wprintf(L"[XamShowMessageBoxUI] !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
wprintf(L"[XamShowMessageBoxUI] If you are encountering this message and the game has ceased functioning,\n");
wprintf(L"[XamShowMessageBoxUI] please create an issue at https://github.com/hedge-dev/UnleashedRecomp/issues.\n");
wprintf(L"[XamShowMessageBoxUI] !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
wprintf(L"[XamShowMessageBoxUI] %ls\n", texts[0].c_str());
wprintf(L"[XamShowMessageBoxUI] %ls\n", texts[1].c_str());
wprintf(L"[XamShowMessageBoxUI] ");
for (size_t i = 0; i < cButtons; i++) for (size_t i = 0; i < cButtons; i++)
buttons.emplace_back(i, texts[2 + i].c_str()); {
wprintf(L"%ls", texts[2 + i].c_str());
XamNotifyEnqueueEvent(9, 1); if (i != cButtons - 1)
wprintf(L" | ");
}
TASKDIALOGCONFIG config{}; wprintf(L"\n");
config.cbSize = sizeof(config); wprintf(L"[XamShowMessageBoxUI] Defaulted to button: %d\n", pResult->get());
config.pszWindowTitle = texts[0].c_str(); wprintf(L"[XamShowMessageBoxUI] !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
config.pszContent = texts[1].c_str();
config.cButtons = cButtons;
config.pButtons = buttons.data();
TaskDialogIndirect(&config, &button, nullptr, nullptr);
#endif #endif
*pResult = button;
if (pOverlapped) if (pOverlapped)
{ {
pOverlapped->dwCompletionContext = GuestThread::GetCurrentThreadId(); pOverlapped->dwCompletionContext = GuestThread::GetCurrentThreadId();
@@ -453,7 +454,7 @@ uint32_t XamInputGetState(uint32_t userIndex, uint32_t flags, XAMINPUT_STATE* st
state->Gamepad.wButtons |= XAMINPUT_GAMEPAD_Y; state->Gamepad.wButtons |= XAMINPUT_GAMEPAD_Y;
} }
state->Gamepad.wButtons &= ~hid::detail::g_prohibitedButtons; state->Gamepad.wButtons &= ~hid::g_prohibitedButtons;
ByteSwapInplace(state->Gamepad.wButtons); ByteSwapInplace(state->Gamepad.wButtons);
ByteSwapInplace(state->Gamepad.sThumbLX); ByteSwapInplace(state->Gamepad.sThumbLX);
@@ -466,7 +467,7 @@ uint32_t XamInputGetState(uint32_t userIndex, uint32_t flags, XAMINPUT_STATE* st
uint32_t XamInputSetState(uint32_t userIndex, uint32_t flags, XAMINPUT_VIBRATION* vibration) uint32_t XamInputSetState(uint32_t userIndex, uint32_t flags, XAMINPUT_VIBRATION* vibration)
{ {
if (!hid::detail::IsInputDeviceController() || !Config::Vibration) if (!hid::IsInputDeviceController() || !Config::Vibration)
return ERROR_SUCCESS; return ERROR_SUCCESS;
ByteSwapInplace(vibration->wLeftMotorSpeed); ByteSwapInplace(vibration->wLeftMotorSpeed);
+18 -7
View File
@@ -19,10 +19,10 @@
*/ */
#define CONFIG_DEFINE_LOCALE(name) \ #define CONFIG_DEFINE_LOCALE(name) \
CONFIG_LOCALE Config::g_##name##_locale = CONFIG_LOCALE g_##name##_locale =
#define CONFIG_DEFINE_ENUM_LOCALE(type) \ #define CONFIG_DEFINE_ENUM_LOCALE(type) \
CONFIG_ENUM_LOCALE(type) Config::g_##type##_locale = CONFIG_ENUM_LOCALE(type) g_##type##_locale =
CONFIG_DEFINE_LOCALE(Language) CONFIG_DEFINE_LOCALE(Language)
{ {
@@ -117,11 +117,6 @@ CONFIG_DEFINE_LOCALE(AllowBackgroundInput)
{ ELanguage::English, { "Allow Background Input", "Allow controller input whilst the game window is unfocused." } } { ELanguage::English, { "Allow Background Input", "Allow controller input whilst the game window is unfocused." } }
}; };
CONFIG_DEFINE_LOCALE(AllowDPadMovement)
{
{ ELanguage::English, { "Allow D-Pad Movement", "Allow the player to also be controlled using the directional pad." } }
};
CONFIG_DEFINE_LOCALE(MasterVolume) CONFIG_DEFINE_LOCALE(MasterVolume)
{ {
{ ELanguage::English, { "Master Volume", "Adjust the overall volume." } } { ELanguage::English, { "Master Volume", "Adjust the overall volume." } }
@@ -142,6 +137,22 @@ CONFIG_DEFINE_LOCALE(MusicAttenuation)
{ ELanguage::English, { "Music Attenuation", "Fade out the game's music when external media is playing." } } { ELanguage::English, { "Music Attenuation", "Fade out the game's music when external media is playing." } }
}; };
CONFIG_DEFINE_LOCALE(ChannelConfiguration)
{
{ ELanguage::English, { "Channel Configuration", "" } }
};
CONFIG_DEFINE_ENUM_LOCALE(EChannelConfiguration)
{
{
ELanguage::English,
{
{ EChannelConfiguration::Stereo, { "STEREO", "" } },
{ EChannelConfiguration::Surround, { "SURROUND", "" } }
}
}
};
CONFIG_DEFINE_LOCALE(VoiceLanguage) CONFIG_DEFINE_LOCALE(VoiceLanguage)
{ {
{ ELanguage::English, { "Voice Language", "Change the language used for character voices." } } { ELanguage::English, { "Voice Language", "Change the language used for character voices." } }
+14
View File
@@ -342,6 +342,20 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
{ ELanguage::Italian, "Sei sicuro di voler uscire?" } { ELanguage::Italian, "Sei sicuro di voler uscire?" }
} }
}, },
{
// Notes: message appears when the SYS-DATA is corrupted (mismatching file size).
// To make this occur, open the file in any editor and just remove a large chunk of data.
// Do not localise this unless absolutely necessary, these strings are from the XEX.
"Title_Message_SaveDataCorrupt",
{
{ ELanguage::English, "The save file appears to be\ncorrupted and cannot be loaded." },
{ ELanguage::Japanese, "ゲームデータの読み込みに失敗しました。\nこのまま続けるとゲームデータをセーブすることはできません" },
{ ELanguage::German, "Diese Speicherdatei ist beschädigt\nund kann nicht geladen werden." },
{ ELanguage::French, "Le fichier de sauvegarde semble être\nendommagé et ne peut être chargé." },
{ ELanguage::Spanish, "El archivo parece estar dañado\ny no se puede cargar." },
{ ELanguage::Italian, "I file di salvataggio sembrano danneggiati\ne non possono essere caricati." }
}
},
{ {
"Common_On", "Common_On",
{ {
+3 -3
View File
@@ -26,9 +26,6 @@ static std::vector<Mod> g_mods;
std::filesystem::path ModLoader::ResolvePath(std::string_view path) std::filesystem::path ModLoader::ResolvePath(std::string_view path)
{ {
if (g_mods.empty())
return {};
std::string_view root; std::string_view root;
size_t sepIndex = path.find(":\\"); size_t sepIndex = path.find(":\\");
@@ -51,6 +48,9 @@ std::filesystem::path ModLoader::ResolvePath(std::string_view path)
return {}; return {};
} }
if (g_mods.empty())
return {};
thread_local xxHashMap<std::filesystem::path> s_cache; thread_local xxHashMap<std::filesystem::path> s_cache;
XXH64_hash_t hash = XXH3_64bits(path.data(), path.size()); XXH64_hash_t hash = XXH3_64bits(path.data(), path.size());
+3 -3
View File
@@ -1,10 +1,10 @@
#include <os/logger_detail.h> #include <os/logger.h>
void os::logger::detail::Init() void os::logger::Init()
{ {
} }
void os::logger::detail::Log(const std::string_view str, detail::ELogType type, const char* func) void os::logger::Log(const std::string_view str, ELogType type, const char* func)
{ {
if (func) if (func)
{ {
+2 -2
View File
@@ -1,6 +1,6 @@
#include <os/media_detail.h> #include <os/media.h>
bool os::media::detail::IsExternalMediaPlaying() bool os::media::IsExternalMediaPlaying()
{ {
// This functionality is not supported in Linux. // This functionality is not supported in Linux.
return false; return false;
+4 -4
View File
@@ -1,8 +1,8 @@
#include <os/process_detail.h> #include <os/process.h>
#include <signal.h> #include <signal.h>
std::filesystem::path os::process::detail::GetExecutablePath() std::filesystem::path os::process::GetExecutablePath()
{ {
char exePath[PATH_MAX] = {}; char exePath[PATH_MAX] = {};
if (readlink("/proc/self/exe", exePath, PATH_MAX) > 0) if (readlink("/proc/self/exe", exePath, PATH_MAX) > 0)
@@ -15,7 +15,7 @@ std::filesystem::path os::process::detail::GetExecutablePath()
} }
} }
std::filesystem::path os::process::detail::GetWorkingDirectory() std::filesystem::path os::process::GetWorkingDirectory()
{ {
char cwd[PATH_MAX] = {}; char cwd[PATH_MAX] = {};
char *res = getcwd(cwd, sizeof(cwd)); char *res = getcwd(cwd, sizeof(cwd));
@@ -29,7 +29,7 @@ std::filesystem::path os::process::detail::GetWorkingDirectory()
} }
} }
bool os::process::detail::StartProcess(const std::filesystem::path path, const std::vector<std::string> args, std::filesystem::path work) bool os::process::StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work)
{ {
pid_t pid = fork(); pid_t pid = fork();
if (pid < 0) if (pid < 0)
+2 -2
View File
@@ -1,6 +1,6 @@
#include <os/user_detail.h> #include <os/user.h>
bool os::user::detail::IsDarkTheme() bool os::user::IsDarkTheme()
{ {
return false; return false;
} }
+3 -3
View File
@@ -1,7 +1,7 @@
#include <os/version_detail.h> #include <os/version.h>
os::version::detail::OSVersion os::version::detail::GetOSVersion() os::version::OSVersion os::version::GetOSVersion()
{ {
assert(false && "Unimplemented."); assert(false && "Unimplemented.");
return os::version::detail::OSVersion(); return os::version::OSVersion();
} }
-12
View File
@@ -1,12 +0,0 @@
#include <os/logger.h>
#include <os/logger_detail.h>
void os::logger::Init()
{
detail::Init();
}
void os::logger::Log(const std::string_view str, detail::ELogType type, const char* func)
{
detail::Log(str, type, func);
}
+12 -4
View File
@@ -1,9 +1,9 @@
#pragma once #pragma once
#include <os/logger_detail.h> #include <source_location>
#define LOG_IMPL(type, func, str) os::logger::Log(str, os::logger::detail::ELogType::type, func) #define LOG_IMPL(type, func, str) os::logger::Log(str, os::logger::ELogType::type, func)
#define LOGF_IMPL(type, func, str, ...) os::logger::Log(fmt::format(str, __VA_ARGS__), os::logger::detail::ELogType::type, func) #define LOGF_IMPL(type, func, str, ...) os::logger::Log(fmt::format(str, __VA_ARGS__), os::logger::ELogType::type, func)
// Function-specific logging. // Function-specific logging.
@@ -51,6 +51,14 @@
namespace os::logger namespace os::logger
{ {
enum class ELogType
{
None,
Utility,
Warning,
Error
};
void Init(); void Init();
void Log(const std::string_view str, detail::ELogType type = detail::ELogType::None, const char* func = nullptr); void Log(const std::string_view str, ELogType type = ELogType::None, const char* func = nullptr);
} }
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#include <source_location>
namespace os::logger::detail
{
enum class ELogType
{
None,
Utility,
Warning,
Error
};
void Init();
void Log(const std::string_view str, ELogType type = ELogType::None, const char* func = nullptr);
}
-7
View File
@@ -1,7 +0,0 @@
#include <os/media.h>
#include <os/media_detail.h>
bool os::media::IsExternalMediaPlaying()
{
return detail::IsExternalMediaPlaying();
}
-6
View File
@@ -1,6 +0,0 @@
#pragma once
namespace os::media::detail
{
bool IsExternalMediaPlaying();
}
-17
View File
@@ -1,17 +0,0 @@
#include <os/process.h>
#include <os/process_detail.h>
std::filesystem::path os::process::GetExecutablePath()
{
return detail::GetExecutablePath();
}
std::filesystem::path os::process::GetWorkingDirectory()
{
return detail::GetWorkingDirectory();
}
bool os::process::StartProcess(const std::filesystem::path path, const std::vector<std::string> args, std::filesystem::path work)
{
return detail::StartProcess(path, args, work);
}
+1 -1
View File
@@ -4,5 +4,5 @@ namespace os::process
{ {
std::filesystem::path GetExecutablePath(); std::filesystem::path GetExecutablePath();
std::filesystem::path GetWorkingDirectory(); std::filesystem::path GetWorkingDirectory();
bool StartProcess(const std::filesystem::path path, const std::vector<std::string> args, std::filesystem::path work = {}); bool StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work = {});
} }
-8
View File
@@ -1,8 +0,0 @@
#pragma once
namespace os::process::detail
{
std::filesystem::path GetExecutablePath();
std::filesystem::path GetWorkingDirectory();
bool StartProcess(const std::filesystem::path path, const std::vector<std::string> args, std::filesystem::path work = {});
}
-7
View File
@@ -1,7 +0,0 @@
#include <os/user.h>
#include <os/user_detail.h>
bool os::user::IsDarkTheme()
{
return detail::IsDarkTheme();
}
-6
View File
@@ -1,6 +0,0 @@
#pragma once
namespace os::user::detail
{
bool IsDarkTheme();
}
-7
View File
@@ -1,7 +0,0 @@
#include <os/version.h>
#include <os/version_detail.h>
os::version::detail::OSVersion os::version::GetOSVersion()
{
return detail::GetOSVersion();
}
+8 -3
View File
@@ -1,8 +1,13 @@
#pragma once #pragma once
#include <os/version_detail.h>
namespace os::version namespace os::version
{ {
detail::OSVersion GetOSVersion(); struct OSVersion
{
uint32_t Major{};
uint32_t Minor{};
uint32_t Build{};
};
OSVersion GetOSVersion();
} }
-13
View File
@@ -1,13 +0,0 @@
#pragma once
namespace os::version::detail
{
struct OSVersion
{
uint32_t Major{};
uint32_t Minor{};
uint32_t Build{};
};
OSVersion GetOSVersion();
}
+3 -4
View File
@@ -1,17 +1,16 @@
#include <os/logger_detail.h> #include <os/logger.h>
#include <print>
#define FOREGROUND_WHITE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define FOREGROUND_WHITE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define FOREGROUND_YELLOW (FOREGROUND_RED | FOREGROUND_GREEN) #define FOREGROUND_YELLOW (FOREGROUND_RED | FOREGROUND_GREEN)
HANDLE g_hStandardOutput; HANDLE g_hStandardOutput;
void os::logger::detail::Init() void os::logger::Init()
{ {
g_hStandardOutput = GetStdHandle(STD_OUTPUT_HANDLE); g_hStandardOutput = GetStdHandle(STD_OUTPUT_HANDLE);
} }
void os::logger::detail::Log(const std::string_view str, detail::ELogType type, const char* func) void os::logger::Log(const std::string_view str, ELogType type, const char* func)
{ {
switch (type) switch (type)
{ {
+2 -2
View File
@@ -1,4 +1,4 @@
#include <os/media_detail.h> #include <os/media.h>
#include <os/logger.h> #include <os/logger.h>
#include <winrt/Windows.Foundation.h> #include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Media.Control.h> #include <winrt/Windows.Media.Control.h>
@@ -62,7 +62,7 @@ static GlobalSystemMediaTransportControlsSessionPlaybackInfo GetPlaybackInfo()
} }
} }
bool os::media::detail::IsExternalMediaPlaying() bool os::media::IsExternalMediaPlaying()
{ {
auto playbackInfo = GetPlaybackInfo(); auto playbackInfo = GetPlaybackInfo();
+4 -4
View File
@@ -1,6 +1,6 @@
#include <os/process_detail.h> #include <os/process.h>
std::filesystem::path os::process::detail::GetExecutablePath() std::filesystem::path os::process::GetExecutablePath()
{ {
WCHAR exePath[MAX_PATH]; WCHAR exePath[MAX_PATH];
@@ -10,7 +10,7 @@ std::filesystem::path os::process::detail::GetExecutablePath()
return std::filesystem::path(exePath); return std::filesystem::path(exePath);
} }
std::filesystem::path os::process::detail::GetWorkingDirectory() std::filesystem::path os::process::GetWorkingDirectory()
{ {
WCHAR workPath[MAX_PATH]; WCHAR workPath[MAX_PATH];
@@ -20,7 +20,7 @@ std::filesystem::path os::process::detail::GetWorkingDirectory()
return std::filesystem::path(workPath); return std::filesystem::path(workPath);
} }
bool os::process::detail::StartProcess(const std::filesystem::path path, const std::vector<std::string> args, std::filesystem::path work) bool os::process::StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work)
{ {
if (path.empty()) if (path.empty())
return false; return false;
+2 -2
View File
@@ -1,6 +1,6 @@
#include <os/user_detail.h> #include <os/user.h>
bool os::user::detail::IsDarkTheme() bool os::user::IsDarkTheme()
{ {
HKEY hKey; HKEY hKey;
+3 -3
View File
@@ -1,10 +1,10 @@
#include <os/version_detail.h> #include <os/version.h>
LIB_FUNCTION(LONG, "ntdll.dll", RtlGetVersion, PRTL_OSVERSIONINFOW); LIB_FUNCTION(LONG, "ntdll.dll", RtlGetVersion, PRTL_OSVERSIONINFOW);
os::version::detail::OSVersion os::version::detail::GetOSVersion() os::version::OSVersion os::version::GetOSVersion()
{ {
auto result = os::version::detail::OSVersion{}; auto result = os::version::OSVersion{};
OSVERSIONINFOEXW osvi = { 0 }; OSVERSIONINFOEXW osvi = { 0 };
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
@@ -0,0 +1,14 @@
#include <api/SWA.h>
#include <patches/ui/CTitleStateIntro_patches.h>
// SWA::CGameModeStageTitle::Update
PPC_FUNC_IMPL(__imp__sub_825518B8);
PPC_FUNC(sub_825518B8)
{
auto pGameModeStageTitle = (SWA::CGameModeStageTitle*)g_memory.Translate(ctx.r3.u32);
__imp__sub_825518B8(ctx, base);
if (g_quitMessageOpen)
pGameModeStageTitle->m_AdvertiseMovieWaitTime = 0;
}
+118 -96
View File
@@ -185,13 +185,13 @@ void AspectRatioPatches::ComputeOffsets()
float height = Video::s_viewportHeight; float height = Video::s_viewportHeight;
g_aspectRatio = width / height; g_aspectRatio = width / height;
g_aspectRatioScale = 1.0f; g_aspectRatioGameplayScale = 1.0f;
if (g_aspectRatio >= NARROW_ASPECT_RATIO) if (g_aspectRatio >= NARROW_ASPECT_RATIO)
{ {
// height is locked to 720 in this case g_aspectRatioOffsetX = (width - height * WIDE_ASPECT_RATIO) / 2.0f;
g_aspectRatioOffsetX = 0.5f * (g_aspectRatio * 720.0f - 1280.0f);
g_aspectRatioOffsetY = 0.0f; g_aspectRatioOffsetY = 0.0f;
g_aspectRatioScale = height / 720.0f;
// keep same scale above Steam Deck aspect ratio // keep same scale above Steam Deck aspect ratio
if (g_aspectRatio < WIDE_ASPECT_RATIO) if (g_aspectRatio < WIDE_ASPECT_RATIO)
@@ -201,20 +201,29 @@ void AspectRatioPatches::ComputeOffsets()
float narrowScale = ComputeScale(NARROW_ASPECT_RATIO); float narrowScale = ComputeScale(NARROW_ASPECT_RATIO);
float lerpFactor = std::clamp((g_aspectRatio - NARROW_ASPECT_RATIO) / (STEAM_DECK_ASPECT_RATIO - NARROW_ASPECT_RATIO), 0.0f, 1.0f); float lerpFactor = std::clamp((g_aspectRatio - NARROW_ASPECT_RATIO) / (STEAM_DECK_ASPECT_RATIO - NARROW_ASPECT_RATIO), 0.0f, 1.0f);
g_aspectRatioScale = narrowScale + (steamDeckScale - narrowScale) * lerpFactor; g_aspectRatioGameplayScale = narrowScale + (steamDeckScale - narrowScale) * lerpFactor;
} }
} }
else else
{ {
// width is locked to 960 in this case to have 4:3 crop // 4:3 crop
g_aspectRatioOffsetX = 0.5f * (960.0f - 1280.0f); g_aspectRatioOffsetX = (width - width * NARROW_ASPECT_RATIO) / 2.0f;
g_aspectRatioOffsetY = 0.5f * (960.0f / g_aspectRatio - 720.0f); g_aspectRatioOffsetY = (height - width / NARROW_ASPECT_RATIO) / 2.0f;
g_aspectRatioScale = ComputeScale(NARROW_ASPECT_RATIO); g_aspectRatioScale = width / 960.0f;
g_aspectRatioGameplayScale = ComputeScale(NARROW_ASPECT_RATIO);
} }
g_narrowOffsetScale = std::clamp((g_aspectRatio - NARROW_ASPECT_RATIO) / (WIDE_ASPECT_RATIO - NARROW_ASPECT_RATIO), 0.0f, 1.0f); g_aspectRatioNarrowScale = std::clamp((g_aspectRatio - NARROW_ASPECT_RATIO) / (WIDE_ASPECT_RATIO - NARROW_ASPECT_RATIO), 0.0f, 1.0f);
} }
static void GetViewport(void* application, be<uint32_t>* width, be<uint32_t>* height)
{
*width = 1280;
*height = 720;
}
GUEST_FUNCTION_HOOK(sub_82E169B8, GetViewport);
// SWA::CGameDocument::ComputeScreenPosition // SWA::CGameDocument::ComputeScreenPosition
PPC_FUNC_IMPL(__imp__sub_8250FC70); PPC_FUNC_IMPL(__imp__sub_8250FC70);
PPC_FUNC(sub_8250FC70) PPC_FUNC(sub_8250FC70)
@@ -222,14 +231,15 @@ PPC_FUNC(sub_8250FC70)
__imp__sub_8250FC70(ctx, base); __imp__sub_8250FC70(ctx, base);
auto position = reinterpret_cast<be<float>*>(base + ctx.r3.u32); auto position = reinterpret_cast<be<float>*>(base + ctx.r3.u32);
position[0] = position[0] - g_aspectRatioOffsetX;
position[1] = position[1] - g_aspectRatioOffsetY; position[0] = (position[0] / 1280.0f * Video::s_viewportWidth - g_aspectRatioOffsetX) / g_aspectRatioScale;
position[1] = (position[1] / 720.0f * Video::s_viewportHeight - g_aspectRatioOffsetY) / g_aspectRatioScale;
} }
void ComputeScreenPositionMidAsmHook(PPCRegister& f1, PPCRegister& f2) void ComputeScreenPositionMidAsmHook(PPCRegister& f1, PPCRegister& f2)
{ {
f1.f64 -= g_aspectRatioOffsetX; f1.f64 = (f1.f64 / 1280.0 * Video::s_viewportWidth - g_aspectRatioOffsetX) / g_aspectRatioScale;
f2.f64 -= g_aspectRatioOffsetY; f2.f64 = (f2.f64 / 720.0 * Video::s_viewportHeight - g_aspectRatioOffsetY) / g_aspectRatioScale;
} }
void WorldMapInfoMidAsmHook(PPCRegister& r4) void WorldMapInfoMidAsmHook(PPCRegister& r4)
@@ -258,11 +268,11 @@ PPC_FUNC(sub_8258B558)
if (scene != NULL) if (scene != NULL)
{ {
ctx.r3.u32 = scene; ctx.r3.u32 = scene;
ctx.f1.f64 = offsetX + g_narrowOffsetScale * 140.0f; ctx.f1.f64 = offsetX + g_aspectRatioNarrowScale * 140.0f;
ctx.f2.f64 = offsetY; ctx.f2.f64 = offsetY;
if (Config::UIScaleMode == EUIScaleMode::Edge && g_narrowOffsetScale >= 1.0f) if (Config::UIScaleMode == EUIScaleMode::Edge && g_aspectRatioNarrowScale >= 1.0f)
ctx.f1.f64 += g_aspectRatioOffsetX; ctx.f1.f64 += g_aspectRatioOffsetX / g_aspectRatioScale;
sub_830BB3D0(ctx, base); sub_830BB3D0(ctx, base);
} }
@@ -282,9 +292,9 @@ PPC_FUNC(sub_8258B558)
uint32_t textBox = PPC_LOAD_U32(menuTextBox + 0x4); uint32_t textBox = PPC_LOAD_U32(menuTextBox + 0x4);
if (textBox != NULL) if (textBox != NULL)
{ {
float value = 708.0f + g_narrowOffsetScale * 140.0f; float value = 708.0f + g_aspectRatioNarrowScale * 140.0f;
if (Config::UIScaleMode == EUIScaleMode::Edge && g_narrowOffsetScale >= 1.0f) if (Config::UIScaleMode == EUIScaleMode::Edge && g_aspectRatioNarrowScale >= 1.0f)
value += g_aspectRatioOffsetX; value += g_aspectRatioOffsetX / g_aspectRatioScale;
PPC_STORE_U32(textBox + 0x38, reinterpret_cast<uint32_t&>(value)); PPC_STORE_U32(textBox + 0x38, reinterpret_cast<uint32_t&>(value));
} }
@@ -740,8 +750,6 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
modifier.flags &= ~(ALIGN_LEFT | ALIGN_RIGHT); modifier.flags &= ~(ALIGN_LEFT | ALIGN_RIGHT);
} }
auto backBuffer = Video::GetBackBuffer();
uint32_t size = ctx.r5.u32 * stride; uint32_t size = ctx.r5.u32 * stride;
ctx.r1.u32 -= size; ctx.r1.u32 -= size;
@@ -755,10 +763,12 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
if ((modifier.flags & STRETCH_HORIZONTAL) != 0) if ((modifier.flags & STRETCH_HORIZONTAL) != 0)
{ {
scaleX = backBuffer->width / 1280.0f; scaleX = Video::s_viewportWidth / 1280.0f;
} }
else else
{ {
scaleX = g_aspectRatioScale;
if ((modifier.flags & ALIGN_RIGHT) != 0) if ((modifier.flags & ALIGN_RIGHT) != 0)
offsetX = g_aspectRatioOffsetX * 2.0f; offsetX = g_aspectRatioOffsetX * 2.0f;
else if ((modifier.flags & ALIGN_LEFT) == 0) else if ((modifier.flags & ALIGN_LEFT) == 0)
@@ -766,27 +776,29 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
if ((modifier.flags & SCALE) != 0) if ((modifier.flags & SCALE) != 0)
{ {
scaleX = g_aspectRatioScale; scaleX *= g_aspectRatioGameplayScale;
if ((modifier.flags & ALIGN_RIGHT) != 0) if ((modifier.flags & ALIGN_RIGHT) != 0)
offsetX += 1280.0f * (1.0f - scaleX); offsetX += 1280.0f * (1.0f - g_aspectRatioGameplayScale) * g_aspectRatioScale;
else if ((modifier.flags & ALIGN_LEFT) == 0) else if ((modifier.flags & ALIGN_LEFT) == 0)
offsetX += 640.0f * (1.0f - scaleX); offsetX += 640.0f * (1.0f - g_aspectRatioGameplayScale) * g_aspectRatioScale;
} }
if ((modifier.flags & WORLD_MAP) != 0) if ((modifier.flags & WORLD_MAP) != 0)
{ {
if ((modifier.flags & ALIGN_LEFT) != 0) if ((modifier.flags & ALIGN_LEFT) != 0)
offsetX += (1.0f - g_narrowOffsetScale) * -20.0f; offsetX += (1.0f - g_aspectRatioNarrowScale) * g_aspectRatioScale * -20.0f;
} }
} }
if ((modifier.flags & STRETCH_VERTICAL) != 0) if ((modifier.flags & STRETCH_VERTICAL) != 0)
{ {
scaleY = backBuffer->height / 720.0f; scaleY = Video::s_viewportHeight / 720.0f;
} }
else else
{ {
scaleY = g_aspectRatioScale;
if ((modifier.flags & ALIGN_BOTTOM) != 0) if ((modifier.flags & ALIGN_BOTTOM) != 0)
offsetY = g_aspectRatioOffsetY * 2.0f; offsetY = g_aspectRatioOffsetY * 2.0f;
else if ((modifier.flags & ALIGN_TOP) == 0) else if ((modifier.flags & ALIGN_TOP) == 0)
@@ -794,12 +806,12 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
if ((modifier.flags & SCALE) != 0) if ((modifier.flags & SCALE) != 0)
{ {
scaleY = g_aspectRatioScale; scaleY *= g_aspectRatioGameplayScale;
if ((modifier.flags & ALIGN_BOTTOM) != 0) if ((modifier.flags & ALIGN_BOTTOM) != 0)
offsetY += 720.0f * (1.0f - scaleY); offsetY += 720.0f * (1.0f - g_aspectRatioGameplayScale) * g_aspectRatioScale;
else if ((modifier.flags & ALIGN_TOP) == 0) else if ((modifier.flags & ALIGN_TOP) == 0)
offsetY += 360.0f * (1.0f - scaleY); offsetY += 360.0f * (1.0f - g_aspectRatioGameplayScale) * g_aspectRatioScale;
} }
} }
@@ -836,7 +848,7 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
if ((offsetScaleModifier.flags & OFFSET_SCALE_LEFT) != 0) if ((offsetScaleModifier.flags & OFFSET_SCALE_LEFT) != 0)
offsetX *= corner / offsetScaleModifier.cornerMax; offsetX *= corner / offsetScaleModifier.cornerMax;
else if ((offsetScaleModifier.flags & OFFSET_SCALE_RIGHT) != 0) else if ((offsetScaleModifier.flags & OFFSET_SCALE_RIGHT) != 0)
offsetX = 1280.0f - (1280.0f - offsetX) * (1280.0f - corner) / (1280.0f - offsetScaleModifier.cornerMax); offsetX = Video::s_viewportWidth - (Video::s_viewportWidth - offsetX) * (1280.0f - corner) / (1280.0f - offsetScaleModifier.cornerMax);
} }
for (size_t i = 0; i < ctx.r5.u32; i++) for (size_t i = 0; i < ctx.r5.u32; i++)
@@ -852,11 +864,11 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
} }
else if ((modifier.flags & EXTEND_RIGHT) != 0 && (i == 2 || i == 3)) else if ((modifier.flags & EXTEND_RIGHT) != 0 && (i == 2 || i == 3))
{ {
x = std::max(x, float(backBuffer->width)); x = std::max(x, float(Video::s_viewportWidth));
} }
position[0] = round(x / backBuffer->width * Video::s_viewportWidth) / Video::s_viewportWidth * backBuffer->width; position[0] = round(x);
position[1] = round(y / backBuffer->height * Video::s_viewportHeight) / Video::s_viewportHeight * backBuffer->height; position[1] = round(y);
} }
ctx.r4.u32 = ctx.r1.u32; ctx.r4.u32 = ctx.r1.u32;
@@ -882,13 +894,12 @@ PPC_FUNC(sub_825E2E88)
PPC_FUNC_IMPL(__imp__sub_82E16C70); PPC_FUNC_IMPL(__imp__sub_82E16C70);
PPC_FUNC(sub_82E16C70) PPC_FUNC(sub_82E16C70)
{ {
auto backBuffer = Video::GetBackBuffer();
auto scissorRect = reinterpret_cast<GuestRect*>(base + ctx.r4.u32); auto scissorRect = reinterpret_cast<GuestRect*>(base + ctx.r4.u32);
scissorRect->left = scissorRect->left + g_aspectRatioOffsetX; scissorRect->left = scissorRect->left * g_aspectRatioScale + g_aspectRatioOffsetX;
scissorRect->top = scissorRect->top + g_aspectRatioOffsetY; scissorRect->top = scissorRect->top * g_aspectRatioScale + g_aspectRatioOffsetY;
scissorRect->right = scissorRect->right + g_aspectRatioOffsetX; scissorRect->right = scissorRect->right * g_aspectRatioScale + g_aspectRatioOffsetX;
scissorRect->bottom = scissorRect->bottom + g_aspectRatioOffsetY; scissorRect->bottom = scissorRect->bottom * g_aspectRatioScale + g_aspectRatioOffsetY;
__imp__sub_82E16C70(ctx, base); __imp__sub_82E16C70(ctx, base);
} }
@@ -926,65 +937,76 @@ PPC_FUNC(sub_830D1EF0)
__imp__sub_830D1EF0(ctx, base); __imp__sub_830D1EF0(ctx, base);
if (!PPC_LOAD_U8(r3.u32 + PRIMITIVE_2D_PADDING_OFFSET)) struct Vertex
{ {
auto backBuffer = Video::GetBackBuffer(); be<float> x;
be<float> y;
be<float> z;
be<float> w;
be<uint32_t> color;
be<float> u;
be<float> v;
};
struct Vertex auto vertex = reinterpret_cast<Vertex*>(base + ctx.r4.u32);
for (size_t i = 0; i < 4; i++)
{
float x = vertex[i].x * 640.0f + 640.0f;
float y = vertex[i].y * -360.0f + 360.0f;
if (PPC_LOAD_U8(r3.u32 + PRIMITIVE_2D_PADDING_OFFSET))
{ {
be<float> x; // Stretch
be<float> y; x = ((x + 0.5f) / 1280.0f) * Video::s_viewportWidth;
be<float> z; y = ((y + 0.5f) / 720.0f) * Video::s_viewportHeight;
be<float> w; }
be<uint32_t> color; else
be<float> u;
be<float> v;
};
auto vertex = reinterpret_cast<Vertex*>(base + ctx.r4.u32);
for (size_t i = 0; i < 4; i++)
{ {
vertex[i].x = vertex[i].x * 1280.0f / backBuffer->width; // Center
vertex[i].y = vertex[i].y * 720.0f / backBuffer->height; x = g_aspectRatioOffsetX + (x + 0.5f) * g_aspectRatioScale;
y = g_aspectRatioOffsetY + (y + 0.5f) * g_aspectRatioScale;
} }
bool letterboxTop = PPC_LOAD_U8(r3.u32 + PRIMITIVE_2D_PADDING_OFFSET + 0x1); vertex[i].x = ((x - 0.5f) / Video::s_viewportWidth) * 2.0f - 1.0f;
bool letterboxBottom = PPC_LOAD_U8(r3.u32 + PRIMITIVE_2D_PADDING_OFFSET + 0x2); vertex[i].y = ((y - 0.5f) / Video::s_viewportHeight) * -2.0f + 1.0f;
}
if (letterboxTop || letterboxBottom) bool letterboxTop = PPC_LOAD_U8(r3.u32 + PRIMITIVE_2D_PADDING_OFFSET + 0x1);
bool letterboxBottom = PPC_LOAD_U8(r3.u32 + PRIMITIVE_2D_PADDING_OFFSET + 0x2);
if (letterboxTop || letterboxBottom)
{
float halfPixelX = 1.0f / Video::s_viewportWidth;
float halfPixelY = 1.0f / Video::s_viewportHeight;
if (letterboxTop)
{ {
float halfPixelX = 1.0f / backBuffer->width; vertex[0].x = -1.0f - halfPixelX;
float halfPixelY = 1.0f / backBuffer->height; vertex[0].y = 1.0f + halfPixelY;
if (letterboxTop) vertex[1].x = 1.0f - halfPixelX;
{ vertex[1].y = 1.0f + halfPixelY;
vertex[0].x = -1.0f - halfPixelX;
vertex[0].y = 1.0f + halfPixelY;
vertex[1].x = 1.0f - halfPixelX; vertex[2].x = -1.0f - halfPixelX;
vertex[1].y = 1.0f + halfPixelY; // vertex[2].y untouched
vertex[2].x = -1.0f - halfPixelX; vertex[3].x = 1.0f - halfPixelX;
// vertex[2].y untouched // vertex[3].y untouched
}
else if (letterboxBottom)
{
vertex[0].x = -1.0f - halfPixelX;
// vertex[0].y untouched
vertex[3].x = 1.0f - halfPixelX; vertex[1].x = 1.0f - halfPixelX;
// vertex[3].y untouched // vertex[1].y untouched
}
else if (letterboxBottom)
{
vertex[0].x = -1.0f - halfPixelX;
// vertex[0].y untouched
vertex[1].x = 1.0f - halfPixelX; vertex[2].x = -1.0f - halfPixelX;
// vertex[1].y untouched vertex[2].y = -1.0f + halfPixelY;
vertex[2].x = -1.0f - halfPixelX; vertex[3].x = 1.0f - halfPixelX;
vertex[2].y = -1.0f + halfPixelY; vertex[3].y = -1.0f + halfPixelY;
vertex[3].x = 1.0f - halfPixelX;
vertex[3].y = -1.0f + halfPixelY;
}
} }
} }
} }
@@ -1018,8 +1040,9 @@ static double ComputeObjGetItemX(uint32_t type)
x = 1058.0; x = 1058.0;
x *= g_aspectRatioScale; x *= g_aspectRatioScale;
x *= g_aspectRatioGameplayScale;
double scaleOffset = (1280.0 * (1.0 - g_aspectRatioScale)); double scaleOffset = (1280.0 * (1.0 - g_aspectRatioGameplayScale)) * g_aspectRatioScale;
if (Config::UIScaleMode == EUIScaleMode::Edge) if (Config::UIScaleMode == EUIScaleMode::Edge)
{ {
@@ -1031,8 +1054,7 @@ static double ComputeObjGetItemX(uint32_t type)
x += g_aspectRatioOffsetX + scaleOffset; x += g_aspectRatioOffsetX + scaleOffset;
} }
auto backBuffer = Video::GetBackBuffer(); return (x - (0.5 * Video::s_viewportWidth)) / (0.5 * Video::s_viewportHeight) * OBJ_GET_ITEM_TANGENT;
return (x - (0.5 * backBuffer->width)) / (0.5 * backBuffer->height) * OBJ_GET_ITEM_TANGENT;
} }
return 0.0; return 0.0;
@@ -1066,10 +1088,10 @@ static double ComputeObjGetItemY(uint32_t type)
y = 582.0; y = 582.0;
y *= g_aspectRatioScale; y *= g_aspectRatioScale;
y += g_aspectRatioOffsetY * 2.0 + 720.0 * (1.0 - g_aspectRatioScale); y *= g_aspectRatioGameplayScale;
y += g_aspectRatioOffsetY * 2.0 + 720.0 * (1.0 - g_aspectRatioGameplayScale) * g_aspectRatioScale;
auto backBuffer = Video::GetBackBuffer(); return ((0.5 * Video::s_viewportHeight) - y) / (0.5 * Video::s_viewportHeight) * OBJ_GET_ITEM_TANGENT;
return ((0.5 * backBuffer->height) - y) / (0.5 * backBuffer->height) * OBJ_GET_ITEM_TANGENT;
} }
return 0.25; return 0.25;
@@ -1133,12 +1155,12 @@ PPC_FUNC(sub_82B8AA40)
PPC_STORE_U8(ctx.r3.u32, shouldDrawLetterbox); PPC_STORE_U8(ctx.r3.u32, shouldDrawLetterbox);
if (shouldDrawLetterbox) if (shouldDrawLetterbox)
{ {
auto backBuffer = Video::GetBackBuffer(); float aspectRatio = std::max(NARROW_ASPECT_RATIO, g_aspectRatio);
uint32_t height = std::min(720u, backBuffer->height); uint32_t width = aspectRatio * 720;
PPC_STORE_U32(ctx.r3.u32 + 0xC, backBuffer->width); PPC_STORE_U32(ctx.r3.u32 + 0xC, width);
PPC_STORE_U32(ctx.r3.u32 + 0x10, height); PPC_STORE_U32(ctx.r3.u32 + 0x10, 720);
PPC_STORE_U32(ctx.r3.u32 + 0x14, (height - backBuffer->width * 9 / 16) / 2); PPC_STORE_U32(ctx.r3.u32 + 0x14, (720 - width * 9 / 16) / 2);
} }
__imp__sub_82B8AA40(ctx, base); __imp__sub_82B8AA40(ctx, base);
@@ -1161,5 +1183,5 @@ void InspireSubtitleMidAsmHook(PPCRegister& r3)
constexpr float NARROW_OFFSET = 485.0f; constexpr float NARROW_OFFSET = 485.0f;
constexpr float WIDE_OFFSET = 560.0f; constexpr float WIDE_OFFSET = 560.0f;
*reinterpret_cast<be<float>*>(g_memory.base + r3.u32 + 0x3C) = NARROW_OFFSET + (WIDE_OFFSET - NARROW_OFFSET) * g_narrowOffsetScale; *reinterpret_cast<be<float>*>(g_memory.base + r3.u32 + 0x3C) = NARROW_OFFSET + (WIDE_OFFSET - NARROW_OFFSET) * g_aspectRatioNarrowScale;
} }
@@ -8,7 +8,8 @@ inline float g_aspectRatio;
inline float g_aspectRatioOffsetX; inline float g_aspectRatioOffsetX;
inline float g_aspectRatioOffsetY; inline float g_aspectRatioOffsetY;
inline float g_aspectRatioScale; inline float g_aspectRatioScale;
inline float g_narrowOffsetScale; inline float g_aspectRatioGameplayScale;
inline float g_aspectRatioNarrowScale;
struct AspectRatioPatches struct AspectRatioPatches
{ {
+348
View File
@@ -0,0 +1,348 @@
#include <api/SWA.h>
#include <hid/hid.h>
#include <ui/sdl_listener.h>
#include <app.h>
#include <exports.h>
class WorldMapTouchParams
{
public:
float CancelDeadzone{ 0.31f };
float Damping{ 0.99f };
float FlickAccelX{ 0.25f };
float FlickAccelY{ 0.1f };
float FlickTerminalVelocity{ 40.0f };
float FlickThreshold{ 2.25f };
float SensitivityX{};
float SensitivityY{};
float Smoothing{ 0.8f };
};
class WorldMapTouchParamsProspero : public WorldMapTouchParams
{
public:
WorldMapTouchParamsProspero()
{
SensitivityX = 1.15f;
SensitivityY = 1.05f;
}
}
g_worldMapTouchParamsProspero;
class WorldMapTouchParamsOrbis : public WorldMapTouchParams
{
public:
WorldMapTouchParamsOrbis()
{
SensitivityX = 0.95f;
SensitivityY = 1.0f;
}
}
g_worldMapTouchParamsOrbis;
WorldMapTouchParams g_worldMapTouchParams{};
static bool g_isTouchActive;
static float g_worldMapTouchVelocityX;
static float g_worldMapTouchVelocityY;
class SDLEventListenerForInputPatches : public SDLEventListener
{
static inline int ms_touchpadFingerCount;
static inline float ms_touchpadX;
static inline float ms_touchpadY;
static inline float ms_touchpadDeltaX;
static inline float ms_touchpadDeltaY;
static inline float ms_touchpadPrevX;
static inline float ms_touchpadPrevY;
public:
static void Update(float deltaTime)
{
/* NOTE (Hyper): this code was written at 144Hz and was
discovered later to be faulty at any other frame rate,
so this is here to account for that without changing
all the constants that I had tuned. */
constexpr auto referenceDeltaTime = 1.0f / 144.0f;
if (g_isTouchActive)
{
auto dxNorm = ms_touchpadDeltaX / referenceDeltaTime;
auto dyNorm = ms_touchpadDeltaY / referenceDeltaTime;
auto dxSens = dxNorm * g_worldMapTouchParams.SensitivityX;
auto dySens = dyNorm * g_worldMapTouchParams.SensitivityY;
auto smoothing = powf(g_worldMapTouchParams.Smoothing, deltaTime / referenceDeltaTime);
g_worldMapTouchVelocityX = smoothing * g_worldMapTouchVelocityX + (1.0f - smoothing) * dxSens;
g_worldMapTouchVelocityY = smoothing * g_worldMapTouchVelocityY + (1.0f - smoothing) * dySens;
auto flickThreshold = g_worldMapTouchParams.FlickThreshold;
if (fabs(dxSens) > flickThreshold || fabs(dySens) > flickThreshold)
{
g_worldMapTouchVelocityX += dxNorm * g_worldMapTouchParams.FlickAccelX * (deltaTime / referenceDeltaTime);
g_worldMapTouchVelocityY += dyNorm * g_worldMapTouchParams.FlickAccelY * (deltaTime / referenceDeltaTime);
}
auto terminalVelocity = g_worldMapTouchParams.FlickTerminalVelocity;
g_worldMapTouchVelocityX = std::clamp(g_worldMapTouchVelocityX, -terminalVelocity, terminalVelocity);
g_worldMapTouchVelocityY = std::clamp(g_worldMapTouchVelocityY, -terminalVelocity, terminalVelocity);
}
else
{
auto dampingFactor = powf(g_worldMapTouchParams.Damping, deltaTime / referenceDeltaTime);
g_worldMapTouchVelocityX *= dampingFactor;
g_worldMapTouchVelocityY *= dampingFactor;
}
}
void OnSDLEvent(SDL_Event* event) override
{
switch (event->type)
{
case SDL_CONTROLLERTOUCHPADMOTION:
{
g_isTouchActive = true;
if (ms_touchpadFingerCount > 1)
{
g_isTouchActive = false;
break;
}
ms_touchpadX = event->ctouchpad.x;
ms_touchpadY = event->ctouchpad.y;
ms_touchpadDeltaX = ms_touchpadX - ms_touchpadPrevX;
ms_touchpadDeltaY = ms_touchpadY - ms_touchpadPrevY;
ms_touchpadPrevX = ms_touchpadX;
ms_touchpadPrevY = ms_touchpadY;
break;
}
case SDL_CONTROLLERTOUCHPADDOWN:
{
g_worldMapTouchParams = hid::g_inputDeviceExplicit == hid::EInputDeviceExplicit::DualSense
? (WorldMapTouchParams)g_worldMapTouchParamsProspero
: (WorldMapTouchParams)g_worldMapTouchParamsOrbis;
ms_touchpadFingerCount++;
ms_touchpadPrevX = event->ctouchpad.x;
ms_touchpadPrevY = event->ctouchpad.y;
break;
}
case SDL_CONTROLLERTOUCHPADUP:
g_isTouchActive = false;
ms_touchpadFingerCount--;
break;
}
}
}
g_sdlEventListenerForInputPatches;
// -------------- COMMON --------------- //
static bool IsDPadActive(SWA::SPadState* pPadState)
{
return pPadState->IsDown(SWA::eKeyState_DpadUp) ||
pPadState->IsDown(SWA::eKeyState_DpadDown) ||
pPadState->IsDown(SWA::eKeyState_DpadLeft) ||
pPadState->IsDown(SWA::eKeyState_DpadRight);
}
static void SetDPadAnalogDirectionX(PPCRegister& pPadState, PPCRegister& x, bool invert, float max = 1.0f)
{
auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32);
if (pGuestPadState->IsDown(SWA::eKeyState_DpadLeft))
x.f64 = invert ? max : -max;
if (pGuestPadState->IsDown(SWA::eKeyState_DpadRight))
x.f64 = invert ? -max : max;
}
static void SetDPadAnalogDirectionY(PPCRegister& pPadState, PPCRegister& y, bool invert, float max = 1.0f)
{
auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32);
if (pGuestPadState->IsDown(SWA::eKeyState_DpadUp))
y.f64 = invert ? -max : max;
if (pGuestPadState->IsDown(SWA::eKeyState_DpadDown))
y.f64 = invert ? max : -max;
}
// -------------- PLAYER --------------- //
void PostureDPadSupportMidAsmHook(PPCRegister& pPadState, PPCRegister& x, PPCRegister& y)
{
SetDPadAnalogDirectionX(pPadState, x, false);
SetDPadAnalogDirectionY(pPadState, y, false);
}
void PostureDPadSupportInvertYMidAsmHook(PPCRegister& pPadState, PPCRegister& x, PPCRegister& y)
{
SetDPadAnalogDirectionX(pPadState, x, false);
SetDPadAnalogDirectionY(pPadState, y, true);
}
void PostureDPadSupportXMidAsmHook(PPCRegister& pPadState, PPCRegister& x)
{
SetDPadAnalogDirectionX(pPadState, x, false);
}
void PostureDPadSupportYMidAsmHook(PPCRegister& pPadState, PPCRegister& y)
{
SetDPadAnalogDirectionY(pPadState, y, false);
}
void PostureSpaceHurrierDPadSupportXMidAsmHook(PPCRegister& pPadState, PPCVRegister& vector)
{
auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32);
if (pGuestPadState->IsDown(SWA::eKeyState_DpadLeft))
vector.f32[3] = -1.0f;
if (pGuestPadState->IsDown(SWA::eKeyState_DpadRight))
vector.f32[3] = 1.0f;
}
void PostureSpaceHurrierDPadSupportYMidAsmHook(PPCRegister& pPadState, PPCVRegister& vector)
{
auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32);
if (pGuestPadState->IsDown(SWA::eKeyState_DpadUp))
vector.f32[3] = 1.0f;
if (pGuestPadState->IsDown(SWA::eKeyState_DpadDown))
vector.f32[3] = -1.0f;
}
// ------------- WORLD MAP ------------- //
bool WorldMapTouchSupportMidAsmHook()
{
SDLEventListenerForInputPatches::Update(App::s_deltaTime);
auto vxAbs = fabs(g_worldMapTouchVelocityX);
auto vyAbs = fabs(g_worldMapTouchVelocityY);
/* Reduce touch noise if the player has
their finger resting on the touchpad,
but allow much precise values without
touch for proper interpolation to zero. */
if (vxAbs < 0.05f || vyAbs < 0.05f)
return !g_isTouchActive;
return vxAbs > 0 || vyAbs > 0;
}
bool WorldMapTouchMagnetismSupportMidAsmHook(PPCRegister& f0)
{
return fabs(g_worldMapTouchVelocityX) > f0.f64 || fabs(g_worldMapTouchVelocityY) > f0.f64;
}
void TouchAndDPadSupportWorldMapXMidAsmHook(PPCRegister& pPadState, PPCRegister& x)
{
auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32);
if (fabs(pGuestPadState->LeftStickHorizontal) > g_worldMapTouchParams.CancelDeadzone ||
fabs(pGuestPadState->LeftStickVertical) > g_worldMapTouchParams.CancelDeadzone)
{
g_worldMapTouchVelocityX = 0;
}
if (IsDPadActive(pGuestPadState))
{
g_worldMapTouchVelocityX = 0;
SetDPadAnalogDirectionX(pPadState, x, false);
}
else
{
if (fabs(g_worldMapTouchVelocityX) > 0)
x.f64 = -g_worldMapTouchVelocityX;
}
}
void TouchAndDPadSupportWorldMapYMidAsmHook(PPCRegister& pPadState, PPCRegister& y)
{
auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32);
if (fabs(pGuestPadState->LeftStickHorizontal) > g_worldMapTouchParams.CancelDeadzone ||
fabs(pGuestPadState->LeftStickVertical) > g_worldMapTouchParams.CancelDeadzone)
{
g_worldMapTouchVelocityY = 0;
}
if (IsDPadActive(pGuestPadState))
{
g_worldMapTouchVelocityY = 0;
SetDPadAnalogDirectionY(pPadState, y, false);
}
else
{
if (fabs(g_worldMapTouchVelocityY) > 0)
y.f64 = g_worldMapTouchVelocityY;
}
}
// SWA::CWorldMapCamera::Update
PPC_FUNC_IMPL(__imp__sub_82486968);
PPC_FUNC(sub_82486968)
{
auto pWorldMapCamera = (SWA::CWorldMapCamera*)g_memory.Translate(ctx.r3.u32);
// Reset vertical velocity if maximum pitch reached.
if (fabs(pWorldMapCamera->m_Pitch) >= 80.0f)
g_worldMapTouchVelocityY = 0;
__imp__sub_82486968(ctx, base);
}
// World Map cursor move hook.
PPC_FUNC(sub_8256C938)
{
auto pWorldMapCursor = (SWA::CWorldMapCursor*)g_memory.Translate(ctx.r3.u32);
pWorldMapCursor->m_IsCursorMoving = g_isTouchActive;
if (ctx.r4.u8)
{
pWorldMapCursor->m_LeftStickVertical = 0;
pWorldMapCursor->m_LeftStickHorizontal = 0;
}
else if (auto pInputState = SWA::CInputState::GetInstance())
{
auto& rPadState = pInputState->GetPadState();
pWorldMapCursor->m_LeftStickVertical = rPadState.LeftStickVertical;
pWorldMapCursor->m_LeftStickHorizontal = rPadState.LeftStickHorizontal;
if (rPadState.IsDown(SWA::eKeyState_DpadUp))
pWorldMapCursor->m_LeftStickVertical = 1.0f;
if (rPadState.IsDown(SWA::eKeyState_DpadDown))
pWorldMapCursor->m_LeftStickVertical = -1.0f;
if (rPadState.IsDown(SWA::eKeyState_DpadLeft))
pWorldMapCursor->m_LeftStickHorizontal = -1.0f;
if (rPadState.IsDown(SWA::eKeyState_DpadRight))
pWorldMapCursor->m_LeftStickHorizontal = 1.0f;
if (sqrtf((pWorldMapCursor->m_LeftStickHorizontal * pWorldMapCursor->m_LeftStickHorizontal) +
(pWorldMapCursor->m_LeftStickVertical * pWorldMapCursor->m_LeftStickVertical)) > 0.7f)
{
pWorldMapCursor->m_IsCursorMoving = true;
}
}
}
-2
View File
@@ -49,8 +49,6 @@ void WerehogBattleMusicMidAsmHook(PPCRegister& r11)
r11.u8 = 3; r11.u8 = 3;
} }
void StorageDevicePromptMidAsmHook() {}
/* Hook function that gets the game region /* Hook function that gets the game region
and force result to zero for Japanese and force result to zero for Japanese
to display the correct logos. */ to display the correct logos. */
@@ -1,3 +1,6 @@
#include <user/config.h>
#include <SWA/CharacterUtility/CharacterProxy.h>
// CObjFlame::CObjFlame // CObjFlame::CObjFlame
// A field is not zero initialized, // A field is not zero initialized,
// causing collisions to constantly get created // causing collisions to constantly get created
@@ -8,3 +11,59 @@ PPC_FUNC(sub_82608E60)
memset(base + ctx.r3.u32, 0, 0x154); memset(base + ctx.r3.u32, 0, 0x154);
__imp__sub_82608E60(ctx, base); __imp__sub_82608E60(ctx, base);
} }
// The barrel gets stuck at a slope at high frame rates and softlocks the player.
// We can update the character proxy at 30 FPS, and interpolate the visuals to work around this issue.
static constexpr size_t OBJ_BIG_BARREL_SIZE = 0x1A0;
struct ObjBigBarrelEx
{
float elapsedTime{};
bool interpolate{};
};
void ObjBigBarrelAllocMidAsmHook(PPCRegister& r3)
{
r3.u32 += sizeof(ObjBigBarrelEx);
}
// CObjBigBarrel::CObjBigBarrel
PPC_FUNC_IMPL(__imp__sub_8271AC08);
PPC_FUNC(sub_8271AC08)
{
new (base + ctx.r3.u32 + OBJ_BIG_BARREL_SIZE) ObjBigBarrelEx();
__imp__sub_8271AC08(ctx, base);
}
// CObjBigBarrel::Integrate
PPC_FUNC_IMPL(__imp__sub_8271AA30);
PPC_FUNC(sub_8271AA30)
{
auto objBigBarrelEx = reinterpret_cast<ObjBigBarrelEx*>(base + ctx.r3.u32 + OBJ_BIG_BARREL_SIZE);
objBigBarrelEx->interpolate = ctx.f1.f64 < (1.0 / 30.0);
objBigBarrelEx->elapsedTime += ctx.f1.f64;
if (!objBigBarrelEx->interpolate || objBigBarrelEx->elapsedTime >= (1.0f / 30.0f))
{
ctx.f1.f64 = objBigBarrelEx->elapsedTime;
__imp__sub_8271AA30(ctx, base);
objBigBarrelEx->elapsedTime = 0.0f;
}
}
void ObjBigBarrelSetPositionMidAsmHook(PPCRegister& r3, PPCRegister& r4)
{
uint8_t* base = g_memory.base;
auto objBigBarrelEx = reinterpret_cast<ObjBigBarrelEx*>(base + r3.u32 + OBJ_BIG_BARREL_SIZE);
if (objBigBarrelEx->interpolate)
{
auto characterProxy = reinterpret_cast<SWA::CCharacterProxy*>(base + PPC_LOAD_U32(r3.u32 + 0x100));
auto position = reinterpret_cast<Hedgehog::Math::CVector*>(base + r4.u32);
float factor = (1.0f / 30.0f) - objBigBarrelEx->elapsedTime;
position->X = position->X - characterProxy->m_Velocity.X * factor;
position->Y = position->Y - characterProxy->m_Velocity.Y * factor;
position->Z = position->Z - characterProxy->m_Velocity.Z * factor;
}
}
@@ -10,26 +10,6 @@ static uint32_t g_lastTrickScore;
static float g_lastDarkGaiaEnergy; static float g_lastDarkGaiaEnergy;
static bool g_isUnleashCancelled; static bool g_isUnleashCancelled;
void PostureDPadSupportMidAsmHook(PPCRegister& r3)
{
if (!Config::AllowDPadMovement)
return;
auto pPadState = (SWA::SPadState*)g_memory.Translate(r3.u32);
if (pPadState->IsDown(SWA::eKeyState_DpadUp))
pPadState->LeftStickVertical = 1.0f;
if (pPadState->IsDown(SWA::eKeyState_DpadDown))
pPadState->LeftStickVertical = -1.0f;
if (pPadState->IsDown(SWA::eKeyState_DpadLeft))
pPadState->LeftStickHorizontal = -1.0f;
if (pPadState->IsDown(SWA::eKeyState_DpadRight))
pPadState->LeftStickHorizontal = 1.0f;
}
/* Hook function for when checkpoints are activated /* Hook function for when checkpoints are activated
to preserve the current checkpoint score. */ to preserve the current checkpoint score. */
PPC_FUNC_IMPL(__imp__sub_82624308); PPC_FUNC_IMPL(__imp__sub_82624308);
+4 -2
View File
@@ -2,7 +2,7 @@
#include <user/config.h> #include <user/config.h>
#include <api/SWA.h> #include <api/SWA.h>
#include <os/logger.h> #include <os/logger.h>
#include <hid/hid_detail.h> #include <hid/hid.h>
#include <app.h> #include <app.h>
bool m_isSavedAchievementData = false; bool m_isSavedAchievementData = false;
@@ -69,6 +69,8 @@ PPC_FUNC(sub_824E5170)
if (pSaveIcon->m_IsVisible) if (pSaveIcon->m_IsVisible)
{ {
App::s_isSaveDataCorrupt = false;
if (!m_isSavedAchievementData) if (!m_isSavedAchievementData)
{ {
LOGN("Saving achievements..."); LOGN("Saving achievements...");
@@ -131,7 +133,7 @@ void LoadingScreenControllerMidAsmHook()
auto isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation; auto isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation;
if (Config::ControllerIcons == EControllerIcons::Auto) if (Config::ControllerIcons == EControllerIcons::Auto)
isPlayStation = hid::detail::g_inputDeviceController == hid::detail::EInputDevice::PlayStation; isPlayStation = hid::g_inputDeviceController == hid::EInputDevice::PlayStation;
const char* prefix = isPlayStation ? "ps3" : "360"; const char* prefix = isPlayStation ? "ps3" : "360";
@@ -19,7 +19,7 @@ void CHudPauseAddOptionsItemMidAsmHook(PPCRegister& pThis)
guest_stack_var<Hedgehog::Base::CSharedString> menu("TopMenu"); guest_stack_var<Hedgehog::Base::CSharedString> menu("TopMenu");
guest_stack_var<Hedgehog::Base::CSharedString> name("option"); guest_stack_var<Hedgehog::Base::CSharedString> name("option");
GuestToHostFunction<int>(0x824AE690, pThis.u32, menu.get(), name.get()); GuestToHostFunction<int>(sub_824AE690, pThis.u32, menu.get(), name.get());
} }
bool InjectMenuBehaviour(uint32_t pThis, uint32_t count) bool InjectMenuBehaviour(uint32_t pThis, uint32_t count)
@@ -68,6 +68,9 @@ bool InjectMenuBehaviour(uint32_t pThis, uint32_t count)
pHudPause->m_Action = SWA::eActionType_Undefined; pHudPause->m_Action = SWA::eActionType_Undefined;
pHudPause->m_Transition = SWA::eTransitionType_Hide; pHudPause->m_Transition = SWA::eTransitionType_Hide;
if (pHudPause->m_rcBg1Select)
pHudPause->m_rcBg1Select->SetHideFlag(true);
return true; return true;
} }
else if (cursorIndex == count - 1) else if (cursorIndex == count - 1)
@@ -125,7 +128,7 @@ PPC_FUNC(sub_824B0930)
// Re-open pause menu after achievement menu closes with delay. // Re-open pause menu after achievement menu closes with delay.
if (g_achievementMenuOutroTime >= g_achievementMenuOutroThreshold) if (g_achievementMenuOutroTime >= g_achievementMenuOutroThreshold)
{ {
GuestToHostFunction<int>(0x824AFD28, pHudPause, 0, 1, 0, 0); GuestToHostFunction<int>(sub_824AFD28, pHudPause, 0, 1, 0, 0);
g_achievementMenuOutroTime = 0; g_achievementMenuOutroTime = 0;
g_isAchievementMenuOutro = false; g_isAchievementMenuOutro = false;
@@ -152,7 +155,8 @@ PPC_FUNC(sub_824B0930)
{ {
OptionsMenu::Close(); OptionsMenu::Close();
GuestToHostFunction<int>(0x824AFD28, pHudPause, 0, 0, 0, 1); GuestToHostFunction<int>(sub_824AFD28, pHudPause, 0, 0, 0, 1);
__imp__sub_824B0930(ctx, base);
} }
} }
else else
@@ -1,15 +1,23 @@
#include "CTitleStateIntro_patches.h"
#include <api/SWA.h> #include <api/SWA.h>
#include <locale/locale.h> #include <locale/locale.h>
#include <ui/fader.h> #include <ui/fader.h>
#include <ui/message_window.h> #include <ui/message_window.h>
#include <user/paths.h>
#include <app.h> #include <app.h>
static bool g_quitMessageOpen = false; bool g_quitMessageOpen = false;
static bool g_quitMessageFaderBegun = false; static bool g_quitMessageFaderBegun = false;
static int g_quitMessageResult = -1; static int g_quitMessageResult = -1;
static std::atomic<bool> g_corruptSaveMessageOpen = false;
static int g_corruptSaveMessageResult = -1;
static bool ProcessQuitMessage() static bool ProcessQuitMessage()
{ {
if (g_corruptSaveMessageOpen)
return false;
if (!g_quitMessageOpen) if (!g_quitMessageOpen)
return false; return false;
@@ -37,6 +45,33 @@ static bool ProcessQuitMessage()
return true; return true;
} }
static bool ProcessCorruptSaveMessage()
{
if (!g_corruptSaveMessageOpen)
return false;
if (MessageWindow::Open(Localise("Title_Message_SaveDataCorrupt"), &g_corruptSaveMessageResult) == MSG_CLOSED)
{
g_corruptSaveMessageOpen = false;
g_corruptSaveMessageOpen.notify_one();
g_corruptSaveMessageResult = -1;
}
return true;
}
void StorageDevicePromptMidAsmHook() {}
// Save data validation hook.
PPC_FUNC_IMPL(__imp__sub_822C55B0);
PPC_FUNC(sub_822C55B0)
{
App::s_isSaveDataCorrupt = true;
g_corruptSaveMessageOpen = true;
g_corruptSaveMessageOpen.wait(true);
ctx.r3.u32 = 0;
}
// SWA::CTitleStateIntro::Update // SWA::CTitleStateIntro::Update
PPC_FUNC_IMPL(__imp__sub_82587E50); PPC_FUNC_IMPL(__imp__sub_82587E50);
PPC_FUNC(sub_82587E50) PPC_FUNC(sub_82587E50)
@@ -47,7 +82,7 @@ PPC_FUNC(sub_82587E50)
{ {
__imp__sub_82587E50(ctx, base); __imp__sub_82587E50(ctx, base);
} }
else else if (!ProcessCorruptSaveMessage())
{ {
auto pInputState = SWA::CInputState::GetInstance(); auto pInputState = SWA::CInputState::GetInstance();
@@ -0,0 +1,3 @@
#pragma once
extern bool g_quitMessageOpen;
@@ -50,11 +50,18 @@ PPC_FUNC_IMPL(__imp__sub_825882B8);
PPC_FUNC(sub_825882B8) PPC_FUNC(sub_825882B8)
{ {
auto pTitleState = (SWA::CTitleStateBase*)g_memory.Translate(ctx.r3.u32); auto pTitleState = (SWA::CTitleStateBase*)g_memory.Translate(ctx.r3.u32);
auto pInputState = SWA::CInputState::GetInstance(); auto pInputState = SWA::CInputState::GetInstance();
auto& pPadState = pInputState->GetPadState(); auto& pPadState = pInputState->GetPadState();
auto isAccepted = pPadState.IsTapped(SWA::eKeyState_A) || pPadState.IsTapped(SWA::eKeyState_Start); auto isAccepted = pPadState.IsTapped(SWA::eKeyState_A) || pPadState.IsTapped(SWA::eKeyState_Start);
auto isOptionsIndex = pTitleState->m_pMember->m_pTitleMenu->m_CursorIndex == 2;
auto isInstallIndex = pTitleState->m_pMember->m_pTitleMenu->m_CursorIndex == 3; auto pContext = pTitleState->GetContextBase<SWA::CTitleStateBase::CTitleStateContext>();
auto isOptionsIndex = pContext->m_pTitleMenu->m_CursorIndex == 2;
auto isInstallIndex = pContext->m_pTitleMenu->m_CursorIndex == 3;
// Always default to New Game with corrupted save data.
if (App::s_isSaveDataCorrupt && pContext->m_pTitleMenu->m_CursorIndex == 1)
pContext->m_pTitleMenu->m_CursorIndex = 0;
if (!OptionsMenu::s_isVisible && isOptionsIndex) if (!OptionsMenu::s_isVisible && isOptionsIndex)
{ {
@@ -92,6 +99,14 @@ PPC_FUNC(sub_825882B8)
} }
} }
void TitleMenuRemoveContinueOnCorruptSaveMidAsmHook(PPCRegister& r3)
{
if (!App::s_isSaveDataCorrupt)
return;
r3.u64 = 0;
}
void TitleMenuRemoveStorageDeviceOptionMidAsmHook(PPCRegister& r11) void TitleMenuRemoveStorageDeviceOptionMidAsmHook(PPCRegister& r11)
{ {
r11.u32 = 0; r11.u32 = 0;
+16 -14
View File
@@ -1,6 +1,8 @@
#include <user/config.h> #include <user/config.h>
#include <api/SWA.h> #include <api/SWA.h>
#include <ui/game_window.h> #include <ui/game_window.h>
#include <gpu/video.h>
#include "aspect_ratio_patches.h"
using SVertexData = SWA::Sequence::Utility::CPlayMovieWrapper::CRender::SVertexData; using SVertexData = SWA::Sequence::Utility::CPlayMovieWrapper::CRender::SVertexData;
@@ -20,40 +22,40 @@ PPC_FUNC(sub_82AE30D8)
auto quadHeight = std::fabs(pTopLeft->Y - pBottomLeft->Y) * ((float)*pViewportHeight / 2); auto quadHeight = std::fabs(pTopLeft->Y - pBottomLeft->Y) * ((float)*pViewportHeight / 2);
auto movieAspectRatio = quadWidth / quadHeight; auto movieAspectRatio = quadWidth / quadHeight;
auto windowAspectRatio = (float)GameWindow::s_width / (float)GameWindow::s_height;
auto a = -1.00078f;
auto b = 1.00139f;
auto scaleU = 1.0f; auto scaleU = 1.0f;
auto scaleV = 1.0f; auto scaleV = 1.0f;
auto centreV = (pTopLeft->V + pBottomRight->V) / 2.0f; auto centreV = (pTopLeft->V + pBottomRight->V) / 2.0f;
if (windowAspectRatio > movieAspectRatio) if (g_aspectRatio > movieAspectRatio)
{ {
scaleU = movieAspectRatio / windowAspectRatio; scaleU = movieAspectRatio / g_aspectRatio;
} }
else else
{ {
scaleV = windowAspectRatio / movieAspectRatio; scaleV = g_aspectRatio / movieAspectRatio;
} }
pTopLeft->X = a; float halfPixelX = 1.0f / Video::s_viewportWidth;
pTopLeft->Y = b; float halfPixelY = 1.0f / Video::s_viewportHeight;
pTopLeft->X = -1.0f - halfPixelX;
pTopLeft->Y = 1.0f + halfPixelY;
pTopLeft->U = (pTopLeft->U - centreV) / scaleU + centreV; pTopLeft->U = (pTopLeft->U - centreV) / scaleU + centreV;
pTopLeft->V = (pTopLeft->V - centreV) / scaleV + centreV; pTopLeft->V = (pTopLeft->V - centreV) / scaleV + centreV;
pTopRight->X = b; pTopRight->X = 1.0f - halfPixelX;
pTopRight->Y = b; pTopRight->Y = 1.0f + halfPixelY;
pTopRight->U = (pTopRight->U - centreV) / scaleU + centreV; pTopRight->U = (pTopRight->U - centreV) / scaleU + centreV;
pTopRight->V = (pTopRight->V - centreV) / scaleV + centreV; pTopRight->V = (pTopRight->V - centreV) / scaleV + centreV;
pBottomLeft->X = a; pBottomLeft->X = -1.0f - halfPixelX;
pBottomLeft->Y = a; pBottomLeft->Y = -1.0f + halfPixelY;
pBottomLeft->U = (pBottomLeft->U - centreV) / scaleU + centreV; pBottomLeft->U = (pBottomLeft->U - centreV) / scaleU + centreV;
pBottomLeft->V = (pBottomLeft->V - centreV) / scaleV + centreV; pBottomLeft->V = (pBottomLeft->V - centreV) / scaleV + centreV;
pBottomRight->X = b; pBottomRight->X = 1.0f - halfPixelX;
pBottomRight->Y = a; pBottomRight->Y = -1.0f + halfPixelY;
pBottomRight->U = (pBottomRight->U - centreV) / scaleU + centreV; pBottomRight->U = (pBottomRight->U - centreV) / scaleU + centreV;
pBottomRight->V = (pBottomRight->V - centreV) / scaleV + centreV; pBottomRight->V = (pBottomRight->V - centreV) / scaleV + centreV;
+2 -2
View File
@@ -1,4 +1,4 @@
VERSION_MILESTONE="Alpha" VERSION_MILESTONE="Beta 1"
VERSION_MAJOR=0 VERSION_MAJOR=1
VERSION_MINOR=0 VERSION_MINOR=0
VERSION_REVISION=0 VERSION_REVISION=0
+1 -1
View File
@@ -13,7 +13,7 @@ using Microsoft::WRL::ComPtr;
#include <pwd.h> #include <pwd.h>
#endif #endif
#ifdef SWA_D3D12 #ifdef UNLEASHED_RECOMP_D3D12
#include <dxcapi.h> #include <dxcapi.h>
#endif #endif
+4 -4
View File
@@ -134,8 +134,8 @@ static void DrawHeaderContainer(const char* text)
? Lerp(1, 0, colourMotion) ? Lerp(1, 0, colourMotion)
: Lerp(0, 1, colourMotion); : Lerp(0, 1, colourMotion);
ImVec2 min = { Scale(g_aspectRatioOffsetX + containerMarginX), Scale(g_aspectRatioOffsetY + 136) }; ImVec2 min = { g_aspectRatioOffsetX + Scale(containerMarginX), g_aspectRatioOffsetY + Scale(136) };
ImVec2 max = { min.x + textMarginX * 2 + textSize.x + Scale(5), Scale(g_aspectRatioOffsetY + 196) }; ImVec2 max = { min.x + textMarginX * 2 + textSize.x + Scale(5), g_aspectRatioOffsetY + Scale(196) };
DrawPauseHeaderContainer(g_upWindow.get(), min, max, alpha); DrawPauseHeaderContainer(g_upWindow.get(), min, max, alpha);
@@ -568,8 +568,8 @@ static void DrawContentContainer()
? Hermite(604, 573, motion) ? Hermite(604, 573, motion)
: Hermite(573, 604, motion); : Hermite(573, 604, motion);
ImVec2 min = { Scale(g_aspectRatioOffsetX + minX), Scale(g_aspectRatioOffsetY + minY) }; ImVec2 min = { g_aspectRatioOffsetX + Scale(minX), g_aspectRatioOffsetY + Scale(minY) };
ImVec2 max = { Scale(g_aspectRatioOffsetX + maxX), Scale(g_aspectRatioOffsetY + maxY) }; ImVec2 max = { g_aspectRatioOffsetX + Scale(maxX), g_aspectRatioOffsetY + Scale(maxY) };
// Transparency fade animation. // Transparency fade animation.
auto alpha = g_isClosing auto alpha = g_isClosing
+4 -4
View File
@@ -2,7 +2,7 @@
#include "imgui_utils.h" #include "imgui_utils.h"
#include <gpu/imgui/imgui_snapshot.h> #include <gpu/imgui/imgui_snapshot.h>
#include <gpu/video.h> #include <gpu/video.h>
#include <hid/hid_detail.h> #include <hid/hid.h>
#include <user/config.h> #include <user/config.h>
#include <app.h> #include <app.h>
#include <decompressor.h> #include <decompressor.h>
@@ -63,7 +63,7 @@ std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon
GuestTexture* texture; GuestTexture* texture;
auto isPlayStation = Config::ControllerIcons == EControllerIcons::Auto auto isPlayStation = Config::ControllerIcons == EControllerIcons::Auto
? hid::detail::g_inputDeviceController == hid::detail::EInputDevice::PlayStation ? hid::g_inputDeviceController == hid::EInputDevice::PlayStation
: Config::ControllerIcons == EControllerIcons::PlayStation; : Config::ControllerIcons == EControllerIcons::PlayStation;
auto yOffsetCmn = isPlayStation ? 42 : 0; auto yOffsetCmn = isPlayStation ? 42 : 0;
@@ -229,8 +229,8 @@ void ButtonGuide::Draw()
auto drawList = ImGui::GetForegroundDrawList(); auto drawList = ImGui::GetForegroundDrawList();
auto& res = ImGui::GetIO().DisplaySize; auto& res = ImGui::GetIO().DisplaySize;
ImVec2 regionMin = { Scale(g_aspectRatioOffsetX + g_sideMargins), Scale(g_aspectRatioOffsetY * 2.0f + 720.0f - 102.0f) }; ImVec2 regionMin = { g_aspectRatioOffsetX + Scale(g_sideMargins), g_aspectRatioOffsetY * 2.0f + Scale(720.0f - 102.0f) };
ImVec2 regionMax = { Scale(g_aspectRatioOffsetX + 1280.0f - g_sideMargins), Scale(g_aspectRatioOffsetY * 2.0f + 720.0f) }; ImVec2 regionMax = { g_aspectRatioOffsetX + Scale(1280.0f - g_sideMargins), g_aspectRatioOffsetY * 2.0f + Scale(720.0f) };
auto textMarginX = Scale(57); auto textMarginX = Scale(57);
auto textMarginY = Scale(8); auto textMarginY = Scale(8);
+9 -4
View File
@@ -214,7 +214,7 @@ void GameWindow::Init(const char* sdlVideoDriver)
if (!IsPositionValid()) if (!IsPositionValid())
GameWindow::ResetDimensions(); GameWindow::ResetDimensions();
s_pWindow = SDL_CreateWindow("SWA", s_x, s_y, s_width, s_height, GetWindowFlags()); s_pWindow = SDL_CreateWindow("Unleashed Recompiled", s_x, s_y, s_width, s_height, GetWindowFlags());
if (IsFullscreen()) if (IsFullscreen())
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
@@ -298,9 +298,14 @@ void GameWindow::SetIcon(bool isNight)
const char* GameWindow::GetTitle() const char* GameWindow::GetTitle()
{ {
return Config::Language == ELanguage::Japanese if (Config::UseOfficialTitleOnTitleBar)
? "SONIC WORLD ADVENTURE" {
: "SONIC UNLEASHED"; return Config::Language == ELanguage::Japanese
? "SONIC WORLD ADVENTURE"
: "SONIC UNLEASHED";
}
return "Unleashed Recompiled";
} }
void GameWindow::SetTitle(const char* title) void GameWindow::SetTitle(const char* title)
+12 -6
View File
@@ -108,14 +108,20 @@ inline void ResetProceduralOrigin()
SetProceduralOrigin({ 0.0f, 0.0f }); SetProceduralOrigin({ 0.0f, 0.0f });
} }
inline void SetAdditive(bool enabled)
{
auto callbackData = AddImGuiCallback(ImGuiCallback::SetAdditive);
callbackData->setAdditive.enabled = enabled;
}
inline void ResetAdditive()
{
SetAdditive(false);
}
inline float Scale(float size) inline float Scale(float size)
{ {
auto& io = ImGui::GetIO(); return size * g_aspectRatioScale;
if (g_aspectRatio >= NARROW_ASPECT_RATIO)
return size * (io.DisplaySize.y / 720.0f);
else
return size * (io.DisplaySize.x / 960.0f);
} }
inline double ComputeMotion(double duration, double offset, double total) inline double ComputeMotion(double duration, double offset, double total)
+52 -48
View File
@@ -7,7 +7,6 @@
#include <gpu/video.h> #include <gpu/video.h>
#include <gpu/imgui/imgui_snapshot.h> #include <gpu/imgui/imgui_snapshot.h>
#include <hid/hid.h> #include <hid/hid.h>
#include <hid/hid_detail.h>
#include <locale/locale.h> #include <locale/locale.h>
#include <patches/aspect_ratio_patches.h> #include <patches/aspect_ratio_patches.h>
#include <ui/imgui_utils.h> #include <ui/imgui_utils.h>
@@ -16,6 +15,7 @@
#include <ui/sdl_listener.h> #include <ui/sdl_listener.h>
#include <ui/game_window.h> #include <ui/game_window.h>
#include <decompressor.h> #include <decompressor.h>
#include <exports.h>
#include <res/images/common/hedge-dev.dds.h> #include <res/images/common/hedge-dev.dds.h>
#include <res/images/installer/install_001.dds.h> #include <res/images/installer/install_001.dds.h>
@@ -448,7 +448,7 @@ static void DrawLeftImage()
GuestTexture *guestTexture = g_installTextures[installTextureIndex % g_installTextures.size()].get(); GuestTexture *guestTexture = g_installTextures[installTextureIndex % g_installTextures.size()].get();
auto &res = ImGui::GetIO().DisplaySize; auto &res = ImGui::GetIO().DisplaySize;
auto drawList = ImGui::GetForegroundDrawList(); auto drawList = ImGui::GetForegroundDrawList();
ImVec2 min = { Scale(g_aspectRatioOffsetX + IMAGE_X), Scale(g_aspectRatioOffsetY + IMAGE_Y) }; ImVec2 min = { g_aspectRatioOffsetX + Scale(IMAGE_X), g_aspectRatioOffsetY + Scale(IMAGE_Y) };
ImVec2 max = { min.x + Scale(IMAGE_WIDTH), min.y + Scale(IMAGE_HEIGHT) }; ImVec2 max = { min.x + Scale(IMAGE_WIDTH), min.y + Scale(IMAGE_HEIGHT) };
drawList->AddImage(guestTexture, min, max, ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, a)); drawList->AddImage(guestTexture, min, max, ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, a));
} }
@@ -458,9 +458,9 @@ static void DrawHeaderIconsForInstallPhase(double iconsPosX, double iconsPosY, d
auto drawList = ImGui::GetForegroundDrawList(); auto drawList = ImGui::GetForegroundDrawList();
// Arrow Circle Icon // Arrow Circle Icon
ImVec2 arrowCircleMin = { Scale(iconsPosX - iconsScale / 2), Scale(iconsPosY - iconsScale / 2) }; ImVec2 arrowCircleMin = { g_aspectRatioOffsetX + Scale(iconsPosX - iconsScale / 2), Scale(iconsPosY - iconsScale / 2) };
ImVec2 arrowCircleMax = { Scale(iconsPosX + iconsScale / 2), Scale(iconsPosY + iconsScale / 2) }; ImVec2 arrowCircleMax = { g_aspectRatioOffsetX + Scale(iconsPosX + iconsScale / 2), Scale(iconsPosY + iconsScale / 2) };
ImVec2 center = { Scale(iconsPosX) + 0.5f, Scale(iconsPosY) - 0.5f }; ImVec2 center = { g_aspectRatioOffsetX + Scale(iconsPosX) + 0.5f, Scale(iconsPosY) - 0.5f };
float arrowCircleFadeMotion = ComputeMotionInstaller(g_installerStartTime, g_installerEndTime, INSTALL_ICONS_FADE_IN_ANIMATION_TIME, INSTALL_ICONS_FADE_IN_ANIMATION_DURATION); float arrowCircleFadeMotion = ComputeMotionInstaller(g_installerStartTime, g_installerEndTime, INSTALL_ICONS_FADE_IN_ANIMATION_TIME, INSTALL_ICONS_FADE_IN_ANIMATION_DURATION);
float rotationMotion = ComputeMotionInstallerLoop(g_installerStartTime, ARROW_CIRCLE_LOOP_SPEED, 0); float rotationMotion = ComputeMotionInstallerLoop(g_installerStartTime, ARROW_CIRCLE_LOOP_SPEED, 0);
@@ -503,8 +503,8 @@ static void DrawHeaderIconsForInstallPhase(double iconsPosX, double iconsPosY, d
float pulseScale = iconsScale * pulseHermiteMotion * 1.5; float pulseScale = iconsScale * pulseHermiteMotion * 1.5;
ImVec2 pulseMin = { Scale(iconsPosX - pulseScale / 2), Scale(iconsPosY - pulseScale / 2) }; ImVec2 pulseMin = { g_aspectRatioOffsetX + Scale(iconsPosX - pulseScale / 2), Scale(iconsPosY - pulseScale / 2) };
ImVec2 pulseMax = { Scale(iconsPosX + pulseScale / 2), Scale(iconsPosY + pulseScale / 2) }; ImVec2 pulseMax = { g_aspectRatioOffsetX + Scale(iconsPosX + pulseScale / 2), Scale(iconsPosY + pulseScale / 2) };
drawList->AddImage(g_pulseInstall.get(), pulseMin, pulseMax, ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 255 * pulseFade * pulseFadeMotion)); drawList->AddImage(g_pulseInstall.get(), pulseMin, pulseMax, ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 255 * pulseFade * pulseFadeMotion));
} }
@@ -512,7 +512,7 @@ static void DrawHeaderIcons()
{ {
auto drawList = ImGui::GetForegroundDrawList(); auto drawList = ImGui::GetForegroundDrawList();
float iconsPosX = g_aspectRatioOffsetX + 253.0f; float iconsPosX = 253.0f;
float iconsPosY = 79.0f; float iconsPosY = 79.0f;
float iconsScale = 58; float iconsScale = 58;
@@ -520,8 +520,8 @@ static void DrawHeaderIcons()
float milesIconMotion = ComputeMotionInstaller(g_appearTime, g_disappearTime, MILES_ICON_ANIMATION_TIME, MILES_ICON_ANIMATION_DURATION); float milesIconMotion = ComputeMotionInstaller(g_appearTime, g_disappearTime, MILES_ICON_ANIMATION_TIME, MILES_ICON_ANIMATION_DURATION);
float milesIconScale = iconsScale * (2 - milesIconMotion); float milesIconScale = iconsScale * (2 - milesIconMotion);
ImVec2 milesElectricMin = { Scale(iconsPosX - milesIconScale / 2), Scale(iconsPosY - milesIconScale / 2) }; ImVec2 milesElectricMin = { g_aspectRatioOffsetX + Scale(iconsPosX - milesIconScale / 2), Scale(iconsPosY - milesIconScale / 2) };
ImVec2 milesElectricMax = { Scale(iconsPosX + milesIconScale / 2), Scale(iconsPosY + milesIconScale / 2) }; ImVec2 milesElectricMax = { g_aspectRatioOffsetX + Scale(iconsPosX + milesIconScale / 2), Scale(iconsPosY + milesIconScale / 2) };
drawList->AddImage(g_milesElectricIcon.get(), milesElectricMin, milesElectricMax, ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 255 * milesIconMotion)); drawList->AddImage(g_milesElectricIcon.get(), milesElectricMin, milesElectricMax, ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 255 * milesIconMotion));
if (int(g_currentPage) >= int(WizardPage::Installing)) if (int(g_currentPage) >= int(WizardPage::Installing))
@@ -578,7 +578,7 @@ static void DrawScanlineBars()
// Installer text // Installer text
const std::string &headerText = Localise(g_currentPage == WizardPage::Installing ? "Installer_Header_Installing" : "Installer_Header_Installer"); const std::string &headerText = Localise(g_currentPage == WizardPage::Installing ? "Installer_Header_Installing" : "Installer_Header_Installer");
auto alphaMotion = ComputeMotionInstaller(g_appearTime, g_disappearTime, TITLE_ANIMATION_TIME, TITLE_ANIMATION_DURATION); auto alphaMotion = ComputeMotionInstaller(g_appearTime, g_disappearTime, TITLE_ANIMATION_TIME, TITLE_ANIMATION_DURATION);
DrawTextWithOutline(g_dfsogeistdFont, Scale(42.0f), { Scale(g_aspectRatioOffsetX + 285.0f), Scale(57.0f) }, IM_COL32(255, 195, 0, 255 * alphaMotion), headerText.c_str(), 4, IM_COL32(0, 0, 0, 255 * alphaMotion), IMGUI_SHADER_MODIFIER_TITLE_BEVEL); DrawTextWithOutline(g_dfsogeistdFont, Scale(42.0f), { g_aspectRatioOffsetX + Scale(285.0f), Scale(57.0f) }, IM_COL32(255, 195, 0, 255 * alphaMotion), headerText.c_str(), 4, IM_COL32(0, 0, 0, 255 * alphaMotion), IMGUI_SHADER_MODIFIER_TITLE_BEVEL);
// Top bar line // Top bar line
drawList->AddLine drawList->AddLine
@@ -613,13 +613,15 @@ static void DrawContainer(ImVec2 min, ImVec2 max, bool isTextArea)
); );
double gridOverlayAlpha = ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_INNER_TIME, CONTAINER_INNER_DURATION); double gridOverlayAlpha = ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_INNER_TIME, CONTAINER_INNER_DURATION);
const uint32_t gridColor = IM_COL32(0, 33, 0, (isTextArea ? 128 : 255) * gridAlpha); const uint32_t gridColor = IM_COL32(0, 33, 0, (isTextArea ? 223 : 255) * gridAlpha);
const uint32_t gridOverlayColor = IM_COL32(0, 32, 0, 128 * gridOverlayAlpha); const uint32_t gridOverlayColor = IM_COL32(0, 32, 0, 128 * gridOverlayAlpha);
float gridSize = Scale(GRID_SIZE); float gridSize = Scale(GRID_SIZE);
SetShaderModifier(IMGUI_SHADER_MODIFIER_CHECKERBOARD); SetShaderModifier(IMGUI_SHADER_MODIFIER_CHECKERBOARD);
SetAdditive(true);
drawList->AddRectFilled(min, max, gridColor); drawList->AddRectFilled(min, max, gridColor);
SetAdditive(false);
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE); SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
if (isTextArea) if (isTextArea)
@@ -637,8 +639,8 @@ static void DrawDescriptionContainer()
auto drawList = ImGui::GetForegroundDrawList(); auto drawList = ImGui::GetForegroundDrawList();
auto fontSize = Scale(26.0f); auto fontSize = Scale(26.0f);
ImVec2 descriptionMin = { Scale(g_aspectRatioOffsetX + CONTAINER_X), Scale(g_aspectRatioOffsetY + CONTAINER_Y) }; ImVec2 descriptionMin = { g_aspectRatioOffsetX + Scale(CONTAINER_X), g_aspectRatioOffsetY + Scale(CONTAINER_Y) };
ImVec2 descriptionMax = { Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH), Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT) }; ImVec2 descriptionMax = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT) };
SetProceduralOrigin(descriptionMin); SetProceduralOrigin(descriptionMin);
DrawContainer(descriptionMin, descriptionMax, true); DrawContainer(descriptionMin, descriptionMax, true);
@@ -687,22 +689,24 @@ static void DrawDescriptionContainer()
auto imageScale = hedgeDevTextSize.x / 3; auto imageScale = hedgeDevTextSize.x / 3;
auto imageMarginY = Scale(15); auto imageMarginY = Scale(15);
auto colWhite = IM_COL32(255, 255, 255, 255 * textAlpha);
ImVec2 imageMin = ImVec2 imageMin =
{ {
/* X */ Scale(g_aspectRatioOffsetX + CONTAINER_X) + (Scale(CONTAINER_WIDTH) / 2) - (imageScale / 2) - (hedgeDevTextSize.x / 2) - hedgeDevTextMarginX, /* X */ g_aspectRatioOffsetX + Scale(CONTAINER_X) + (Scale(CONTAINER_WIDTH) / 2) - (imageScale / 2) - (hedgeDevTextSize.x / 2) - hedgeDevTextMarginX,
/* Y */ Scale(g_aspectRatioOffsetY + CONTAINER_Y) + (Scale(CONTAINER_HEIGHT) / 2) - (imageScale / 2) + imageMarginY /* Y */ g_aspectRatioOffsetY + Scale(CONTAINER_Y) + (Scale(CONTAINER_HEIGHT) / 2) - (imageScale / 2) + imageMarginY
}; };
ImVec2 imageMax = { imageMin.x + imageScale, imageMin.y + imageScale }; ImVec2 imageMax = { imageMin.x + imageScale, imageMin.y + imageScale };
drawList->AddImage(g_upHedgeDev.get(), imageMin, imageMax); drawList->AddImage(g_upHedgeDev.get(), imageMin, imageMax, { 0, 0 }, { 1, 1 }, colWhite);
drawList->AddText drawList->AddText
( (
g_seuratFont, g_seuratFont,
fontSize, fontSize,
{ /* X */ imageMax.x + hedgeDevTextMarginX, /* Y */ imageMin.y + (imageScale / 2) - (hedgeDevTextSize.y / 2) }, { /* X */ imageMax.x + hedgeDevTextMarginX, /* Y */ imageMin.y + (imageScale / 2) - (hedgeDevTextSize.y / 2) },
IM_COL32_WHITE, colWhite,
hedgeDevStr hedgeDevStr
); );
@@ -710,12 +714,12 @@ static void DrawDescriptionContainer()
auto marqueeTextMarginX = Scale(5); auto marqueeTextMarginX = Scale(5);
auto marqueeTextMarginY = Scale(15); auto marqueeTextMarginY = Scale(15);
ImVec2 textPos = { descriptionMax.x, Scale(g_aspectRatioOffsetY + CONTAINER_Y) + Scale(CONTAINER_HEIGHT) - marqueeTextSize.y - marqueeTextMarginY }; ImVec2 textPos = { descriptionMax.x, g_aspectRatioOffsetY + Scale(CONTAINER_Y) + Scale(CONTAINER_HEIGHT) - marqueeTextSize.y - marqueeTextMarginY };
ImVec2 textMin = { Scale(g_aspectRatioOffsetX + CONTAINER_X), textPos.y }; ImVec2 textMin = { g_aspectRatioOffsetX + Scale(CONTAINER_X), textPos.y };
ImVec2 textMax = { Scale(g_aspectRatioOffsetX + CONTAINER_X) + Scale(CONTAINER_WIDTH), Scale(g_aspectRatioOffsetY + CONTAINER_Y) + Scale(CONTAINER_HEIGHT) }; ImVec2 textMax = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + Scale(CONTAINER_WIDTH), g_aspectRatioOffsetY + Scale(CONTAINER_Y) + Scale(CONTAINER_HEIGHT) };
SetMarqueeFade(textMin, textMax, Scale(32)); SetMarqueeFade(textMin, textMax, Scale(32));
DrawTextWithMarquee(g_seuratFont, fontSize, textPos, textMin, textMax, IM_COL32_WHITE, CREDITS_TEXT, g_appearTime, 0.9, Scale(250)); DrawTextWithMarquee(g_seuratFont, fontSize, textPos, textMin, textMax, colWhite, CREDITS_TEXT, g_appearTime, 0.9, Scale(250));
ResetMarqueeFade(); ResetMarqueeFade();
} }
@@ -726,9 +730,9 @@ static void DrawDescriptionContainer()
if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0) if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
{ {
auto icon = hid::detail::IsInputDeviceController() auto icon = hid::IsInputDeviceController()
? EButtonIcon::A ? EButtonIcon::A
: hid::detail::g_inputDevice == hid::detail::EInputDevice::Keyboard : hid::g_inputDevice == hid::EInputDevice::Keyboard
? EButtonIcon::Enter ? EButtonIcon::Enter
: EButtonIcon::LMB; : EButtonIcon::LMB;
@@ -845,16 +849,16 @@ static void ComputeButtonColumnCoordinates(ButtonColumn buttonColumn, float &min
switch (buttonColumn) switch (buttonColumn)
{ {
case ButtonColumnLeft: case ButtonColumnLeft:
minX = Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_BUTTON_GAP); minX = g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_BUTTON_GAP);
maxX = Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_BUTTON_GAP + CONTAINER_BUTTON_WIDTH); maxX = g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_BUTTON_GAP + CONTAINER_BUTTON_WIDTH);
break; break;
case ButtonColumnMiddle: case ButtonColumnMiddle:
minX = Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH / 2.0f - CONTAINER_BUTTON_WIDTH / 2.0f); minX = g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH / 2.0f - CONTAINER_BUTTON_WIDTH / 2.0f);
maxX = Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH / 2.0f + CONTAINER_BUTTON_WIDTH / 2.0f); maxX = g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH / 2.0f + CONTAINER_BUTTON_WIDTH / 2.0f);
break; break;
case ButtonColumnRight: case ButtonColumnRight:
minX = Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH - CONTAINER_BUTTON_GAP - CONTAINER_BUTTON_WIDTH); minX = g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - CONTAINER_BUTTON_GAP - CONTAINER_BUTTON_WIDTH);
maxX = Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH - CONTAINER_BUTTON_GAP); maxX = g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - CONTAINER_BUTTON_GAP);
break; break;
} }
} }
@@ -866,8 +870,8 @@ static void DrawSourceButton(ButtonColumn buttonColumn, float yRatio, const char
ComputeButtonColumnCoordinates(buttonColumn, minX, maxX); ComputeButtonColumnCoordinates(buttonColumn, minX, maxX);
float minusY = (CONTAINER_BUTTON_GAP + BUTTON_HEIGHT) * yRatio; float minusY = (CONTAINER_BUTTON_GAP + BUTTON_HEIGHT) * yRatio;
ImVec2 min = { minX, Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - BUTTON_HEIGHT - minusY) }; ImVec2 min = { minX, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - BUTTON_HEIGHT - minusY) };
ImVec2 max = { maxX, Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - minusY) }; ImVec2 max = { maxX, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - minusY) };
DrawButton(min, max, sourceText, true, sourceSet, buttonPressed); DrawButton(min, max, sourceText, true, sourceSet, buttonPressed);
} }
@@ -880,8 +884,8 @@ static void DrawProgressBar(float progressRatio)
const uint32_t innerColor1 = IM_COL32(0, 32, 0, 255 * alpha); const uint32_t innerColor1 = IM_COL32(0, 32, 0, 255 * alpha);
float xPadding = Scale(6.0f); float xPadding = Scale(6.0f);
float yPadding = Scale(3.0f); float yPadding = Scale(3.0f);
ImVec2 min = { Scale(g_aspectRatioOffsetX + CONTAINER_X) + BOTTOM_X_GAP, Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) }; ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + BOTTOM_X_GAP, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
ImVec2 max = { Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) }; ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
DrawButtonContainer(min, max, 0, 0, alpha); DrawButtonContainer(min, max, 0, 0, alpha);
@@ -1068,8 +1072,8 @@ static void DrawLanguagePicker()
ComputeButtonColumnCoordinates((i < 3) ? ButtonColumnLeft : ButtonColumnRight, minX, maxX); ComputeButtonColumnCoordinates((i < 3) ? ButtonColumnLeft : ButtonColumnRight, minX, maxX);
float minusY = (CONTAINER_BUTTON_GAP + BUTTON_HEIGHT) * (float(i % 3)); float minusY = (CONTAINER_BUTTON_GAP + BUTTON_HEIGHT) * (float(i % 3));
ImVec2 min = { minX, Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - BUTTON_HEIGHT - minusY) }; ImVec2 min = { minX, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - BUTTON_HEIGHT - minusY) };
ImVec2 max = { maxX, Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - minusY) }; ImVec2 max = { maxX, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - minusY) };
// TODO: The active button should change its style to show an enabled toggle if it matches the current language. // TODO: The active button should change its style to show an enabled toggle if it matches the current language.
@@ -1094,8 +1098,8 @@ static void DrawSourcePickers()
ImVec2 textSize = ComputeTextSize(g_dfsogeistdFont, addFilesText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH); ImVec2 textSize = ComputeTextSize(g_dfsogeistdFont, addFilesText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH);
textSize.x += BUTTON_TEXT_GAP; textSize.x += BUTTON_TEXT_GAP;
ImVec2 min = { Scale(g_aspectRatioOffsetX + CONTAINER_X + BOTTOM_X_GAP), Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) }; ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X + BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
ImVec2 max = { Scale(g_aspectRatioOffsetX + CONTAINER_X + BOTTOM_X_GAP + textSize.x * squashRatio), Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) }; ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + BOTTOM_X_GAP + textSize.x * squashRatio), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
DrawButton(min, max, addFilesText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH); DrawButton(min, max, addFilesText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
if (buttonPressed) if (buttonPressed)
{ {
@@ -1230,8 +1234,8 @@ static void DrawNextButton()
ImVec2 textSize = ComputeTextSize(g_newRodinFont, buttonText.c_str(), 20.0f, squashRatio, NEXT_BUTTON_MAX_TEXT_WIDTH); ImVec2 textSize = ComputeTextSize(g_newRodinFont, buttonText.c_str(), 20.0f, squashRatio, NEXT_BUTTON_MAX_TEXT_WIDTH);
textSize.x += BUTTON_TEXT_GAP; textSize.x += BUTTON_TEXT_GAP;
ImVec2 min = { Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH - textSize.x * squashRatio - BOTTOM_X_GAP), Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) }; ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - textSize.x * squashRatio - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
ImVec2 max = { Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) }; ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
bool buttonPressed = false; bool buttonPressed = false;
DrawButton(min, max, buttonText.c_str(), false, nextButtonEnabled, buttonPressed, NEXT_BUTTON_MAX_TEXT_WIDTH); DrawButton(min, max, buttonText.c_str(), false, nextButtonEnabled, buttonPressed, NEXT_BUTTON_MAX_TEXT_WIDTH);
@@ -1316,10 +1320,10 @@ static void DrawHorizontalBorder(bool bottomBorder)
const uint32_t FADE_COLOR_RIGHT = IM_COL32(155, 225, 155, 0); const uint32_t FADE_COLOR_RIGHT = IM_COL32(155, 225, 155, 0);
auto drawList = ImGui::GetForegroundDrawList(); auto drawList = ImGui::GetForegroundDrawList();
double borderScale = 1.0 - ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_LINE_ANIMATION_TIME, CONTAINER_LINE_ANIMATION_DURATION); double borderScale = 1.0 - ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_LINE_ANIMATION_TIME, CONTAINER_LINE_ANIMATION_DURATION);
float midX = Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH / 5); float midX = g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH / 5);
float minX = std::lerp(Scale(g_aspectRatioOffsetX + CONTAINER_X - BORDER_SIZE - BORDER_OVERSHOOT), midX, borderScale); float minX = std::lerp(g_aspectRatioOffsetX + Scale(CONTAINER_X - BORDER_SIZE - BORDER_OVERSHOOT), midX, borderScale);
float maxX = std::lerp(Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH + SIDE_CONTAINER_WIDTH + BORDER_OVERSHOOT), midX, borderScale); float maxX = std::lerp(g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH + SIDE_CONTAINER_WIDTH + BORDER_OVERSHOOT), midX, borderScale);
float minY = bottomBorder ? Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT) : Scale(g_aspectRatioOffsetY + CONTAINER_Y - BORDER_SIZE); float minY = g_aspectRatioOffsetY + (bottomBorder ? Scale(CONTAINER_Y + CONTAINER_HEIGHT) : Scale(CONTAINER_Y - BORDER_SIZE));
float maxY = minY + Scale(BORDER_SIZE); float maxY = minY + Scale(BORDER_SIZE);
drawList->AddRectFilledMultiColor drawList->AddRectFilledMultiColor
( (
@@ -1348,11 +1352,11 @@ static void DrawVerticalBorder(bool rightBorder)
const uint32_t FADE_COLOR = IM_COL32(155, rightBorder ? 225 : 155, 155, 0); const uint32_t FADE_COLOR = IM_COL32(155, rightBorder ? 225 : 155, 155, 0);
auto drawList = ImGui::GetForegroundDrawList(); auto drawList = ImGui::GetForegroundDrawList();
double borderScale = 1.0 - ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_LINE_ANIMATION_TIME, CONTAINER_LINE_ANIMATION_DURATION); double borderScale = 1.0 - ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_LINE_ANIMATION_TIME, CONTAINER_LINE_ANIMATION_DURATION);
float minX = rightBorder ? Scale(g_aspectRatioOffsetX + CONTAINER_X + CONTAINER_WIDTH) : Scale(g_aspectRatioOffsetX + CONTAINER_X - BORDER_SIZE); float minX = g_aspectRatioOffsetX + (rightBorder ? Scale(CONTAINER_X + CONTAINER_WIDTH) : Scale(CONTAINER_X - BORDER_SIZE));
float maxX = minX + Scale(BORDER_SIZE); float maxX = minX + Scale(BORDER_SIZE);
float midY = Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT / 2); float midY = g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT / 2);
float minY = std::lerp(Scale(g_aspectRatioOffsetY + CONTAINER_Y - BORDER_OVERSHOOT), midY, borderScale); float minY = std::lerp(g_aspectRatioOffsetY + Scale(CONTAINER_Y - BORDER_OVERSHOOT), midY, borderScale);
float maxY = std::lerp(Scale(g_aspectRatioOffsetY + CONTAINER_Y + CONTAINER_HEIGHT + BORDER_OVERSHOOT), midY, borderScale); float maxY = std::lerp(g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BORDER_OVERSHOOT), midY, borderScale);
drawList->AddRectFilledMultiColor drawList->AddRectFilledMultiColor
( (
{ minX, minY }, { minX, minY },
+4 -4
View File
@@ -2,7 +2,7 @@
#include "imgui_utils.h" #include "imgui_utils.h"
#include <api/SWA.h> #include <api/SWA.h>
#include <gpu/video.h> #include <gpu/video.h>
#include <hid/hid_detail.h> #include <hid/hid.h>
#include <locale/locale.h> #include <locale/locale.h>
#include <ui/button_guide.h> #include <ui/button_guide.h>
#include <ui/sdl_listener.h> #include <ui/sdl_listener.h>
@@ -257,7 +257,7 @@ static void ResetSelection()
{ {
/* Always use -1 for mouse input to prevent the selection /* Always use -1 for mouse input to prevent the selection
cursor from erroneously appearing where it shouldn't. */ cursor from erroneously appearing where it shouldn't. */
g_selectedRowIndex = hid::detail::g_inputDevice == hid::detail::EInputDevice::Mouse g_selectedRowIndex = hid::g_inputDevice == hid::EInputDevice::Mouse
? -1 ? -1
: g_defaultButtonIndex; : g_defaultButtonIndex;
@@ -294,8 +294,8 @@ void MessageWindow::Draw()
auto textMarginX = Scale(37); auto textMarginX = Scale(37);
auto textMarginY = Scale(45); auto textMarginY = Scale(45);
bool isController = hid::detail::IsInputDeviceController(); bool isController = hid::IsInputDeviceController();
bool isKeyboard = hid::detail::g_inputDevice == hid::detail::EInputDevice::Keyboard; bool isKeyboard = hid::g_inputDevice == hid::EInputDevice::Keyboard;
// Handle controller input when the game is booted. // Handle controller input when the game is booted.
if (App::s_isInit) if (App::s_isInit)
+21 -17
View File
@@ -5,6 +5,7 @@
#include "exports.h" #include "exports.h"
#include <api/SWA/System/InputState.h> #include <api/SWA/System/InputState.h>
#include <apu/audio.h>
#include <gpu/imgui/imgui_common.h> #include <gpu/imgui/imgui_common.h>
#include <gpu/video.h> #include <gpu/video.h>
#include <gpu/imgui/imgui_snapshot.h> #include <gpu/imgui/imgui_snapshot.h>
@@ -161,14 +162,14 @@ static void DrawScanlineBars()
if (g_aspectRatio >= WIDE_ASPECT_RATIO) if (g_aspectRatio >= WIDE_ASPECT_RATIO)
optionsX = g_aspectRatioOffsetX; optionsX = g_aspectRatioOffsetX;
else else
optionsX = (1.0f - g_narrowOffsetScale) * -20.0f; optionsX = (1.0f - g_aspectRatioNarrowScale) * g_aspectRatioScale * -20.0f;
// Options text // Options text
DrawTextWithOutline DrawTextWithOutline
( (
g_dfsogeistdFont, g_dfsogeistdFont,
Scale(48.0f), Scale(48.0f),
{ Scale(optionsX + 122.0f), Scale(56.0f) }, { optionsX + Scale(122.0f), Scale(56.0f) },
IM_COL32(255, 190, 33, 255), IM_COL32(255, 190, 33, 255),
Localise("Options_Header_Name").c_str(), Localise("Options_Header_Name").c_str(),
4, 4,
@@ -322,7 +323,7 @@ static bool DrawCategories()
constexpr float WIDE_PADDING_GRID_COUNT = 3.0f; constexpr float WIDE_PADDING_GRID_COUNT = 3.0f;
float gridSize = Scale(GRID_SIZE); float gridSize = Scale(GRID_SIZE);
float textPadding = gridSize * Lerp(NARROW_PADDING_GRID_COUNT, WIDE_PADDING_GRID_COUNT, g_narrowOffsetScale); float textPadding = gridSize * Lerp(NARROW_PADDING_GRID_COUNT, WIDE_PADDING_GRID_COUNT, g_aspectRatioNarrowScale);
float tabPadding = gridSize; float tabPadding = gridSize;
float size = Scale(32.0f); float size = Scale(32.0f);
@@ -468,7 +469,7 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
constexpr float OPTION_WIDE_GRID_COUNT = 54.0f; constexpr float OPTION_WIDE_GRID_COUNT = 54.0f;
auto gridSize = Scale(GRID_SIZE); auto gridSize = Scale(GRID_SIZE);
auto optionWidth = gridSize * floor(Lerp(OPTION_NARROW_GRID_COUNT, OPTION_WIDE_GRID_COUNT, g_narrowOffsetScale)); auto optionWidth = gridSize * floor(Lerp(OPTION_NARROW_GRID_COUNT, OPTION_WIDE_GRID_COUNT, g_aspectRatioNarrowScale));
auto optionHeight = gridSize * 5.5f; auto optionHeight = gridSize * 5.5f;
auto optionPadding = gridSize * 0.5f; auto optionPadding = gridSize * 0.5f;
auto valueWidth = Scale(192.0f); auto valueWidth = Scale(192.0f);
@@ -507,6 +508,7 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
config->Callback(config); config->Callback(config);
VideoConfigValueChangedCallback(config); VideoConfigValueChangedCallback(config);
XAudioConfigValueChangedCallback(config);
Game_PlaySound("sys_worldmap_finaldecide"); Game_PlaySound("sys_worldmap_finaldecide");
} }
@@ -538,6 +540,7 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
if (config->Value != s_oldValue) if (config->Value != s_oldValue)
{ {
VideoConfigValueChangedCallback(config); VideoConfigValueChangedCallback(config);
XAudioConfigValueChangedCallback(config);
if (config->ApplyCallback) if (config->ApplyCallback)
config->ApplyCallback(config); config->ApplyCallback(config);
@@ -564,6 +567,7 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
config->MakeDefault(); config->MakeDefault();
VideoConfigValueChangedCallback(config); VideoConfigValueChangedCallback(config);
XAudioConfigValueChangedCallback(config);
if (config->Callback) if (config->Callback)
config->Callback(config); config->Callback(config);
@@ -883,6 +887,8 @@ static void DrawConfigOptions()
{ {
case 0: // SYSTEM case 0: // SYSTEM
DrawConfigOption(rowCount++, yOffset, &Config::Language, !OptionsMenu::s_isPause, cmnReason); DrawConfigOption(rowCount++, yOffset, &Config::Language, !OptionsMenu::s_isPause, cmnReason);
DrawConfigOption(rowCount++, yOffset, &Config::VoiceLanguage, OptionsMenu::s_pauseMenuType == SWA::eMenuType_WorldMap, cmnReason);
DrawConfigOption(rowCount++, yOffset, &Config::Subtitles, true);
DrawConfigOption(rowCount++, yOffset, &Config::Hints, !isStage, cmnReason); DrawConfigOption(rowCount++, yOffset, &Config::Hints, !isStage, cmnReason);
DrawConfigOption(rowCount++, yOffset, &Config::ControlTutorial, !isStage, cmnReason); DrawConfigOption(rowCount++, yOffset, &Config::ControlTutorial, !isStage, cmnReason);
DrawConfigOption(rowCount++, yOffset, &Config::AchievementNotifications, true); DrawConfigOption(rowCount++, yOffset, &Config::AchievementNotifications, true);
@@ -894,7 +900,6 @@ static void DrawConfigOptions()
DrawConfigOption(rowCount++, yOffset, &Config::InvertCameraY, true); DrawConfigOption(rowCount++, yOffset, &Config::InvertCameraY, true);
DrawConfigOption(rowCount++, yOffset, &Config::Vibration, true); DrawConfigOption(rowCount++, yOffset, &Config::Vibration, true);
DrawConfigOption(rowCount++, yOffset, &Config::AllowBackgroundInput, true); DrawConfigOption(rowCount++, yOffset, &Config::AllowBackgroundInput, true);
DrawConfigOption(rowCount++, yOffset, &Config::AllowDPadMovement, true);
DrawConfigOption(rowCount++, yOffset, &Config::ControllerIcons, true); DrawConfigOption(rowCount++, yOffset, &Config::ControllerIcons, true);
break; break;
@@ -902,8 +907,7 @@ static void DrawConfigOptions()
DrawConfigOption(rowCount++, yOffset, &Config::MasterVolume, true); DrawConfigOption(rowCount++, yOffset, &Config::MasterVolume, true);
DrawConfigOption(rowCount++, yOffset, &Config::MusicVolume, true); DrawConfigOption(rowCount++, yOffset, &Config::MusicVolume, true);
DrawConfigOption(rowCount++, yOffset, &Config::EffectsVolume, true); DrawConfigOption(rowCount++, yOffset, &Config::EffectsVolume, true);
DrawConfigOption(rowCount++, yOffset, &Config::VoiceLanguage, OptionsMenu::s_pauseMenuType == SWA::eMenuType_WorldMap, cmnReason); DrawConfigOption(rowCount++, yOffset, &Config::ChannelConfiguration, true);
DrawConfigOption(rowCount++, yOffset, &Config::Subtitles, true);
DrawConfigOption(rowCount++, yOffset, &Config::MusicAttenuation, AudioPatches::CanAttenuate(), &Localise("Options_Desc_OSNotSupported")); DrawConfigOption(rowCount++, yOffset, &Config::MusicAttenuation, AudioPatches::CanAttenuate(), &Localise("Options_Desc_OSNotSupported"));
DrawConfigOption(rowCount++, yOffset, &Config::BattleTheme, true); DrawConfigOption(rowCount++, yOffset, &Config::BattleTheme, true);
break; break;
@@ -1220,23 +1224,23 @@ void OptionsMenu::Draw()
DrawScanlineBars(); DrawScanlineBars();
float settingsGridCount = floor(Lerp(SETTINGS_NARROW_GRID_COUNT, SETTINGS_WIDE_GRID_COUNT, g_narrowOffsetScale)); float settingsGridCount = floor(Lerp(SETTINGS_NARROW_GRID_COUNT, SETTINGS_WIDE_GRID_COUNT, g_aspectRatioNarrowScale));
float paddingGridCount = Lerp(PADDING_NARROW_GRID_COUNT, PADDING_WIDE_GRID_COUNT, g_narrowOffsetScale); float paddingGridCount = Lerp(PADDING_NARROW_GRID_COUNT, PADDING_WIDE_GRID_COUNT, g_aspectRatioNarrowScale);
float infoGridCount = floor(Lerp(INFO_NARROW_GRID_COUNT, INFO_WIDE_GRID_COUNT, g_narrowOffsetScale)); float infoGridCount = floor(Lerp(INFO_NARROW_GRID_COUNT, INFO_WIDE_GRID_COUNT, g_aspectRatioNarrowScale));
float totalGridCount = settingsGridCount + paddingGridCount + infoGridCount; float totalGridCount = settingsGridCount + paddingGridCount + infoGridCount;
float offsetX = g_aspectRatioOffsetX + (1280.0f - ((GRID_SIZE * totalGridCount) - 1)) / 2.0f; float offsetX = (1280.0f - ((GRID_SIZE * totalGridCount) - 1)) / 2.0f;
float minY = Scale(g_aspectRatioOffsetY + CONTAINER_POS_Y); float minY = g_aspectRatioOffsetY + Scale(CONTAINER_POS_Y);
float maxY = Scale(g_aspectRatioOffsetY + (720.0f - CONTAINER_POS_Y + 1.0f)); float maxY = g_aspectRatioOffsetY + Scale((720.0f - CONTAINER_POS_Y + 1.0f));
DrawSettingsPanel( DrawSettingsPanel(
{ Scale(offsetX), minY }, { g_aspectRatioOffsetX + Scale(offsetX), minY },
{ Scale(offsetX + settingsGridCount * GRID_SIZE), maxY } { g_aspectRatioOffsetX + Scale(offsetX + settingsGridCount * GRID_SIZE), maxY }
); );
DrawInfoPanel( DrawInfoPanel(
{ Scale(offsetX + (settingsGridCount + paddingGridCount) * GRID_SIZE), minY }, { g_aspectRatioOffsetX + Scale(offsetX + (settingsGridCount + paddingGridCount) * GRID_SIZE), minY },
{ Scale(offsetX + totalGridCount * GRID_SIZE), maxY } { g_aspectRatioOffsetX + Scale(offsetX + totalGridCount * GRID_SIZE), maxY }
); );
if (g_isStage) if (g_isStage)
+4 -13
View File
@@ -4,7 +4,6 @@
// TODO (Hyper): lower the resolution of these textures once final. // TODO (Hyper): lower the resolution of these textures once final.
#include <res/images/options_menu/thumbnails/achievement_notifications.dds.h> #include <res/images/options_menu/thumbnails/achievement_notifications.dds.h>
#include <res/images/options_menu/thumbnails/allow_background_input.dds.h> #include <res/images/options_menu/thumbnails/allow_background_input.dds.h>
#include <res/images/options_menu/thumbnails/allow_dpad_movement.dds.h>
#include <res/images/options_menu/thumbnails/antialiasing.dds.h> #include <res/images/options_menu/thumbnails/antialiasing.dds.h>
#include <res/images/options_menu/thumbnails/aspect_ratio.dds.h> #include <res/images/options_menu/thumbnails/aspect_ratio.dds.h>
#include <res/images/options_menu/thumbnails/battle_theme.dds.h> #include <res/images/options_menu/thumbnails/battle_theme.dds.h>
@@ -46,8 +45,7 @@
#include <res/images/options_menu/thumbnails/vibration.dds.h> #include <res/images/options_menu/thumbnails/vibration.dds.h>
#include <res/images/options_menu/thumbnails/vsync.dds.h> #include <res/images/options_menu/thumbnails/vsync.dds.h>
#include <res/images/options_menu/thumbnails/window_size.dds.h> #include <res/images/options_menu/thumbnails/window_size.dds.h>
#include <res/images/options_menu/thumbnails/xbox_color_correction_false.dds.h> #include <res/images/options_menu/thumbnails/xbox_color_correction.dds.h>
#include <res/images/options_menu/thumbnails/xbox_color_correction_true.dds.h>
#define VALUE_THUMBNAIL_MAP(type) std::unordered_map<type, std::unique_ptr<GuestTexture>> #define VALUE_THUMBNAIL_MAP(type) std::unordered_map<type, std::unique_ptr<GuestTexture>>
@@ -67,6 +65,8 @@ void LoadThumbnails()
g_namedThumbnails["WindowSize"] = LOAD_ZSTD_TEXTURE(g_window_size); g_namedThumbnails["WindowSize"] = LOAD_ZSTD_TEXTURE(g_window_size);
g_configThumbnails[&Config::Language] = LOAD_ZSTD_TEXTURE(g_language); g_configThumbnails[&Config::Language] = LOAD_ZSTD_TEXTURE(g_language);
g_configThumbnails[&Config::VoiceLanguage] = LOAD_ZSTD_TEXTURE(g_voice_language);
g_configThumbnails[&Config::Subtitles] = LOAD_ZSTD_TEXTURE(g_subtitles);
g_configThumbnails[&Config::Hints] = LOAD_ZSTD_TEXTURE(g_hints); g_configThumbnails[&Config::Hints] = LOAD_ZSTD_TEXTURE(g_hints);
g_configThumbnails[&Config::ControlTutorial] = LOAD_ZSTD_TEXTURE(g_control_tutorial); g_configThumbnails[&Config::ControlTutorial] = LOAD_ZSTD_TEXTURE(g_control_tutorial);
g_configThumbnails[&Config::AchievementNotifications] = LOAD_ZSTD_TEXTURE(g_achievement_notifications); g_configThumbnails[&Config::AchievementNotifications] = LOAD_ZSTD_TEXTURE(g_achievement_notifications);
@@ -78,13 +78,10 @@ void LoadThumbnails()
g_configThumbnails[&Config::InvertCameraY] = LOAD_ZSTD_TEXTURE(g_invert_camera_y); g_configThumbnails[&Config::InvertCameraY] = LOAD_ZSTD_TEXTURE(g_invert_camera_y);
g_configThumbnails[&Config::Vibration] = LOAD_ZSTD_TEXTURE(g_vibration); g_configThumbnails[&Config::Vibration] = LOAD_ZSTD_TEXTURE(g_vibration);
g_configThumbnails[&Config::AllowBackgroundInput] = LOAD_ZSTD_TEXTURE(g_allow_background_input); g_configThumbnails[&Config::AllowBackgroundInput] = LOAD_ZSTD_TEXTURE(g_allow_background_input);
g_configThumbnails[&Config::AllowDPadMovement] = LOAD_ZSTD_TEXTURE(g_allow_dpad_movement);
g_configThumbnails[&Config::ControllerIcons] = LOAD_ZSTD_TEXTURE(g_controller_icons); g_configThumbnails[&Config::ControllerIcons] = LOAD_ZSTD_TEXTURE(g_controller_icons);
g_configThumbnails[&Config::MasterVolume] = LOAD_ZSTD_TEXTURE(g_master_volume); g_configThumbnails[&Config::MasterVolume] = LOAD_ZSTD_TEXTURE(g_master_volume);
g_configThumbnails[&Config::MusicVolume] = LOAD_ZSTD_TEXTURE(g_music_volume); g_configThumbnails[&Config::MusicVolume] = LOAD_ZSTD_TEXTURE(g_music_volume);
g_configThumbnails[&Config::EffectsVolume] = LOAD_ZSTD_TEXTURE(g_effects_volume); g_configThumbnails[&Config::EffectsVolume] = LOAD_ZSTD_TEXTURE(g_effects_volume);
g_configThumbnails[&Config::VoiceLanguage] = LOAD_ZSTD_TEXTURE(g_voice_language);
g_configThumbnails[&Config::Subtitles] = LOAD_ZSTD_TEXTURE(g_subtitles);
g_configThumbnails[&Config::MusicAttenuation] = LOAD_ZSTD_TEXTURE(g_music_attenuation); g_configThumbnails[&Config::MusicAttenuation] = LOAD_ZSTD_TEXTURE(g_music_attenuation);
g_configThumbnails[&Config::BattleTheme] = LOAD_ZSTD_TEXTURE(g_battle_theme); g_configThumbnails[&Config::BattleTheme] = LOAD_ZSTD_TEXTURE(g_battle_theme);
g_configThumbnails[&Config::WindowSize] = LOAD_ZSTD_TEXTURE(g_window_size); g_configThumbnails[&Config::WindowSize] = LOAD_ZSTD_TEXTURE(g_window_size);
@@ -114,9 +111,7 @@ void LoadThumbnails()
g_motionBlurThumbnails[EMotionBlur::Original] = LOAD_ZSTD_TEXTURE(g_motion_blur_original); g_motionBlurThumbnails[EMotionBlur::Original] = LOAD_ZSTD_TEXTURE(g_motion_blur_original);
g_motionBlurThumbnails[EMotionBlur::Enhanced] = LOAD_ZSTD_TEXTURE(g_motion_blur_enhanced); g_motionBlurThumbnails[EMotionBlur::Enhanced] = LOAD_ZSTD_TEXTURE(g_motion_blur_enhanced);
g_xboxColorCorrectionThumbnails[false] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction_false); g_configThumbnails[&Config::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
g_xboxColorCorrectionThumbnails[true] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction_true);
g_configThumbnails[&Config::UIScaleMode] = LOAD_ZSTD_TEXTURE(g_ui_scale_mode); g_configThumbnails[&Config::UIScaleMode] = LOAD_ZSTD_TEXTURE(g_ui_scale_mode);
} }
@@ -173,10 +168,6 @@ GuestTexture* GetThumbnail(const IConfigDef* cfg)
{ {
TryGetValueThumbnail<EMotionBlur>(cfg, &g_motionBlurThumbnails, &texture); TryGetValueThumbnail<EMotionBlur>(cfg, &g_motionBlurThumbnails, &texture);
} }
else if (cfg == &Config::XboxColorCorrection)
{
TryGetValueThumbnail<bool>(cfg, &g_xboxColorCorrectionThumbnails, &texture);
}
return texture; return texture;
} }
+470
View File
@@ -1,5 +1,475 @@
#include "config.h" #include "config.h"
#include <os/logger.h> #include <os/logger.h>
#include <user/paths.h>
#include <exports.h>
std::vector<IConfigDef*> g_configDefinitions;
#define CONFIG_DEFINE_ENUM_TEMPLATE(type) \
static std::unordered_map<std::string, type> g_##type##_template =
CONFIG_DEFINE_ENUM_TEMPLATE(ELanguage)
{
{ "English", ELanguage::English },
{ "Japanese", ELanguage::Japanese },
{ "German", ELanguage::German },
{ "French", ELanguage::French },
{ "Spanish", ELanguage::Spanish },
{ "Italian", ELanguage::Italian }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EUnleashGaugeBehaviour)
{
{ "Original", EUnleashGaugeBehaviour::Original },
{ "Revised", EUnleashGaugeBehaviour::Revised }
};
CONFIG_DEFINE_ENUM_TEMPLATE(ETimeOfDayTransition)
{
{ "Xbox", ETimeOfDayTransition::Xbox },
{ "PlayStation", ETimeOfDayTransition::PlayStation }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EControllerIcons)
{
{ "Auto", EControllerIcons::Auto },
{ "Xbox", EControllerIcons::Xbox },
{ "PlayStation", EControllerIcons::PlayStation }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EChannelConfiguration)
{
{ "Stereo", EChannelConfiguration::Stereo },
{ "Surround", EChannelConfiguration::Surround }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EVoiceLanguage)
{
{ "English", EVoiceLanguage::English },
{ "Japanese", EVoiceLanguage::Japanese }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EGraphicsAPI)
{
#ifdef UNLEASHED_RECOMP_D3D12
{ "D3D12", EGraphicsAPI::D3D12 },
#endif
{ "Vulkan", EGraphicsAPI::Vulkan }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EWindowState)
{
{ "Normal", EWindowState::Normal },
{ "Maximised", EWindowState::Maximised },
{ "Maximized", EWindowState::Maximised }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EAspectRatio)
{
{ "Auto", EAspectRatio::Auto },
{ "16:9", EAspectRatio::Wide },
{ "4:3", EAspectRatio::Narrow },
{ "Original 4:3", EAspectRatio::OriginalNarrow },
};
CONFIG_DEFINE_ENUM_TEMPLATE(ETripleBuffering)
{
{ "Auto", ETripleBuffering::Auto },
{ "On", ETripleBuffering::On },
{ "Off", ETripleBuffering::Off }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EAntiAliasing)
{
{ "None", EAntiAliasing::None },
{ "2x MSAA", EAntiAliasing::MSAA2x },
{ "4x MSAA", EAntiAliasing::MSAA4x },
{ "8x MSAA", EAntiAliasing::MSAA8x }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EShadowResolution)
{
{ "Original", EShadowResolution::Original },
{ "512", EShadowResolution::x512 },
{ "1024", EShadowResolution::x1024 },
{ "2048", EShadowResolution::x2048 },
{ "4096", EShadowResolution::x4096 },
{ "8192", EShadowResolution::x8192 },
};
CONFIG_DEFINE_ENUM_TEMPLATE(EGITextureFiltering)
{
{ "Bilinear", EGITextureFiltering::Bilinear },
{ "Bicubic", EGITextureFiltering::Bicubic }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EDepthOfFieldQuality)
{
{ "Auto", EDepthOfFieldQuality::Auto },
{ "Low", EDepthOfFieldQuality::Low },
{ "Medium", EDepthOfFieldQuality::Medium },
{ "High", EDepthOfFieldQuality::High },
{ "Ultra", EDepthOfFieldQuality::Ultra }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EMotionBlur)
{
{ "Off", EMotionBlur::Off },
{ "Original", EMotionBlur::Original },
{ "Enhanced", EMotionBlur::Enhanced }
};
CONFIG_DEFINE_ENUM_TEMPLATE(ECutsceneAspectRatio)
{
{ "Original", ECutsceneAspectRatio::Original },
{ "Unlocked", ECutsceneAspectRatio::Unlocked }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EUIScaleMode)
{
{ "Edge", EUIScaleMode::Edge },
{ "Centre", EUIScaleMode::Centre },
{ "Center", EUIScaleMode::Centre }
};
#undef CONFIG_DEFINE
#define CONFIG_DEFINE(section, type, name, defaultValue) \
ConfigDef<type> Config::name{section, #name, defaultValue};
#undef CONFIG_DEFINE_HIDDEN
#define CONFIG_DEFINE_HIDDEN(section, type, name, defaultValue) \
ConfigDef<type, true> Config::name{section, #name, defaultValue};
#undef CONFIG_DEFINE_LOCALISED
#define CONFIG_DEFINE_LOCALISED(section, type, name, defaultValue) \
extern CONFIG_LOCALE g_##name##_locale; \
ConfigDef<type> Config::name{section, #name, &g_##name##_locale, defaultValue};
#undef CONFIG_DEFINE_ENUM
#define CONFIG_DEFINE_ENUM(section, type, name, defaultValue) \
ConfigDef<type> Config::name{section, #name, defaultValue, &g_##type##_template};
#undef CONFIG_DEFINE_ENUM_LOCALISED
#define CONFIG_DEFINE_ENUM_LOCALISED(section, type, name, defaultValue) \
extern CONFIG_LOCALE g_##name##_locale; \
extern CONFIG_ENUM_LOCALE(type) g_##type##_locale; \
ConfigDef<type> Config::name{section, #name, &g_##name##_locale, defaultValue, &g_##type##_template, &g_##type##_locale};
#undef CONFIG_DEFINE_CALLBACK
#define CONFIG_DEFINE_CALLBACK(section, type, name, defaultValue, readCallback) \
extern CONFIG_LOCALE g_##name##_locale; \
ConfigDef<type> Config::name{section, #name, defaultValue, [](ConfigDef<type>* def) readCallback};
#include "config_def.h"
// CONFIG_DEFINE
template<typename T, bool isHidden>
ConfigDef<T, isHidden>::ConfigDef(std::string section, std::string name, T defaultValue) : Section(section), Name(name), DefaultValue(defaultValue)
{
g_configDefinitions.emplace_back(this);
}
// CONFIG_DEFINE_LOCALISED
template<typename T, bool isHidden>
ConfigDef<T, isHidden>::ConfigDef(std::string section, std::string name, CONFIG_LOCALE* nameLocale, T defaultValue) : Section(section), Name(name), Locale(nameLocale), DefaultValue(defaultValue)
{
g_configDefinitions.emplace_back(this);
}
// CONFIG_DEFINE_ENUM
template<typename T, bool isHidden>
ConfigDef<T, isHidden>::ConfigDef(std::string section, std::string name, T defaultValue, std::unordered_map<std::string, T>* enumTemplate) : Section(section), Name(name), DefaultValue(defaultValue), EnumTemplate(enumTemplate)
{
for (const auto& pair : *EnumTemplate)
EnumTemplateReverse[pair.second] = pair.first;
g_configDefinitions.emplace_back(this);
}
// CONFIG_DEFINE_ENUM_LOCALISED
template<typename T, bool isHidden>
ConfigDef<T, isHidden>::ConfigDef(std::string section, std::string name, CONFIG_LOCALE* nameLocale, T defaultValue, std::unordered_map<std::string, T>* enumTemplate, CONFIG_ENUM_LOCALE(T)* enumLocale) : Section(section), Name(name), Locale(nameLocale), DefaultValue(defaultValue), EnumTemplate(enumTemplate), EnumLocale(enumLocale)
{
for (const auto& pair : *EnumTemplate)
EnumTemplateReverse[pair.second] = pair.first;
g_configDefinitions.emplace_back(this);
}
// CONFIG_DEFINE_CALLBACK
template<typename T, bool isHidden>
ConfigDef<T, isHidden>::ConfigDef(std::string section, std::string name, T defaultValue, std::function<void(ConfigDef<T, isHidden>*)> callback) : Section(section), Name(name), DefaultValue(defaultValue), Callback(callback)
{
g_configDefinitions.emplace_back(this);
}
template<typename T, bool isHidden>
ConfigDef<T, isHidden>::~ConfigDef() = default;
template<typename T, bool isHidden>
bool ConfigDef<T, isHidden>::IsHidden()
{
return isHidden && !IsLoadedFromConfig;
}
template<typename T, bool isHidden>
void ConfigDef<T, isHidden>::ReadValue(toml::v3::ex::parse_result& toml)
{
if (auto pSection = toml[Section].as_table())
{
const auto& section = *pSection;
if constexpr (std::is_same<T, std::string>::value)
{
Value = section[Name].value_or<std::string>(DefaultValue);
}
else if constexpr (std::is_enum_v<T>)
{
auto value = section[Name].value_or(std::string());
auto it = EnumTemplate->find(value);
if (it != EnumTemplate->end())
{
Value = it->second;
}
else
{
Value = DefaultValue;
}
}
else
{
Value = section[Name].value_or(DefaultValue);
}
if (Callback)
Callback(this);
if (pSection->contains(Name))
IsLoadedFromConfig = true;
}
}
template<typename T, bool isHidden>
void ConfigDef<T, isHidden>::MakeDefault()
{
Value = DefaultValue;
}
template<typename T, bool isHidden>
std::string_view ConfigDef<T, isHidden>::GetSection() const
{
return Section;
}
template<typename T, bool isHidden>
std::string_view ConfigDef<T, isHidden>::GetName() const
{
return Name;
}
template<typename T, bool isHidden>
std::string ConfigDef<T, isHidden>::GetNameLocalised(ELanguage language) const
{
if (!Locale)
return Name;
if (!Locale->count(language))
{
if (Locale->count(ELanguage::English))
{
return std::get<0>(Locale->at(ELanguage::English));
}
else
{
return Name;
}
}
return std::get<0>(Locale->at(language));
}
template<typename T, bool isHidden>
std::string ConfigDef<T, isHidden>::GetDescription(ELanguage language) const
{
if (!Locale)
return "";
if (!Locale->count(language))
{
if (Locale->count(ELanguage::English))
{
return std::get<1>(Locale->at(ELanguage::English));
}
else
{
return "";
}
}
return std::get<1>(Locale->at(language));
}
template<typename T, bool isHidden>
bool ConfigDef<T, isHidden>::IsDefaultValue() const
{
return Value == DefaultValue;
}
template<typename T, bool isHidden>
const void* ConfigDef<T, isHidden>::GetValue() const
{
return &Value;
}
template<typename T, bool isHidden>
std::string ConfigDef<T, isHidden>::GetValueLocalised(ELanguage language) const
{
CONFIG_ENUM_LOCALE(T)* locale = nullptr;
if constexpr (std::is_enum_v<T>)
{
locale = EnumLocale;
}
else if constexpr (std::is_same_v<T, bool>)
{
return Value
? Localise("Common_On")
: Localise("Common_Off");
}
if (!locale)
return ToString(false);
if (!locale->count(language))
{
if (locale->count(ELanguage::English))
{
language = ELanguage::English;
}
else
{
return ToString(false);
}
}
auto strings = locale->at(language);
if (!strings.count(Value))
return ToString(false);
return std::get<0>(strings.at(Value));
}
template<typename T, bool isHidden>
std::string ConfigDef<T, isHidden>::GetValueDescription(ELanguage language) const
{
CONFIG_ENUM_LOCALE(T)* locale = nullptr;
if constexpr (std::is_enum_v<T>)
{
locale = EnumLocale;
}
else if constexpr (std::is_same_v<T, bool>)
{
return "";
}
if (!locale)
return "";
if (!locale->count(language))
{
if (locale->count(ELanguage::English))
{
language = ELanguage::English;
}
else
{
return "";
}
}
auto strings = locale->at(language);
if (!strings.count(Value))
return "";
return std::get<1>(strings.at(Value));
}
template<typename T, bool isHidden>
std::string ConfigDef<T, isHidden>::GetDefinition(bool withSection) const
{
std::string result;
if (withSection)
result += "[" + Section + "]\n";
result += Name + " = " + ToString();
return result;
}
template<typename T, bool isHidden>
std::string ConfigDef<T, isHidden>::ToString(bool strWithQuotes) const
{
std::string result = "N/A";
if constexpr (std::is_same_v<T, std::string>)
{
result = fmt::format("{}", Value);
if (strWithQuotes)
result = fmt::format("\"{}\"", result);
}
else if constexpr (std::is_enum_v<T>)
{
auto it = EnumTemplateReverse.find(Value);
if (it != EnumTemplateReverse.end())
result = fmt::format("{}", it->second);
if (strWithQuotes)
result = fmt::format("\"{}\"", result);
}
else
{
result = fmt::format("{}", Value);
}
return result;
}
template<typename T, bool isHidden>
void ConfigDef<T, isHidden>::GetLocaleStrings(std::vector<std::string_view>& localeStrings) const
{
if (Locale != nullptr)
{
for (auto& [language, nameAndDesc] : *Locale)
{
localeStrings.push_back(std::get<0>(nameAndDesc));
localeStrings.push_back(std::get<1>(nameAndDesc));
}
}
if (EnumLocale != nullptr)
{
for (auto& [language, locale] : *EnumLocale)
{
for (auto& [value, nameAndDesc] : locale)
{
localeStrings.push_back(std::get<0>(nameAndDesc));
localeStrings.push_back(std::get<1>(nameAndDesc));
}
}
}
}
std::filesystem::path Config::GetConfigPath()
{
return GetUserPath() / "config.toml";
}
void Config::Load() void Config::Load()
{ {

Some files were not shown because too many files have changed in this diff Show More