mirror of
https://github.com/hedge-dev/UnleashedRecomp
synced 2026-06-08 12:28:15 -04:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 95c044299e | |||
| b04d9e683c | |||
| 5e8d15e334 | |||
| 8f8b574e56 | |||
| c8feff3f8d | |||
| 414ccb3637 | |||
| 431a6d9841 | |||
| 7a5cfe55f5 | |||
| 4f3144472a | |||
| e9f510e8c9 | |||
| a54f850425 | |||
| ab382deb04 | |||
| 8df3e0e440 | |||
| fe083f0eed | |||
| a8e78c21d1 | |||
| 9ec6bd95e1 | |||
| 771c2626b8 | |||
| 54a63e857a | |||
| a13fdc136b | |||
| 86b346e037 | |||
| 3081aec7c1 | |||
| dd294a30d4 | |||
| 99d6cebf92 | |||
| e86922b2b2 | |||
| a07610fb7a | |||
| db4974a9ca | |||
| 4b09a22041 | |||
| 989bf85986 | |||
| 0194c372e9 | |||
| 854d7412fa | |||
| 0441845f2a | |||
| f6d820faae | |||
| a7063dc118 | |||
| fb55ac1087 | |||
| e76cbff3ea | |||
| d2a3818700 | |||
| 3285ad045f | |||
| c687d87126 | |||
| 4502a9efee | |||
| fc99db7c97 | |||
| 0b8b243404 | |||
| 8220f6772b | |||
| b7cee84bda | |||
| 073065c6a6 | |||
| ed6f8f082b | |||
| f23d8ae08e | |||
| f7e660b5d8 | |||
| 7c1aea4e24 | |||
| 138d9b616d | |||
| 7f108285fe | |||
| 97b20742a3 | |||
| fcd1673cfc | |||
| fff96a8528 | |||
| 2fdd32e889 | |||
| 54aacf9a1f | |||
| 39272b7975 |
@@ -0,0 +1,73 @@
|
||||
name: Build Project (Linux)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
LLVM_VERSION: 18
|
||||
CMAKE_PRESET: linux-relwithdebinfo
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Linux
|
||||
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: ./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: |-
|
||||
sudo apt update
|
||||
sudo apt install -y ninja-build llvm-${{ env.LLVM_VERSION }}-dev libgtk-3-dev
|
||||
|
||||
- name: Cache ccache Directory
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/ccache
|
||||
key: ccache-${{ runner.os }}
|
||||
|
||||
- name: Prepare Project
|
||||
run: cp ./private/* ./UnleashedRecompLib/private
|
||||
|
||||
- name: Configure Project
|
||||
env:
|
||||
CCACHE_DIR: /tmp/ccache
|
||||
run: cmake . --preset ${{ env.CMAKE_PRESET }} -DSDL2MIXER_VORBIS=VORBISFILE -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||
|
||||
- name: Build Project
|
||||
env:
|
||||
CCACHE_DIR: /tmp/ccache
|
||||
run: cmake --build ./out/build/${{ env.CMAKE_PRESET }} --target UnleashedRecomp
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: UnleashedRecomp-Linux
|
||||
path: ./out/build/${{ env.CMAKE_PRESET }}/UnleashedRecomp/UnleashedRecomp
|
||||
|
||||
@@ -158,7 +158,8 @@ set(UNLEASHED_RECOMP_UI_CXX_SOURCES
|
||||
"ui/installer_wizard.cpp"
|
||||
"ui/message_window.cpp"
|
||||
"ui/options_menu.cpp"
|
||||
"ui/options_menu_thumbnails.cpp"
|
||||
"ui/options_menu_thumbnails.cpp"
|
||||
"ui/tv_static.cpp"
|
||||
)
|
||||
|
||||
set(UNLEASHED_RECOMP_INSTALL_CXX_SOURCES
|
||||
@@ -471,7 +472,8 @@ generate_aggregate_header(
|
||||
|
||||
set(RESOURCES_SOURCE_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources")
|
||||
set(RESOURCES_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/res")
|
||||
|
||||
|
||||
## Miscellaneous ##
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/bc_diff/button_bc_diff.bin" DEST_FILE "${RESOURCES_OUTPUT_PATH}/bc_diff/button_bc_diff.bin" ARRAY_NAME "g_button_bc_diff" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/font/im_font_atlas.bin" DEST_FILE "${RESOURCES_OUTPUT_PATH}/font/im_font_atlas.bin" ARRAY_NAME "g_im_font_atlas" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/font/im_font_atlas.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/font/im_font_atlas.dds" ARRAY_NAME "g_im_font_atlas_texture" COMPRESSION_TYPE "zstd")
|
||||
@@ -482,6 +484,8 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/co
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/kbm.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/kbm.dds" ARRAY_NAME "g_kbm" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select.dds" ARRAY_NAME "g_select" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/light.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/light.dds" ARRAY_NAME "g_light" COMPRESSION_TYPE "zstd")
|
||||
|
||||
## Installer ##
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/arrow_circle.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/arrow_circle.dds" ARRAY_NAME "g_arrow_circle" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_001.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_001.dds" ARRAY_NAME "g_install_001" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_002.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_002.dds" ARRAY_NAME "g_install_002" COMPRESSION_TYPE "zstd")
|
||||
@@ -492,14 +496,23 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/in
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_007.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_007.dds" ARRAY_NAME "g_install_007" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_008.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_008.dds" ARRAY_NAME "g_install_008" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/miles_electric_icon.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/miles_electric_icon.dds" ARRAY_NAME "g_miles_electric_icon" 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/installer/pulse_install.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/pulse_install.dds" ARRAY_NAME "g_pulse_install" COMPRESSION_TYPE "zstd")
|
||||
|
||||
## Options Menu ##
|
||||
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/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/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_none.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_none.dds" ARRAY_NAME "g_antialiasing_none" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" ARRAY_NAME "g_antialiasing_2x" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" ARRAY_NAME "g_antialiasing_4x" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_8x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_8x.dds" ARRAY_NAME "g_antialiasing_8x" 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/brightness.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/brightness.dds" ARRAY_NAME "g_brightness" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial.dds" ARRAY_NAME "g_control_tutorial" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/brightness.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/brightness.dds" ARRAY_NAME "g_brightness" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_stereo.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_stereo.dds" ARRAY_NAME "g_channel_stereo" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_surround.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_surround.dds" ARRAY_NAME "g_channel_surround" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" ARRAY_NAME "g_control_tutorial_xb" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" ARRAY_NAME "g_control_tutorial_ps" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/controller_icons.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/controller_icons.dds" ARRAY_NAME "g_controller_icons" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/default.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/default.dds" ARRAY_NAME "g_default" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/effects_volume.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/effects_volume.dds" ARRAY_NAME "g_effects_volume" COMPRESSION_TYPE "zstd")
|
||||
@@ -515,7 +528,8 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/motion_blur_off.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/motion_blur_off.dds" ARRAY_NAME "g_motion_blur_off" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/motion_blur_original.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/motion_blur_original.dds" ARRAY_NAME "g_motion_blur_original" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/motion_blur_enhanced.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/motion_blur_enhanced.dds" ARRAY_NAME "g_motion_blur_enhanced" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/movie_scale_mode.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/movie_scale_mode.dds" ARRAY_NAME "g_movie_scale_mode" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/movie_scale_fit.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/movie_scale_fit.dds" ARRAY_NAME "g_movie_scale_fit" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/movie_scale_fill.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/movie_scale_fill.dds" ARRAY_NAME "g_movie_scale_fill" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/music_attenuation.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/music_attenuation.dds" ARRAY_NAME "g_music_attenuation" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/music_volume.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/music_volume.dds" ARRAY_NAME "g_music_volume" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/resolution_scale.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/resolution_scale.dds" ARRAY_NAME "g_resolution_scale" COMPRESSION_TYPE "zstd")
|
||||
@@ -526,25 +540,32 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x4096.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x4096.dds" ARRAY_NAME "g_shadow_resolution_x4096" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x8192.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x8192.dds" ARRAY_NAME "g_shadow_resolution_x8192" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/subtitles.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/subtitles.dds" ARRAY_NAME "g_subtitles" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_of_day_transition_xbox.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_of_day_transition_xbox.dds" ARRAY_NAME "g_time_of_day_transition_xbox" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_of_day_transition_playstation.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_of_day_transition_playstation.dds" ARRAY_NAME "g_time_of_day_transition_playstation" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_transition_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_xb.dds" ARRAY_NAME "g_time_of_day_transition_xbox" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" ARRAY_NAME "g_time_of_day_transition_playstation" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" ARRAY_NAME "g_transparency_antialiasing_false" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" ARRAY_NAME "g_transparency_antialiasing_true" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_mode.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_mode.dds" ARRAY_NAME "g_ui_alignment_mode" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" ARRAY_NAME "g_ui_alignment_centre" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_edge.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_edge.dds" ARRAY_NAME "g_ui_alignment_edge" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vertical_camera.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vertical_camera.dds" ARRAY_NAME "g_vertical_camera" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/voice_language.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/voice_language.dds" ARRAY_NAME "g_voice_language" 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/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_on.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vsync_on.dds" ARRAY_NAME "g_vsync_on" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vsync_off.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vsync_off.dds" ARRAY_NAME "g_vsync_off" 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.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/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/options_menu/options_static.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/options_static.dds" ARRAY_NAME "g_options_static" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/options_static_flash.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/options_static_flash.dds" ARRAY_NAME "g_options_static_flash" COMPRESSION_TYPE "zstd")
|
||||
|
||||
## 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")
|
||||
|
||||
## Audio ##
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_worldmap_cursor.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_worldmap_cursor.ogg" ARRAY_NAME "g_sys_worldmap_cursor")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_worldmap_finaldecide.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_worldmap_finaldecide.ogg" ARRAY_NAME "g_sys_worldmap_finaldecide")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausecansel.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausecansel.ogg" ARRAY_NAME "g_sys_actstg_pausecansel")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausecursor.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausecursor.ogg" ARRAY_NAME "g_sys_actstg_pausecursor")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausedecide.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausedecide.ogg" ARRAY_NAME "g_sys_actstg_pausedecide")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausewinclose.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausewinclose.ogg" ARRAY_NAME "g_sys_actstg_pausewinclose")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausewinopen.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausewinopen.ogg" ARRAY_NAME "g_sys_actstg_pausewinopen")
|
||||
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausewinopen.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausewinopen.ogg" ARRAY_NAME "g_sys_actstg_pausewinopen")
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <SWA.inl>
|
||||
|
||||
namespace Hedgehog::Math
|
||||
{
|
||||
class CMatrix
|
||||
{
|
||||
public:
|
||||
be<float> m_M00;
|
||||
be<float> m_M01;
|
||||
be<float> m_M02;
|
||||
be<float> m_M03;
|
||||
be<float> m_M10;
|
||||
be<float> m_M11;
|
||||
be<float> m_M12;
|
||||
be<float> m_M13;
|
||||
be<float> m_M20;
|
||||
be<float> m_M21;
|
||||
be<float> m_M22;
|
||||
be<float> m_M23;
|
||||
be<float> m_M30;
|
||||
be<float> m_M31;
|
||||
be<float> m_M32;
|
||||
be<float> m_M33;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <SWA.inl>
|
||||
|
||||
namespace Hedgehog::Math
|
||||
{
|
||||
class CQuaternion
|
||||
{
|
||||
public:
|
||||
be<float> X;
|
||||
be<float> Y;
|
||||
be<float> Z;
|
||||
be<float> W;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <SWA.inl>
|
||||
|
||||
namespace Hedgehog::Mirage
|
||||
{
|
||||
class CMatrixNodeListener;
|
||||
|
||||
class CMatrixNode : public Base::CObject
|
||||
{
|
||||
public:
|
||||
SWA_INSERT_PADDING(0x60);
|
||||
};
|
||||
|
||||
SWA_ASSERT_SIZEOF(CMatrixNode, 0x60);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <SWA.inl>
|
||||
|
||||
namespace Hedgehog::Mirage
|
||||
{
|
||||
class CTransform
|
||||
{
|
||||
public:
|
||||
Math::CQuaternion m_Rotation;
|
||||
Math::CVector m_Position;
|
||||
Math::CMatrix m_Matrix;
|
||||
};
|
||||
|
||||
SWA_ASSERT_OFFSETOF(CTransform, m_Rotation, 0x00);
|
||||
SWA_ASSERT_OFFSETOF(CTransform, m_Position, 0x10);
|
||||
SWA_ASSERT_OFFSETOF(CTransform, m_Matrix, 0x20);
|
||||
SWA_ASSERT_SIZEOF(CTransform, 0x60);
|
||||
}
|
||||
@@ -27,7 +27,11 @@
|
||||
#include "Hedgehog/Base/Type/hhSharedString.h"
|
||||
#include "Hedgehog/Base/hhObject.h"
|
||||
#include "Hedgehog/Database/System/hhDatabaseData.h"
|
||||
#include "Hedgehog/Math/Matrix.h"
|
||||
#include "Hedgehog/Math/Quaternion.h"
|
||||
#include "Hedgehog/Math/Vector.h"
|
||||
#include "Hedgehog/MirageCore/MatrixNode/hhMatrixNode.h"
|
||||
#include "Hedgehog/MirageCore/Misc/hhTransform.h"
|
||||
#include "Hedgehog/MirageCore/Misc/hhVertexDeclarationPtr.h"
|
||||
#include "Hedgehog/MirageCore/RenderData/hhMaterialData.h"
|
||||
#include "Hedgehog/MirageCore/RenderData/hhMeshData.h"
|
||||
@@ -55,6 +59,7 @@
|
||||
#include "SWA/Achievement/AchievementID.h"
|
||||
#include "SWA/Achievement/AchievementManager.h"
|
||||
#include "SWA/Achievement/AchievementTest.h"
|
||||
#include "SWA/Boss/EggDragoon/Object/BossEggDragoonDrillMissile.h"
|
||||
#include "SWA/CSD/CsdDatabaseWrapper.h"
|
||||
#include "SWA/CSD/CsdProject.h"
|
||||
#include "SWA/CSD/CsdTexListMirage.h"
|
||||
@@ -85,6 +90,7 @@
|
||||
#include "SWA/Movie/MovieDisplayer.h"
|
||||
#include "SWA/Movie/MovieManager.h"
|
||||
#include "SWA/Object/Common/DashPanel/ObjDashPanel.h"
|
||||
#include "SWA/Object/SonicStage/EU/RollingBarrel/ObjRollingBarrel.h"
|
||||
#include "SWA/Player/Character/EvilSonic/EvilSonic.h"
|
||||
#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h"
|
||||
#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h"
|
||||
@@ -115,6 +121,7 @@
|
||||
#include "SWA/System/GameParameter.h"
|
||||
#include "SWA/System/GammaController.h"
|
||||
#include "SWA/System/InputState.h"
|
||||
#include "SWA/System/MatrixNodeTransform.h"
|
||||
#include "SWA/System/PadState.h"
|
||||
#include "SWA/System/World.h"
|
||||
#include "boost/smart_ptr/make_shared_object.h"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <SWA.inl>
|
||||
#include "SWA/System/MatrixNodeTransform.h"
|
||||
|
||||
namespace SWA::Boss::EggDragoon::DrillMissile
|
||||
{
|
||||
class CMissile
|
||||
{
|
||||
public:
|
||||
SWA_INSERT_PADDING(0xC4);
|
||||
xpointer<CMatrixNodeTransform> m_pMatrixNodeTransform;
|
||||
SWA_INSERT_PADDING(0x68);
|
||||
be<float> m_Speed;
|
||||
};
|
||||
}
|
||||
@@ -9,6 +9,9 @@ namespace SWA
|
||||
// ms_DrawLightFieldSamplingPoint: サンプリング点をデバッグ表示
|
||||
static inline bool* ms_DrawLightFieldSamplingPoint;
|
||||
|
||||
// N/A
|
||||
static inline bool* ms_IsAutoSaveWarningShown;
|
||||
|
||||
// ms_IgnoreLightFieldData: データを無視する
|
||||
static inline bool* ms_IgnoreLightFieldData;
|
||||
|
||||
@@ -39,6 +42,9 @@ namespace SWA
|
||||
// ms_IsRenderHudPause: ポーズメニュー 描画
|
||||
static inline bool* ms_IsRenderHudPause;
|
||||
|
||||
// N/A
|
||||
static inline bool* ms_IsTitleStateMenu;
|
||||
|
||||
// IsTriggerRender
|
||||
static inline bool* ms_IsTriggerRender;
|
||||
|
||||
@@ -52,6 +58,7 @@ namespace SWA
|
||||
{
|
||||
ms_DrawLightFieldSamplingPoint = (bool*)MmGetHostAddress(0x83367BCE);
|
||||
ms_IgnoreLightFieldData = (bool*)MmGetHostAddress(0x83367BCF);
|
||||
ms_IsAutoSaveWarningShown = (bool*)MmGetHostAddress(0x83367BC1);
|
||||
ms_IsCollisionRender = (bool*)MmGetHostAddress(0x833678A6);
|
||||
ms_IsLoading = (bool*)MmGetHostAddress(0x83367A4C);
|
||||
ms_IsObjectCollisionRender = (bool*)MmGetHostAddress(0x83367905);
|
||||
@@ -61,6 +68,7 @@ namespace SWA
|
||||
ms_IsRenderGameMainHud = (bool*)MmGetHostAddress(0x8328BB27);
|
||||
ms_IsRenderHud = (bool*)MmGetHostAddress(0x8328BB26);
|
||||
ms_IsRenderHudPause = (bool*)MmGetHostAddress(0x8328BB28);
|
||||
ms_IsTitleStateMenu = (bool*)MmGetHostAddress(0x83367BC0);
|
||||
ms_IsTriggerRender = (bool*)MmGetHostAddress(0x83367904);
|
||||
ms_LightFieldDebug = (bool*)MmGetHostAddress(0x83367BCD);
|
||||
ms_VisualizeLoadedLevel = (bool*)MmGetHostAddress(0x833678C1);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <SWA.inl>
|
||||
|
||||
namespace SWA
|
||||
{
|
||||
class CObjRollingBarrel
|
||||
{
|
||||
public:
|
||||
class CElement
|
||||
{
|
||||
public:
|
||||
SWA_INSERT_PADDING(0xEC);
|
||||
xpointer<void> m_FieldEC;
|
||||
SWA_INSERT_PADDING(0x20);
|
||||
be<float> m_Roll;
|
||||
};
|
||||
|
||||
SWA_INSERT_PADDING(0xE8);
|
||||
be<float> m_GenerationTime;
|
||||
SWA_INSERT_PADDING(0x09);
|
||||
bool m_FieldF5;
|
||||
SWA_INSERT_PADDING(0x0A);
|
||||
be<float> m_RandomRange;
|
||||
be<float> m_Field104;
|
||||
};
|
||||
|
||||
SWA_ASSERT_OFFSETOF(CObjRollingBarrel::CElement, m_FieldEC, 0xEC);
|
||||
SWA_ASSERT_OFFSETOF(CObjRollingBarrel::CElement, m_Roll, 0x110);
|
||||
|
||||
SWA_ASSERT_OFFSETOF(CObjRollingBarrel, m_GenerationTime, 0xE8);
|
||||
SWA_ASSERT_OFFSETOF(CObjRollingBarrel, m_FieldF5, 0xF5);
|
||||
SWA_ASSERT_OFFSETOF(CObjRollingBarrel, m_RandomRange, 0x100);
|
||||
SWA_ASSERT_OFFSETOF(CObjRollingBarrel, m_Field104, 0x104);
|
||||
}
|
||||
@@ -71,7 +71,8 @@ namespace SWA
|
||||
boost::shared_ptr<Hedgehog::Mirage::CMatrixNode> m_spMatrixNodeRoot;
|
||||
SWA_INSERT_PADDING(0x14);
|
||||
CGammaController m_GammaController;
|
||||
SWA_INSERT_PADDING(0x1C);
|
||||
boost::shared_ptr<CLoading> m_spLoading;
|
||||
SWA_INSERT_PADDING(0x14);
|
||||
boost::shared_ptr<Achievement::CManager> m_spAchievementManager;
|
||||
boost::shared_ptr<CDatabaseTree> m_spDatabaseTree;
|
||||
Hedgehog::Base::CSharedString m_Field10C;
|
||||
@@ -104,6 +105,7 @@ namespace SWA
|
||||
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_Field74, 0x74);
|
||||
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_spMatrixNodeRoot, 0x84);
|
||||
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_GammaController, 0xA0);
|
||||
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_spLoading, 0xE0);
|
||||
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_spAchievementManager, 0xFC);
|
||||
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_spDatabaseTree, 0x104);
|
||||
SWA_ASSERT_OFFSETOF(CApplicationDocument::CMember, m_Field10C, 0x10C);
|
||||
|
||||
@@ -4,14 +4,5 @@
|
||||
|
||||
namespace SWA
|
||||
{
|
||||
class CTitleStateBase : public Hedgehog::Universe::CStateMachineBase::CStateBase
|
||||
{
|
||||
public:
|
||||
class CTitleStateContext
|
||||
{
|
||||
public:
|
||||
SWA_INSERT_PADDING(0x1E8);
|
||||
xpointer<CTitleMenu> m_pTitleMenu;
|
||||
};
|
||||
};
|
||||
class CTitleStateBase : public Hedgehog::Universe::CStateMachineBase::CStateBase {};
|
||||
}
|
||||
|
||||
@@ -4,5 +4,14 @@
|
||||
|
||||
namespace SWA
|
||||
{
|
||||
class CTitleStateMenu : public CTitleStateBase {};
|
||||
class CTitleStateMenu : public CTitleStateBase
|
||||
{
|
||||
public:
|
||||
class CTitleStateMenuContext
|
||||
{
|
||||
public:
|
||||
SWA_INSERT_PADDING(0x1E8);
|
||||
xpointer<CTitleMenu> m_pTitleMenu;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <SWA.inl>
|
||||
|
||||
namespace SWA
|
||||
{
|
||||
class CMatrixNodeTransform : public Hedgehog::Mirage::CMatrixNode
|
||||
{
|
||||
public:
|
||||
Hedgehog::Mirage::CTransform m_Transform;
|
||||
Hedgehog::Math::CMatrix m_WorldMatrix;
|
||||
};
|
||||
|
||||
SWA_ASSERT_OFFSETOF(CMatrixNodeTransform, m_Transform, 0x60);
|
||||
SWA_ASSERT_OFFSETOF(CMatrixNodeTransform, m_WorldMatrix, 0xC0);
|
||||
SWA_ASSERT_SIZEOF(CMatrixNodeTransform, 0x100);
|
||||
}
|
||||
+18
-2
@@ -28,7 +28,7 @@ void App::Exit()
|
||||
std::_Exit(0);
|
||||
}
|
||||
|
||||
// SWA::CApplication
|
||||
// SWA::CApplication::CApplication
|
||||
PPC_FUNC_IMPL(__imp__sub_824EB490);
|
||||
PPC_FUNC(sub_824EB490)
|
||||
{
|
||||
@@ -69,12 +69,28 @@ PPC_FUNC(sub_822C1130)
|
||||
{
|
||||
SDL_PumpEvents();
|
||||
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
|
||||
GameWindow::Update();
|
||||
}
|
||||
|
||||
GameWindow::Update();
|
||||
AudioPatches::Update(App::s_deltaTime);
|
||||
InspirePatches::Update();
|
||||
|
||||
// Apply subtitles option.
|
||||
if (auto pApplicationDocument = SWA::CApplicationDocument::GetInstance())
|
||||
pApplicationDocument->m_InspireSubtitles = Config::Subtitles;
|
||||
|
||||
if (Config::EnableEventCollisionDebugView)
|
||||
*SWA::SGlobals::ms_IsTriggerRender = true;
|
||||
|
||||
if (Config::EnableGIMipLevelDebugView)
|
||||
*SWA::SGlobals::ms_VisualizeLoadedLevel = true;
|
||||
|
||||
if (Config::EnableObjectCollisionDebugView)
|
||||
*SWA::SGlobals::ms_IsObjectCollisionRender = true;
|
||||
|
||||
if (Config::EnableStageCollisionDebugView)
|
||||
*SWA::SGlobals::ms_IsCollisionRender = true;
|
||||
|
||||
__imp__sub_822C1130(ctx, base);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <kernel/heap.h>
|
||||
#include <kernel/memory.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <patches/inspire_patches.h>
|
||||
|
||||
void Game_PlaySound(const char* pName)
|
||||
{
|
||||
@@ -14,8 +15,11 @@ void Game_PlaySound(const char* pName)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use EVENT category in cutscenes since SYSTEM gets muted by the game.
|
||||
uint32_t category = !InspirePatches::s_sceneName.empty() ? 10 : 7;
|
||||
|
||||
guest_stack_var<boost::anonymous_shared_ptr> soundPlayer;
|
||||
GuestToHostFunction<void>(sub_82B4DF50, soundPlayer.get(), ((be<uint32_t>*)g_memory.Translate(0x83367900))->get(), 7, 0, 0);
|
||||
GuestToHostFunction<void>(sub_82B4DF50, soundPlayer.get(), ((be<uint32_t>*)g_memory.Translate(0x83367900))->get(), category, 0, 0);
|
||||
|
||||
auto soundPlayerVtable = (be<uint32_t>*)g_memory.Translate(*(be<uint32_t>*)soundPlayer->get());
|
||||
uint32_t virtualFunction = *(soundPlayerVtable + 1);
|
||||
@@ -27,13 +31,3 @@ void Game_PlaySound(const char* pName)
|
||||
g_userHeap.Free(strAllocation);
|
||||
}
|
||||
}
|
||||
|
||||
void Window_SetDisplay(int displayIndex)
|
||||
{
|
||||
GameWindow::SetDisplay(displayIndex);
|
||||
}
|
||||
|
||||
void Window_SetFullscreen(bool isEnabled)
|
||||
{
|
||||
GameWindow::SetFullscreen(isEnabled);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void Game_PlaySound(const char* pName);
|
||||
void Window_SetDisplay(int displayIndex);
|
||||
void Window_SetFullscreen(bool isEnabled);
|
||||
|
||||
@@ -11,7 +11,7 @@ ImGuiCallbackData* AddImGuiCallback(ImGuiCallback callback)
|
||||
auto& callbackData = g_callbackData[g_callbackDataIndex];
|
||||
++g_callbackDataIndex;
|
||||
|
||||
ImGui::GetForegroundDrawList()->AddCallback(reinterpret_cast<ImDrawCallback>(callback), callbackData.get());
|
||||
ImGui::GetBackgroundDrawList()->AddCallback(reinterpret_cast<ImDrawCallback>(callback), callbackData.get());
|
||||
|
||||
return callbackData.get();
|
||||
}
|
||||
|
||||
@@ -1437,6 +1437,52 @@ namespace plume {
|
||||
return height;
|
||||
}
|
||||
|
||||
// D3D12QueryPool
|
||||
|
||||
D3D12QueryPool::D3D12QueryPool(D3D12Device *device, uint32_t queryCount) {
|
||||
assert(device != nullptr);
|
||||
assert(queryCount > 0);
|
||||
|
||||
this->device = device;
|
||||
|
||||
D3D12_QUERY_HEAP_DESC queryHeapDesc = {};
|
||||
queryHeapDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
|
||||
queryHeapDesc.Count = queryCount;
|
||||
|
||||
HRESULT res = device->d3d->CreateQueryHeap(&queryHeapDesc, IID_PPV_ARGS(&d3d));
|
||||
if (FAILED(res)) {
|
||||
fprintf(stderr, "CreateQueryHeap failed with error code 0x%lX.\n", res);
|
||||
return;
|
||||
}
|
||||
|
||||
readbackBuffer = device->createBuffer(RenderBufferDesc::ReadbackBuffer(sizeof(uint64_t) * queryCount));
|
||||
results.resize(queryCount);
|
||||
}
|
||||
|
||||
D3D12QueryPool::~D3D12QueryPool() {
|
||||
if (d3d != nullptr) {
|
||||
d3d->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12QueryPool::queryResults() {
|
||||
void *readbackData = readbackBuffer->map();
|
||||
memcpy(results.data(), readbackData, sizeof(uint64_t) * results.size());
|
||||
readbackBuffer->unmap();
|
||||
|
||||
for (uint64_t &result : results) {
|
||||
result = result / double(device->timestampFrequency) * 1000000000.0;
|
||||
}
|
||||
}
|
||||
|
||||
const uint64_t *D3D12QueryPool::getResults() const {
|
||||
return results.data();
|
||||
}
|
||||
|
||||
uint32_t D3D12QueryPool::getCount() const {
|
||||
return uint32_t(results.size());
|
||||
}
|
||||
|
||||
// D3D12CommandList
|
||||
|
||||
D3D12CommandList::D3D12CommandList(D3D12Device *device, RenderCommandListType type) {
|
||||
@@ -2004,6 +2050,19 @@ namespace plume {
|
||||
d3d->DiscardResource(interfaceTexture->d3d, nullptr);
|
||||
}
|
||||
|
||||
void D3D12CommandList::resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
void D3D12CommandList::writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) {
|
||||
assert(queryPool != nullptr);
|
||||
|
||||
const D3D12QueryPool *interfaceQueryPool = static_cast<const D3D12QueryPool *>(queryPool);
|
||||
const D3D12Buffer *readbackBuffer = static_cast<const D3D12Buffer *>(interfaceQueryPool->readbackBuffer.get());
|
||||
d3d->EndQuery(interfaceQueryPool->d3d, D3D12_QUERY_TYPE_TIMESTAMP, queryIndex);
|
||||
d3d->ResolveQueryData(interfaceQueryPool->d3d, D3D12_QUERY_TYPE_TIMESTAMP, queryIndex, 1, readbackBuffer->d3d, queryIndex * sizeof(uint64_t));
|
||||
}
|
||||
|
||||
void D3D12CommandList::checkDescriptorHeaps() {
|
||||
if (!descriptorHeapsSet) {
|
||||
ID3D12DescriptorHeap *descriptorHeaps[] = { device->viewHeapAllocator->heap, device->samplerHeapAllocator->heap };
|
||||
@@ -3259,7 +3318,7 @@ namespace plume {
|
||||
|
||||
// D3D12Device
|
||||
|
||||
D3D12Device::D3D12Device(D3D12Interface *renderInterface) {
|
||||
D3D12Device::D3D12Device(D3D12Interface *renderInterface, const std::string &preferredDeviceName) {
|
||||
assert(renderInterface != nullptr);
|
||||
|
||||
this->renderInterface = renderInterface;
|
||||
@@ -3349,9 +3408,10 @@ namespace plume {
|
||||
}
|
||||
|
||||
// Pick this adapter and device if it has better feature support than the current one.
|
||||
std::string deviceName = Utf16ToUtf8(adapterDesc.Description);
|
||||
bool preferOverNothing = (adapter == nullptr) || (d3d == nullptr);
|
||||
bool preferVideoMemory = adapterDesc.DedicatedVideoMemory > description.dedicatedVideoMemory;
|
||||
bool preferUserChoice = false;//wcsstr(adapterDesc.Description, L"AMD") != nullptr;
|
||||
bool preferUserChoice = preferredDeviceName == deviceName;
|
||||
bool preferOption = preferOverNothing || preferVideoMemory || preferUserChoice;
|
||||
if (preferOption) {
|
||||
if (d3d != nullptr) {
|
||||
@@ -3371,8 +3431,15 @@ namespace plume {
|
||||
capabilities.triangleFan = triangleFanSupportOption;
|
||||
capabilities.dynamicDepthBias = dynamicDepthBiasOption;
|
||||
capabilities.uma = uma;
|
||||
description.name = Utf16ToUtf8(adapterDesc.Description);
|
||||
description.name = deviceName;
|
||||
description.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory;
|
||||
description.vendor = RenderDeviceVendor(adapterDesc.VendorId);
|
||||
|
||||
LARGE_INTEGER adapterVersion = {};
|
||||
res = adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &adapterVersion);
|
||||
if (SUCCEEDED(res)) {
|
||||
description.driverVersion = adapterVersion.QuadPart;
|
||||
}
|
||||
|
||||
if (preferUserChoice) {
|
||||
break;
|
||||
@@ -3460,6 +3527,13 @@ namespace plume {
|
||||
samplerHeapAllocator = std::make_unique<D3D12DescriptorHeapAllocator>(this, SamplerDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
colorTargetHeapAllocator = std::make_unique<D3D12DescriptorHeapAllocator>(this, TargetDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
depthTargetHeapAllocator = std::make_unique<D3D12DescriptorHeapAllocator>(this, TargetDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||||
|
||||
// Create a command queue only for retrieving the timestamp frequency. Delete it immediately afterwards.
|
||||
std::unique_ptr<D3D12CommandQueue> timestampCommandQueue = std::make_unique<D3D12CommandQueue>(this, RenderCommandListType::DIRECT);
|
||||
res = timestampCommandQueue->d3d->GetTimestampFrequency(×tampFrequency);
|
||||
if (FAILED(res)) {
|
||||
fprintf(stderr, "GetTimestampFrequency failed with error code 0x%lX. Timestamps will be inaccurate.\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
D3D12Device::~D3D12Device() {
|
||||
@@ -3534,6 +3608,10 @@ namespace plume {
|
||||
return std::make_unique<D3D12Framebuffer>(this, desc);
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderQueryPool> D3D12Device::createQueryPool(uint32_t queryCount) {
|
||||
return std::make_unique<D3D12QueryPool>(this, queryCount);
|
||||
}
|
||||
|
||||
void D3D12Device::setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) {
|
||||
assert(meshes != nullptr);
|
||||
assert(meshCount > 0);
|
||||
@@ -3767,6 +3845,21 @@ namespace plume {
|
||||
|
||||
// Fill capabilities.
|
||||
capabilities.shaderFormat = RenderShaderFormat::DXIL;
|
||||
|
||||
// Fill device names.
|
||||
UINT adapterIndex = 0;
|
||||
IDXGIAdapter1 *adapterOption = nullptr;
|
||||
while (dxgiFactory->EnumAdapters1(adapterIndex++, &adapterOption) != DXGI_ERROR_NOT_FOUND) {
|
||||
DXGI_ADAPTER_DESC1 adapterDesc;
|
||||
adapterOption->GetDesc1(&adapterDesc);
|
||||
|
||||
// Ignore remote or software adapters.
|
||||
if ((adapterDesc.Flags & (DXGI_ADAPTER_FLAG_REMOTE | DXGI_ADAPTER_FLAG_SOFTWARE)) == 0) {
|
||||
deviceNames.emplace_back(Utf16ToUtf8(adapterDesc.Description));
|
||||
}
|
||||
|
||||
adapterOption->Release();
|
||||
}
|
||||
}
|
||||
|
||||
D3D12Interface::~D3D12Interface() {
|
||||
@@ -3775,8 +3868,8 @@ namespace plume {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderDevice> D3D12Interface::createDevice() {
|
||||
std::unique_ptr<D3D12Device> createdDevice = std::make_unique<D3D12Device>(this);
|
||||
std::unique_ptr<RenderDevice> D3D12Interface::createDevice(const std::string &preferredDeviceName) {
|
||||
std::unique_ptr<D3D12Device> createdDevice = std::make_unique<D3D12Device>(this, preferredDeviceName);
|
||||
return createdDevice->isValid() ? std::move(createdDevice) : nullptr;
|
||||
}
|
||||
|
||||
@@ -3784,6 +3877,10 @@ namespace plume {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
const std::vector<std::string> &D3D12Interface::getDeviceNames() const {
|
||||
return deviceNames;
|
||||
}
|
||||
|
||||
bool D3D12Interface::isValid() const {
|
||||
return dxgiFactory != nullptr;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,19 @@ namespace plume {
|
||||
uint32_t getHeight() const override;
|
||||
};
|
||||
|
||||
struct D3D12QueryPool : RenderQueryPool {
|
||||
D3D12Device *device = nullptr;
|
||||
ID3D12QueryHeap *d3d = nullptr;
|
||||
std::vector<uint64_t> results;
|
||||
std::unique_ptr<RenderBuffer> readbackBuffer;
|
||||
|
||||
D3D12QueryPool(D3D12Device *device, uint32_t queryCount);
|
||||
virtual ~D3D12QueryPool() override;
|
||||
virtual void queryResults() override;
|
||||
virtual const uint64_t *getResults() const override;
|
||||
virtual uint32_t getCount() const override;
|
||||
};
|
||||
|
||||
struct D3D12CommandList : RenderCommandList {
|
||||
ID3D12GraphicsCommandList9 *d3d = nullptr;
|
||||
ID3D12CommandAllocator *commandAllocator = nullptr;
|
||||
@@ -196,6 +209,8 @@ namespace plume {
|
||||
void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override;
|
||||
void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override;
|
||||
void discardTexture(const RenderTexture* texture) override;
|
||||
void resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) override;
|
||||
void writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) override;
|
||||
void checkDescriptorHeaps();
|
||||
void notifyDescriptorHeapWasChangedExternally();
|
||||
void checkTopology();
|
||||
@@ -417,8 +432,9 @@ namespace plume {
|
||||
std::unique_ptr<D3D12DescriptorHeapAllocator> depthTargetHeapAllocator;
|
||||
RenderDeviceCapabilities capabilities;
|
||||
RenderDeviceDescription description;
|
||||
uint64_t timestampFrequency = 1;
|
||||
|
||||
D3D12Device(D3D12Interface *renderInterface);
|
||||
D3D12Device(D3D12Interface *renderInterface, const std::string &preferredDeviceName);
|
||||
~D3D12Device() override;
|
||||
std::unique_ptr<RenderCommandList> createCommandList(RenderCommandListType type) override;
|
||||
std::unique_ptr<RenderDescriptorSet> createDescriptorSet(const RenderDescriptorSetDesc &desc) override;
|
||||
@@ -436,6 +452,7 @@ namespace plume {
|
||||
std::unique_ptr<RenderCommandFence> createCommandFence() override;
|
||||
std::unique_ptr<RenderCommandSemaphore> createCommandSemaphore() override;
|
||||
std::unique_ptr<RenderFramebuffer> createFramebuffer(const RenderFramebufferDesc &desc) override;
|
||||
std::unique_ptr<RenderQueryPool> createQueryPool(uint32_t queryCount) override;
|
||||
void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) override;
|
||||
void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild, bool preferFastTrace) override;
|
||||
void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) override;
|
||||
@@ -450,11 +467,13 @@ namespace plume {
|
||||
struct D3D12Interface : RenderInterface {
|
||||
IDXGIFactory4 *dxgiFactory = nullptr;
|
||||
RenderInterfaceCapabilities capabilities;
|
||||
std::vector<std::string> deviceNames;
|
||||
|
||||
D3D12Interface();
|
||||
~D3D12Interface() override;
|
||||
std::unique_ptr<RenderDevice> createDevice() override;
|
||||
std::unique_ptr<RenderDevice> createDevice(const std::string &preferredDeviceName) override;
|
||||
const RenderInterfaceCapabilities &getCapabilities() const override;
|
||||
const std::vector<std::string> &getDeviceNames() const override;
|
||||
bool isValid() const;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -147,6 +147,8 @@ namespace plume {
|
||||
virtual void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) = 0;
|
||||
virtual void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) = 0;
|
||||
virtual void discardTexture(const RenderTexture* texture) = 0; // D3D12 only.
|
||||
virtual void resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) = 0;
|
||||
virtual void writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) = 0;
|
||||
|
||||
// Concrete implementation shortcuts.
|
||||
inline void barriers(RenderBarrierStages stages, const RenderBufferBarrier &barrier) {
|
||||
@@ -208,6 +210,13 @@ namespace plume {
|
||||
virtual std::unique_ptr<RenderTexture> createTexture(const RenderTextureDesc &desc) = 0;
|
||||
};
|
||||
|
||||
struct RenderQueryPool {
|
||||
virtual ~RenderQueryPool() { }
|
||||
virtual void queryResults() = 0;
|
||||
virtual const uint64_t *getResults() const = 0;
|
||||
virtual uint32_t getCount() const = 0;
|
||||
};
|
||||
|
||||
struct RenderDevice {
|
||||
virtual ~RenderDevice() { }
|
||||
virtual std::unique_ptr<RenderCommandList> createCommandList(RenderCommandListType type) = 0;
|
||||
@@ -226,6 +235,7 @@ namespace plume {
|
||||
virtual std::unique_ptr<RenderCommandFence> createCommandFence() = 0;
|
||||
virtual std::unique_ptr<RenderCommandSemaphore> createCommandSemaphore() = 0;
|
||||
virtual std::unique_ptr<RenderFramebuffer> createFramebuffer(const RenderFramebufferDesc &desc) = 0;
|
||||
virtual std::unique_ptr<RenderQueryPool> createQueryPool(uint32_t queryCount) = 0;
|
||||
virtual void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild = true, bool preferFastTrace = false) = 0;
|
||||
virtual void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild = true, bool preferFastTrace = false) = 0;
|
||||
virtual void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) = 0;
|
||||
@@ -237,7 +247,8 @@ namespace plume {
|
||||
|
||||
struct RenderInterface {
|
||||
virtual ~RenderInterface() { }
|
||||
virtual std::unique_ptr<RenderDevice> createDevice() = 0;
|
||||
virtual std::unique_ptr<RenderDevice> createDevice(const std::string &preferredDeviceName = "") = 0;
|
||||
virtual const std::vector<std::string> &getDeviceNames() const = 0;
|
||||
virtual const RenderInterfaceCapabilities &getCapabilities() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -69,9 +69,17 @@ namespace plume {
|
||||
struct RenderSampler;
|
||||
struct RenderShader;
|
||||
struct RenderTexture;
|
||||
struct RenderQueryPool;
|
||||
|
||||
// Enums.
|
||||
|
||||
enum class RenderDeviceVendor {
|
||||
UNKNOWN = 0x0,
|
||||
AMD = 0x1002,
|
||||
NVIDIA = 0x10DE,
|
||||
INTEL = 0x8086
|
||||
};
|
||||
|
||||
enum class RenderFormat {
|
||||
UNKNOWN,
|
||||
R32G32B32A32_TYPELESS,
|
||||
@@ -1769,7 +1777,8 @@ namespace plume {
|
||||
struct RenderDeviceDescription {
|
||||
std::string name = "Unknown";
|
||||
RenderDeviceType type = RenderDeviceType::UNKNOWN;
|
||||
uint32_t driverVersion = 0;
|
||||
RenderDeviceVendor vendor = RenderDeviceVendor::UNKNOWN;
|
||||
uint64_t driverVersion = 0;
|
||||
uint64_t dedicatedVideoMemory = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -2522,6 +2522,80 @@ namespace plume {
|
||||
return (depthAttachment == attachment);
|
||||
}
|
||||
|
||||
// VulkanQueryPool
|
||||
|
||||
VulkanQueryPool::VulkanQueryPool(VulkanDevice *device, uint32_t queryCount) {
|
||||
assert(device != nullptr);
|
||||
assert(queryCount > 0);
|
||||
|
||||
this->device = device;
|
||||
|
||||
VkQueryPoolCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
|
||||
createInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
|
||||
createInfo.queryCount = queryCount;
|
||||
|
||||
VkResult res = vkCreateQueryPool(device->vk, &createInfo, nullptr, &vk);
|
||||
if (res != VK_SUCCESS) {
|
||||
fprintf(stderr, "vkCreateQueryPool failed with error code 0x%X.\n", res);
|
||||
return;
|
||||
}
|
||||
|
||||
results.resize(queryCount);
|
||||
}
|
||||
|
||||
VulkanQueryPool::~VulkanQueryPool() {
|
||||
vkDestroyQueryPool(device->vk, vk, nullptr);
|
||||
}
|
||||
|
||||
void VulkanQueryPool::queryResults() {
|
||||
VkResult res = vkGetQueryPoolResults(device->vk, vk, 0, uint32_t(results.size()), sizeof(uint64_t) * results.size(), results.data(), sizeof(uint64_t), VK_QUERY_RESULT_64_BIT);
|
||||
if (res != VK_SUCCESS) {
|
||||
fprintf(stderr, "vkGetQueryPoolResults failed with error code 0x%X.\n", res);
|
||||
return;
|
||||
}
|
||||
|
||||
// Conversion sourced from Godot Engine's Vulkan Rendering Driver.
|
||||
auto mult64to128 = [](uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) {
|
||||
uint64_t u1 = (u & 0xffffffff);
|
||||
uint64_t v1 = (v & 0xffffffff);
|
||||
uint64_t t = (u1 * v1);
|
||||
uint64_t w3 = (t & 0xffffffff);
|
||||
uint64_t k = (t >> 32);
|
||||
|
||||
u >>= 32;
|
||||
t = (u * v1) + k;
|
||||
k = (t & 0xffffffff);
|
||||
uint64_t w1 = (t >> 32);
|
||||
|
||||
v >>= 32;
|
||||
t = (u1 * v) + k;
|
||||
k = (t >> 32);
|
||||
|
||||
h = (u * v) + w1 + k;
|
||||
l = (t << 32) + w3;
|
||||
};
|
||||
|
||||
// Convert results to timestamps.
|
||||
constexpr uint64_t shift_bits = 16;
|
||||
double timestampPeriod = double(device->physicalDeviceProperties.limits.timestampPeriod);
|
||||
uint64_t h = 0, l = 0;
|
||||
for (uint64_t &result : results) {
|
||||
mult64to128(result, uint64_t(timestampPeriod * double(1 << shift_bits)), h, l);
|
||||
result = l;
|
||||
result >>= shift_bits;
|
||||
result |= h << (64 - shift_bits);
|
||||
}
|
||||
}
|
||||
|
||||
const uint64_t *VulkanQueryPool::getResults() const {
|
||||
return results.data();
|
||||
}
|
||||
|
||||
uint32_t VulkanQueryPool::getCount() const {
|
||||
return uint32_t(results.size());
|
||||
}
|
||||
|
||||
// VulkanCommandList
|
||||
|
||||
VulkanCommandList::VulkanCommandList(VulkanDevice *device, RenderCommandListType type) {
|
||||
@@ -3210,6 +3284,20 @@ namespace plume {
|
||||
// Not required in Vulkan.
|
||||
}
|
||||
|
||||
void VulkanCommandList::resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) {
|
||||
assert(queryPool != nullptr);
|
||||
|
||||
const VulkanQueryPool *interfaceQueryPool = static_cast<const VulkanQueryPool *>(queryPool);
|
||||
vkCmdResetQueryPool(vk, interfaceQueryPool->vk, queryFirstIndex, queryCount);
|
||||
}
|
||||
|
||||
void VulkanCommandList::writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) {
|
||||
assert(queryPool != nullptr);
|
||||
|
||||
const VulkanQueryPool *interfaceQueryPool = static_cast<const VulkanQueryPool *>(queryPool);
|
||||
vkCmdWriteTimestamp(vk, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, interfaceQueryPool->vk, queryIndex);
|
||||
}
|
||||
|
||||
void VulkanCommandList::checkActiveRenderPass() {
|
||||
assert(targetFramebuffer != nullptr);
|
||||
|
||||
@@ -3473,7 +3561,7 @@ namespace plume {
|
||||
|
||||
// VulkanDevice
|
||||
|
||||
VulkanDevice::VulkanDevice(VulkanInterface *renderInterface) {
|
||||
VulkanDevice::VulkanDevice(VulkanInterface *renderInterface, const std::string &preferredDeviceName) {
|
||||
assert(renderInterface != nullptr);
|
||||
|
||||
this->renderInterface = renderInterface;
|
||||
@@ -3506,15 +3594,22 @@ namespace plume {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string deviceName(deviceProperties.deviceName);
|
||||
uint32_t deviceTypeScore = deviceTypeScoreTable[deviceTypeIndex];
|
||||
bool preferDeviceTypeScore = (deviceTypeScore > currentDeviceTypeScore);
|
||||
bool preferOption = preferDeviceTypeScore;
|
||||
bool preferUserChoice = preferredDeviceName == deviceName;
|
||||
bool preferOption = preferDeviceTypeScore || preferUserChoice;
|
||||
if (preferOption) {
|
||||
physicalDevice = physicalDevices[i];
|
||||
description.name = std::string(deviceProperties.deviceName);
|
||||
description.name = deviceName;
|
||||
description.type = toDeviceType(deviceProperties.deviceType);
|
||||
description.driverVersion = deviceProperties.driverVersion;
|
||||
description.vendor = RenderDeviceVendor(deviceProperties.vendorID);
|
||||
currentDeviceTypeScore = deviceTypeScore;
|
||||
|
||||
if (preferUserChoice) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3885,6 +3980,10 @@ namespace plume {
|
||||
return std::make_unique<VulkanFramebuffer>(this, desc);
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderQueryPool> VulkanDevice::createQueryPool(uint32_t queryCount) {
|
||||
return std::make_unique<VulkanQueryPool>(this, queryCount);
|
||||
}
|
||||
|
||||
void VulkanDevice::setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) {
|
||||
assert(meshes != nullptr);
|
||||
assert(meshCount > 0);
|
||||
@@ -4233,6 +4332,23 @@ namespace plume {
|
||||
|
||||
// Fill capabilities.
|
||||
capabilities.shaderFormat = RenderShaderFormat::SPIRV;
|
||||
|
||||
// Fill device names.
|
||||
uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
||||
if (deviceCount > 0) {
|
||||
std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, physicalDevices.data());
|
||||
|
||||
for (uint32_t i = 0; i < deviceCount; i++) {
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(physicalDevices[i], &deviceProperties);
|
||||
uint32_t deviceTypeIndex = deviceProperties.deviceType;
|
||||
if (deviceTypeIndex <= 4) {
|
||||
deviceNames.emplace_back(deviceProperties.deviceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VulkanInterface::~VulkanInterface() {
|
||||
@@ -4241,8 +4357,8 @@ namespace plume {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderDevice> VulkanInterface::createDevice() {
|
||||
std::unique_ptr<VulkanDevice> createdDevice = std::make_unique<VulkanDevice>(this);
|
||||
std::unique_ptr<RenderDevice> VulkanInterface::createDevice(const std::string &preferredDeviceName) {
|
||||
std::unique_ptr<VulkanDevice> createdDevice = std::make_unique<VulkanDevice>(this, preferredDeviceName);
|
||||
return createdDevice->isValid() ? std::move(createdDevice) : nullptr;
|
||||
}
|
||||
|
||||
@@ -4250,6 +4366,10 @@ namespace plume {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
const std::vector<std::string> &VulkanInterface::getDeviceNames() const {
|
||||
return deviceNames;
|
||||
}
|
||||
|
||||
bool VulkanInterface::isValid() const {
|
||||
return instance != nullptr;
|
||||
}
|
||||
|
||||
@@ -271,6 +271,18 @@ namespace plume {
|
||||
bool contains(const VulkanTexture *attachment) const;
|
||||
};
|
||||
|
||||
struct VulkanQueryPool : RenderQueryPool {
|
||||
VulkanDevice *device = nullptr;
|
||||
std::vector<uint64_t> results;
|
||||
VkQueryPool vk = VK_NULL_HANDLE;
|
||||
|
||||
VulkanQueryPool(VulkanDevice *device, uint32_t queryCount);
|
||||
virtual ~VulkanQueryPool() override;
|
||||
virtual void queryResults() override;
|
||||
virtual const uint64_t *getResults() const override;
|
||||
virtual uint32_t getCount() const override;
|
||||
};
|
||||
|
||||
struct VulkanCommandList : RenderCommandList {
|
||||
VkCommandBuffer vk = VK_NULL_HANDLE;
|
||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||
@@ -319,6 +331,8 @@ namespace plume {
|
||||
void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override;
|
||||
void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override;
|
||||
void discardTexture(const RenderTexture* texture) override;
|
||||
void resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) override;
|
||||
void writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) override;
|
||||
void checkActiveRenderPass();
|
||||
void endActiveRenderPass();
|
||||
void setDescriptorSet(VkPipelineBindPoint bindPoint, const VulkanPipelineLayout *pipelineLayout, const RenderDescriptorSet *descriptorSet, uint32_t setIndex);
|
||||
@@ -391,7 +405,7 @@ namespace plume {
|
||||
VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationProperties = {};
|
||||
bool loadStoreOpNoneSupported = false;
|
||||
|
||||
VulkanDevice(VulkanInterface *renderInterface);
|
||||
VulkanDevice(VulkanInterface *renderInterface, const std::string &preferredDeviceName);
|
||||
~VulkanDevice() override;
|
||||
std::unique_ptr<RenderCommandList> createCommandList(RenderCommandListType type) override;
|
||||
std::unique_ptr<RenderDescriptorSet> createDescriptorSet(const RenderDescriptorSetDesc &desc) override;
|
||||
@@ -409,6 +423,7 @@ namespace plume {
|
||||
std::unique_ptr<RenderCommandFence> createCommandFence() override;
|
||||
std::unique_ptr<RenderCommandSemaphore> createCommandSemaphore() override;
|
||||
std::unique_ptr<RenderFramebuffer> createFramebuffer(const RenderFramebufferDesc &desc) override;
|
||||
std::unique_ptr<RenderQueryPool> createQueryPool(uint32_t queryCount) override;
|
||||
void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) override;
|
||||
void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild, bool preferFastTrace) override;
|
||||
void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) override;
|
||||
@@ -424,6 +439,7 @@ namespace plume {
|
||||
VkInstance instance = VK_NULL_HANDLE;
|
||||
VkApplicationInfo appInfo = {};
|
||||
RenderInterfaceCapabilities capabilities;
|
||||
std::vector<std::string> deviceNames;
|
||||
|
||||
# if SDL_VULKAN_ENABLED
|
||||
VulkanInterface(RenderWindow sdlWindow);
|
||||
@@ -432,8 +448,9 @@ namespace plume {
|
||||
# endif
|
||||
|
||||
~VulkanInterface() override;
|
||||
std::unique_ptr<RenderDevice> createDevice() override;
|
||||
std::unique_ptr<RenderDevice> createDevice(const std::string &preferredDeviceName) override;
|
||||
const RenderInterfaceCapabilities &getCapabilities() const override;
|
||||
const std::vector<std::string> &getDeviceNames() const override;
|
||||
bool isValid() const;
|
||||
};
|
||||
};
|
||||
|
||||
+274
-59
@@ -230,6 +230,55 @@ static void SetDirtyValue(bool& dirtyState, T& dest, const T& src)
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr size_t PROFILER_VALUE_COUNT = 256;
|
||||
static size_t g_profilerValueIndex;
|
||||
|
||||
struct Profiler
|
||||
{
|
||||
std::atomic<double> value;
|
||||
double values[PROFILER_VALUE_COUNT];
|
||||
std::chrono::steady_clock::time_point start;
|
||||
|
||||
void Begin()
|
||||
{
|
||||
start = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void End()
|
||||
{
|
||||
value = std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - start).count();
|
||||
}
|
||||
|
||||
void Set(double v)
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
End();
|
||||
Begin();
|
||||
}
|
||||
|
||||
double UpdateAndReturnAverage()
|
||||
{
|
||||
values[g_profilerValueIndex] = value;
|
||||
return std::accumulate(values, values + PROFILER_VALUE_COUNT, 0.0) / PROFILER_VALUE_COUNT;
|
||||
}
|
||||
};
|
||||
|
||||
static double g_applicationValues[PROFILER_VALUE_COUNT];
|
||||
static Profiler g_gpuFrameProfiler;
|
||||
static Profiler g_presentProfiler;
|
||||
static Profiler g_updateDirectorProfiler;
|
||||
static Profiler g_renderDirectorProfiler;
|
||||
static Profiler g_frameFenceProfiler;
|
||||
static Profiler g_presentWaitProfiler;
|
||||
static Profiler g_swapChainAcquireProfiler;
|
||||
|
||||
static bool g_profilerVisible;
|
||||
static bool g_profilerWasToggled;
|
||||
|
||||
#ifdef UNLEASHED_RECOMP_D3D12
|
||||
static bool g_vulkan = false;
|
||||
#else
|
||||
@@ -245,6 +294,7 @@ static std::unique_ptr<RenderDevice> g_device;
|
||||
static RenderDeviceCapabilities g_capabilities;
|
||||
|
||||
static constexpr size_t NUM_FRAMES = 2;
|
||||
static constexpr size_t NUM_QUERIES = 2;
|
||||
|
||||
static uint32_t g_frame = 0;
|
||||
static uint32_t g_nextFrame = 1;
|
||||
@@ -252,6 +302,7 @@ static uint32_t g_nextFrame = 1;
|
||||
static std::unique_ptr<RenderCommandQueue> g_queue;
|
||||
static std::unique_ptr<RenderCommandList> g_commandLists[NUM_FRAMES];
|
||||
static std::unique_ptr<RenderCommandFence> g_commandFences[NUM_FRAMES];
|
||||
static std::unique_ptr<RenderQueryPool> g_queryPools[NUM_FRAMES];
|
||||
static bool g_commandListStates[NUM_FRAMES];
|
||||
|
||||
static Mutex g_copyMutex;
|
||||
@@ -1476,7 +1527,11 @@ static void CheckSwapChain()
|
||||
}
|
||||
|
||||
if (g_swapChainValid)
|
||||
{
|
||||
g_swapChainAcquireProfiler.Begin();
|
||||
g_swapChainValid = g_swapChain->acquireTexture(g_acquireSemaphores[g_frame].get(), &g_backBufferIndex);
|
||||
g_swapChainAcquireProfiler.End();
|
||||
}
|
||||
|
||||
if (g_needsResize)
|
||||
Video::ComputeViewportDimensions();
|
||||
@@ -1552,6 +1607,8 @@ static void BeginCommandList()
|
||||
auto& commandList = g_commandLists[g_frame];
|
||||
|
||||
commandList->begin();
|
||||
commandList->resetQueryPool(g_queryPools[g_frame].get(), 0, NUM_QUERIES);
|
||||
commandList->writeTimestamp(g_queryPools[g_frame].get(), 0);
|
||||
commandList->setGraphicsPipelineLayout(g_pipelineLayout.get());
|
||||
commandList->setGraphicsDescriptorSet(g_textureDescriptorSet.get(), 0);
|
||||
commandList->setGraphicsDescriptorSet(g_textureDescriptorSet.get(), 1);
|
||||
@@ -1567,6 +1624,8 @@ static void ApplyLowEndDefault(ConfigDef<T> &configDef, T newDefault, bool &chan
|
||||
configDef = newDefault;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
configDef.DefaultValue = newDefault;
|
||||
}
|
||||
|
||||
static void ApplyLowEndDefaults()
|
||||
@@ -1615,10 +1674,29 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
|
||||
g_interface = interfaceFunction();
|
||||
if (g_interface != nullptr)
|
||||
{
|
||||
g_device = g_interface->createDevice();
|
||||
g_device = g_interface->createDevice(Config::GraphicsDevice);
|
||||
if (g_device != nullptr)
|
||||
{
|
||||
const RenderDeviceDescription &deviceDescription = g_device->getDescription();
|
||||
|
||||
#ifdef UNLEASHED_RECOMP_D3D12
|
||||
if (interfaceFunction == CreateD3D12Interface)
|
||||
{
|
||||
if (deviceDescription.vendor == RenderDeviceVendor::AMD)
|
||||
{
|
||||
// AMD Drivers before this version have a known issue where MSAA resolve targets will fail to work correctly.
|
||||
// If no specific graphics API was selected, we silently destroy this one and move to the next option as it'll
|
||||
// just work incorrectly otherwise and result in visual glitches and 3D rendering not working in general.
|
||||
constexpr uint64_t MinimumAMDDriverVersion = 0x1F00005DC2005CULL; // 31.0.24002.92
|
||||
if ((Config::GraphicsAPI == EGraphicsAPI::Auto) && (deviceDescription.driverVersion < MinimumAMDDriverVersion))
|
||||
{
|
||||
g_device.reset();
|
||||
g_interface.reset();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_vulkan = (interfaceFunction == CreateVulkanInterfaceWrapper);
|
||||
#endif
|
||||
break;
|
||||
@@ -1655,6 +1733,9 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
|
||||
for (auto& commandFence : g_commandFences)
|
||||
commandFence = g_device->createCommandFence();
|
||||
|
||||
for (auto& queryPool : g_queryPools)
|
||||
queryPool = g_device->createQueryPool(NUM_QUERIES);
|
||||
|
||||
g_copyQueue = g_device->createCommandQueue(RenderCommandListType::COPY);
|
||||
g_copyCommandList = g_device->createCommandList(RenderCommandListType::COPY);
|
||||
g_copyCommandFence = g_device->createCommandFence();
|
||||
@@ -1875,8 +1956,12 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t g_waitForGPUCount = 0;
|
||||
|
||||
void Video::WaitForGPU()
|
||||
{
|
||||
g_waitForGPUCount++;
|
||||
|
||||
if (g_vulkan)
|
||||
{
|
||||
g_device->waitIdle();
|
||||
@@ -2125,45 +2210,6 @@ static uint32_t HashVertexDeclaration(uint32_t vertexDeclaration)
|
||||
return vertexDeclaration;
|
||||
}
|
||||
|
||||
static constexpr size_t PROFILER_VALUE_COUNT = 256;
|
||||
static size_t g_profilerValueIndex;
|
||||
|
||||
struct Profiler
|
||||
{
|
||||
std::atomic<double> value;
|
||||
double values[PROFILER_VALUE_COUNT];
|
||||
std::chrono::steady_clock::time_point start;
|
||||
|
||||
void Begin()
|
||||
{
|
||||
start = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void End()
|
||||
{
|
||||
value = std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - start).count();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
End();
|
||||
Begin();
|
||||
}
|
||||
|
||||
double UpdateAndReturnAverage()
|
||||
{
|
||||
values[g_profilerValueIndex] = value;
|
||||
return std::accumulate(values, values + PROFILER_VALUE_COUNT, 0.0) / PROFILER_VALUE_COUNT;
|
||||
}
|
||||
};
|
||||
|
||||
static double g_applicationValues[PROFILER_VALUE_COUNT];
|
||||
static Profiler g_presentProfiler;
|
||||
static Profiler g_renderDirectorProfiler;
|
||||
|
||||
static bool g_profilerVisible;
|
||||
static bool g_profilerWasToggled;
|
||||
|
||||
static const char *DeviceTypeName(RenderDeviceType type)
|
||||
{
|
||||
switch (type)
|
||||
@@ -2186,8 +2232,12 @@ static void DrawProfiler()
|
||||
bool toggleProfiler = SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_F1] != 0;
|
||||
|
||||
if (!g_profilerWasToggled && toggleProfiler)
|
||||
{
|
||||
g_profilerVisible = !g_profilerVisible;
|
||||
|
||||
GameWindow::SetFullscreenCursorVisibility(App::s_isInit ? g_profilerVisible : true);
|
||||
}
|
||||
|
||||
g_profilerWasToggled = toggleProfiler;
|
||||
|
||||
if (!g_profilerVisible)
|
||||
@@ -2203,29 +2253,51 @@ static void DrawProfiler()
|
||||
g_applicationValues[g_profilerValueIndex] = App::s_deltaTime * 1000.0;
|
||||
|
||||
const double applicationAvg = std::accumulate(g_applicationValues, g_applicationValues + PROFILER_VALUE_COUNT, 0.0) / PROFILER_VALUE_COUNT;
|
||||
double gpuFrameAvg = g_gpuFrameProfiler.UpdateAndReturnAverage();
|
||||
double presentAvg = g_presentProfiler.UpdateAndReturnAverage();
|
||||
double updateDirectorAvg = g_updateDirectorProfiler.UpdateAndReturnAverage();
|
||||
double renderDirectorAvg = g_renderDirectorProfiler.UpdateAndReturnAverage();
|
||||
double frameFenceAvg = g_frameFenceProfiler.UpdateAndReturnAverage();
|
||||
double presentWaitAvg = g_presentWaitProfiler.UpdateAndReturnAverage();
|
||||
double swapChainAcquireAvg = g_swapChainAcquireProfiler.UpdateAndReturnAverage();
|
||||
|
||||
if (ImPlot::BeginPlot("Frame Time"))
|
||||
{
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1, 0.0, 20.0);
|
||||
ImPlot::SetupAxis(ImAxis_Y1, "ms", ImPlotAxisFlags_None);
|
||||
ImPlot::PlotLine<double>("Application", g_applicationValues, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
|
||||
ImPlot::PlotLine<double>("GPU Frame", g_gpuFrameProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
|
||||
ImPlot::PlotLine<double>("Present", g_presentProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
|
||||
ImPlot::PlotLine<double>("Update Director", g_updateDirectorProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
|
||||
ImPlot::PlotLine<double>("Render Director", g_renderDirectorProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
|
||||
ImPlot::PlotLine<double>("Frame Fence", g_frameFenceProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
|
||||
ImPlot::PlotLine<double>("Present Wait", g_presentWaitProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
|
||||
ImPlot::PlotLine<double>("Swap Chain Acquire", g_swapChainAcquireProfiler.values, PROFILER_VALUE_COUNT, 1.0, 0.0, ImPlotLineFlags_None, g_profilerValueIndex);
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
|
||||
g_profilerValueIndex = (g_profilerValueIndex + 1) % PROFILER_VALUE_COUNT;
|
||||
|
||||
ImGui::Text("Current Application: %g ms (%g FPS)", App::s_deltaTime * 1000.0, 1.0 / App::s_deltaTime);
|
||||
ImGui::Text("Current GPU Frame: %g ms (%g FPS)", g_gpuFrameProfiler.value.load(), 1000.0 / g_gpuFrameProfiler.value.load());
|
||||
ImGui::Text("Current Present: %g ms (%g FPS)", g_presentProfiler.value.load(), 1000.0 / g_presentProfiler.value.load());
|
||||
ImGui::Text("Current Update Director: %g ms (%g FPS)", g_updateDirectorProfiler.value.load(), 1000.0 / g_updateDirectorProfiler.value.load());
|
||||
ImGui::Text("Current Render Director: %g ms (%g FPS)", g_renderDirectorProfiler.value.load(), 1000.0 / g_renderDirectorProfiler.value.load());
|
||||
ImGui::Text("Current Frame Fence: %g ms", g_frameFenceProfiler.value.load());
|
||||
ImGui::Text("Current Present Wait: %g ms", g_presentWaitProfiler.value.load());
|
||||
ImGui::Text("Current Swap Chain Acquire: %g ms", g_swapChainAcquireProfiler.value.load());
|
||||
|
||||
ImGui::NewLine();
|
||||
|
||||
ImGui::Text("Average Application: %g ms (%g FPS)", applicationAvg, 1000.0 / applicationAvg);
|
||||
ImGui::Text("Average GPU Frame: %g ms (%g FPS)", gpuFrameAvg, 1000.0 / gpuFrameAvg);
|
||||
ImGui::Text("Average Present: %g ms (%g FPS)", presentAvg, 1000.0 / presentAvg);
|
||||
ImGui::Text("Average Update Director: %g ms (%g FPS)", updateDirectorAvg, 1000.0 / updateDirectorAvg);
|
||||
ImGui::Text("Average Render Director: %g ms (%g FPS)", renderDirectorAvg, 1000.0 / renderDirectorAvg);
|
||||
ImGui::Text("Average Frame Fence: %g ms", frameFenceAvg);
|
||||
ImGui::Text("Average Present Wait: %g ms", presentWaitAvg);
|
||||
ImGui::Text("Average Swap Chain Acquire: %g ms", swapChainAcquireAvg);
|
||||
|
||||
ImGui::NewLine();
|
||||
|
||||
O1HeapDiagnostics diagnostics, physicalDiagnostics;
|
||||
@@ -2240,6 +2312,7 @@ static void DrawProfiler()
|
||||
|
||||
ImGui::Text("Heap Allocated: %d MB", int32_t(diagnostics.allocated / (1024 * 1024)));
|
||||
ImGui::Text("Physical Heap Allocated: %d MB", int32_t(physicalDiagnostics.allocated / (1024 * 1024)));
|
||||
ImGui::Text("GPU Waits: %d", int32_t(g_waitForGPUCount));
|
||||
ImGui::NewLine();
|
||||
|
||||
ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported");
|
||||
@@ -2256,6 +2329,24 @@ static void DrawProfiler()
|
||||
const char* sdlVideoDriver = SDL_GetCurrentVideoDriver();
|
||||
if (sdlVideoDriver != nullptr)
|
||||
ImGui::Text("SDL Video Driver: %s", sdlVideoDriver);
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::Checkbox("Show FPS", &Config::ShowFPS.Value);
|
||||
ImGui::NewLine();
|
||||
|
||||
if (ImGui::TreeNode("Device Names"))
|
||||
{
|
||||
ImGui::Indent();
|
||||
|
||||
uint32_t deviceIndex = 0;
|
||||
for (const std::string &deviceName : g_interface->getDeviceNames())
|
||||
{
|
||||
ImGui::Text("Option #%d: %s", deviceIndex++, deviceName.c_str());
|
||||
}
|
||||
|
||||
ImGui::Unindent();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
@@ -2263,6 +2354,43 @@ static void DrawProfiler()
|
||||
font->Scale = defaultScale;
|
||||
}
|
||||
|
||||
static void DrawFPS()
|
||||
{
|
||||
if (!Config::ShowFPS)
|
||||
return;
|
||||
|
||||
double time = ImGui::GetTime();
|
||||
static double updateTime = time;
|
||||
static double fps = 0;
|
||||
static double totalDeltaTime = 0.0;
|
||||
static uint32_t totalDeltaCount = 0;
|
||||
|
||||
totalDeltaTime += g_presentProfiler.value.load();
|
||||
totalDeltaCount++;
|
||||
|
||||
if (time - updateTime >= 1.0f)
|
||||
{
|
||||
fps = 1000.0 / std::max(totalDeltaTime / double(totalDeltaCount), 1.0);
|
||||
updateTime = time;
|
||||
totalDeltaTime = 0.0;
|
||||
totalDeltaCount = 0;
|
||||
}
|
||||
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
auto fmt = fmt::format("FPS: {:.2f}", fps);
|
||||
auto font = ImFontAtlasSnapshot::GetFont("FOT-SeuratPro-M.otf");
|
||||
auto fontSize = Scale(10);
|
||||
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, fmt.c_str());
|
||||
|
||||
ImVec2 min = { Scale(40), Scale(30) };
|
||||
ImVec2 max = { min.x + std::max(Scale(75), textSize.x + Scale(10)), min.y + Scale(15) };
|
||||
ImVec2 textPos = { min.x + Scale(2), CENTRE_TEXT_VERT(min, max, textSize) + Scale(0.2f) };
|
||||
|
||||
drawList->AddRectFilled(min, max, IM_COL32(0, 0, 0, 200));
|
||||
drawList->AddText(font, fontSize, textPos, IM_COL32_WHITE, fmt.c_str());
|
||||
}
|
||||
|
||||
static void DrawImGui()
|
||||
{
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
@@ -2321,8 +2449,9 @@ static void DrawImGui()
|
||||
Fader::Draw();
|
||||
BlackBar::Draw();
|
||||
|
||||
assert(ImGui::GetForegroundDrawList()->_ClipRectStack.Size == 1 && "Some clip rects were not removed from the stack!");
|
||||
assert(ImGui::GetBackgroundDrawList()->_ClipRectStack.Size == 1 && "Some clip rects were not removed from the stack!");
|
||||
|
||||
DrawFPS();
|
||||
DrawProfiler();
|
||||
ImGui::Render();
|
||||
|
||||
@@ -2494,7 +2623,11 @@ void Video::WaitOnSwapChain()
|
||||
if (g_pendingWaitOnSwapChain)
|
||||
{
|
||||
if (g_swapChainValid)
|
||||
{
|
||||
g_presentWaitProfiler.Begin();
|
||||
g_swapChain->wait();
|
||||
g_presentWaitProfiler.End();
|
||||
}
|
||||
|
||||
g_pendingWaitOnSwapChain = false;
|
||||
}
|
||||
@@ -2527,7 +2660,11 @@ void Video::Present()
|
||||
if (g_swapChainValid)
|
||||
{
|
||||
if (g_pendingWaitOnSwapChain)
|
||||
{
|
||||
g_presentWaitProfiler.Begin();
|
||||
g_swapChain->wait(); // Never gonna happen outside loading threads as explained above.
|
||||
g_presentWaitProfiler.End();
|
||||
}
|
||||
|
||||
RenderCommandSemaphore* signalSemaphores[] = { g_renderSemaphores[g_frame].get() };
|
||||
g_swapChainValid = g_swapChain->present(g_backBufferIndex, signalSemaphores, std::size(signalSemaphores));
|
||||
@@ -2540,8 +2677,15 @@ void Video::Present()
|
||||
|
||||
if (g_commandListStates[g_frame])
|
||||
{
|
||||
g_frameFenceProfiler.Begin();
|
||||
g_queue->waitForCommandFence(g_commandFences[g_frame].get());
|
||||
g_frameFenceProfiler.End();
|
||||
g_commandListStates[g_frame] = false;
|
||||
|
||||
// Update the GPU profiler with the results from the timestamps of the frame.
|
||||
g_queryPools[g_frame]->queryResults();
|
||||
const uint64_t *frameTimestamps = g_queryPools[g_frame]->getResults();
|
||||
g_gpuFrameProfiler.Set(double(frameTimestamps[1] - frameTimestamps[0]) / 1000000.0);
|
||||
}
|
||||
|
||||
g_dirtyStates = DirtyStates(true);
|
||||
@@ -2676,6 +2820,7 @@ static void ProcExecuteCommandList(const RenderCommand& cmd)
|
||||
}
|
||||
|
||||
auto &commandList = g_commandLists[g_frame];
|
||||
commandList->writeTimestamp(g_queryPools[g_frame].get(), 1);
|
||||
commandList->end();
|
||||
|
||||
if (g_swapChainValid)
|
||||
@@ -5622,13 +5767,10 @@ PPC_FUNC(sub_8258C8A0)
|
||||
PPC_FUNC_IMPL(__imp__sub_8258CAE0);
|
||||
PPC_FUNC(sub_8258CAE0)
|
||||
{
|
||||
g_renderDirectorProfiler.Begin();
|
||||
|
||||
if (g_needsResize)
|
||||
{
|
||||
// Backup fade values. These get modified by cutscenes,
|
||||
// Backup job values. These get modified by cutscenes,
|
||||
// and resizing will cause the values to be forgotten.
|
||||
// NOTE: Intentionally ignoring the shared pointers here.
|
||||
auto traverseFxJobs = [&]<typename TCallback>(const TCallback& callback)
|
||||
{
|
||||
uint32_t scheduler = PPC_LOAD_U32(ctx.r3.u32 + 0xE0);
|
||||
@@ -5640,28 +5782,63 @@ PPC_FUNC(sub_8258CAE0)
|
||||
for (uint32_t it = PPC_LOAD_U32(member + 0x24); it != PPC_LOAD_U32(member + 0x28); it += 8)
|
||||
{
|
||||
uint32_t job = PPC_LOAD_U32(it);
|
||||
if (job != NULL && PPC_LOAD_U32(job) == 0x820CA6F8) // SWA::CFxFade
|
||||
if (job != NULL)
|
||||
callback(job);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FadeValues
|
||||
union JobValues
|
||||
{
|
||||
uint8_t field50[0x18];
|
||||
uint8_t field88;
|
||||
struct
|
||||
{
|
||||
uint8_t field50[0x18];
|
||||
uint8_t field88;
|
||||
} fade;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t camera[0x120];
|
||||
uint8_t field44;
|
||||
uint8_t fieldA0;
|
||||
} shadowMap;
|
||||
};
|
||||
|
||||
std::map<uint32_t, FadeValues> fadeValuesMap;
|
||||
std::map<uint32_t, JobValues> jobValuesMap;
|
||||
traverseFxJobs([&](uint32_t job)
|
||||
{
|
||||
FadeValues fadeValues{};
|
||||
uint32_t vfTable = PPC_LOAD_U32(job);
|
||||
|
||||
memcpy(fadeValues.field50, base + job + 0x50, sizeof(fadeValues.field50));
|
||||
fadeValues.field88 = PPC_LOAD_U8(job + 0x88);
|
||||
if (vfTable == 0x820CA6F8) // SWA::CFxFade
|
||||
{
|
||||
// NOTE: Intentionally not storing shared pointers here.
|
||||
// Game sends messages that assign these every frame already.
|
||||
JobValues jobValues{};
|
||||
|
||||
fadeValuesMap.emplace(PPC_LOAD_U32(job + 0x48), fadeValues);
|
||||
memcpy(jobValues.fade.field50, base + job + 0x50, sizeof(jobValues.fade.field50));
|
||||
jobValues.fade.field88 = PPC_LOAD_U8(job + 0x88);
|
||||
|
||||
jobValuesMap.emplace(PPC_LOAD_U32(job + 0x48), jobValues);
|
||||
}
|
||||
else if (vfTable == 0x820CAC5C) // SWA::CFxShadowMap
|
||||
{
|
||||
for (uint32_t it = PPC_LOAD_U32(job + 0x88); it != PPC_LOAD_U32(job + 0x8C); it += 8)
|
||||
{
|
||||
uint32_t camera = PPC_LOAD_U32(it);
|
||||
if (camera != NULL && PPC_LOAD_U32(camera) == 0x820BF83C) // SWA::CShadowMapCameraLiSPSM
|
||||
{
|
||||
JobValues jobValues{};
|
||||
|
||||
memcpy(jobValues.shadowMap.camera, base + camera, sizeof(jobValues.shadowMap.camera));
|
||||
jobValues.shadowMap.field44 = PPC_LOAD_U8(job + 0x44);
|
||||
jobValues.shadowMap.fieldA0 = PPC_LOAD_U8(job + 0xA0);
|
||||
|
||||
jobValuesMap.emplace(vfTable, jobValues);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
auto r3 = ctx.r3;
|
||||
@@ -5670,14 +5847,38 @@ PPC_FUNC(sub_8258CAE0)
|
||||
__imp__sub_8258C8A0(ctx, base);
|
||||
ctx.r3 = r3;
|
||||
|
||||
// Restore fade values.
|
||||
// Restore job values.
|
||||
traverseFxJobs([&](uint32_t job)
|
||||
{
|
||||
auto findResult = fadeValuesMap.find(PPC_LOAD_U32(job + 0x48));
|
||||
if (findResult != fadeValuesMap.end()) // May NOT actually be found.
|
||||
uint32_t vfTable = PPC_LOAD_U32(job);
|
||||
|
||||
if (vfTable == 0x820CA6F8) // SWA::CFxFade
|
||||
{
|
||||
memcpy(base + job + 0x50, findResult->second.field50, sizeof(findResult->second.field50));
|
||||
PPC_STORE_U8(job + 0x88, findResult->second.field88);
|
||||
auto findResult = jobValuesMap.find(PPC_LOAD_U32(job + 0x48));
|
||||
if (findResult != jobValuesMap.end()) // May NOT actually be found.
|
||||
{
|
||||
memcpy(base + job + 0x50, findResult->second.fade.field50, sizeof(findResult->second.fade.field50));
|
||||
PPC_STORE_U8(job + 0x88, findResult->second.fade.field88);
|
||||
}
|
||||
}
|
||||
else if (vfTable == 0x820CAC5C) // SWA::CFxShadowMap
|
||||
{
|
||||
auto findResult = jobValuesMap.find(vfTable);
|
||||
if (findResult != jobValuesMap.end()) // Would be weird if this one wasn't found.
|
||||
{
|
||||
for (uint32_t it = PPC_LOAD_U32(job + 0x88); it != PPC_LOAD_U32(job + 0x8C); it += 8)
|
||||
{
|
||||
uint32_t camera = PPC_LOAD_U32(it);
|
||||
if (camera != NULL && PPC_LOAD_U32(camera) == 0x820BF83C) // SWA::CShadowMapCameraLiSPSM
|
||||
{
|
||||
memcpy(base + camera, findResult->second.shadowMap.camera, sizeof(findResult->second.shadowMap.camera));
|
||||
PPC_STORE_U32(job + 0x80, camera);
|
||||
PPC_STORE_U8(job + 0x44, findResult->second.shadowMap.field44);
|
||||
PPC_STORE_U8(job + 0xA0, findResult->second.shadowMap.fieldA0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5685,7 +5886,21 @@ PPC_FUNC(sub_8258CAE0)
|
||||
}
|
||||
|
||||
__imp__sub_8258CAE0(ctx, base);
|
||||
}
|
||||
|
||||
PPC_FUNC_IMPL(__imp__sub_824EB5B0);
|
||||
PPC_FUNC(sub_824EB5B0)
|
||||
{
|
||||
g_updateDirectorProfiler.Begin();
|
||||
__imp__sub_824EB5B0(ctx, base);
|
||||
g_updateDirectorProfiler.End();
|
||||
}
|
||||
|
||||
PPC_FUNC_IMPL(__imp__sub_824EB290);
|
||||
PPC_FUNC(sub_824EB290)
|
||||
{
|
||||
g_renderDirectorProfiler.Begin();
|
||||
__imp__sub_824EB290(ctx, base);
|
||||
g_renderDirectorProfiler.End();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
//#define ASYNC_PSO_DEBUG
|
||||
#define PSO_CACHING
|
||||
/////////////////////////////////////////////////////////////////////#define PSO_CACHING
|
||||
//#define PSO_CACHING_CLEANUP
|
||||
|
||||
#include "rhi/plume_render_interface.h"
|
||||
|
||||
@@ -7,10 +7,14 @@ hid::EInputDevice hid::g_inputDeviceController;
|
||||
hid::EInputDeviceExplicit hid::g_inputDeviceExplicit;
|
||||
|
||||
uint16_t hid::g_prohibitedButtons;
|
||||
bool hid::g_isLeftStickProhibited;
|
||||
bool hid::g_isRightStickProhibited;
|
||||
|
||||
void hid::SetProhibitedButtons(uint16_t wButtons)
|
||||
void hid::SetProhibitedInputs(uint16_t wButtons, bool leftStick, bool rightStick)
|
||||
{
|
||||
hid::g_prohibitedButtons = wButtons;
|
||||
hid::g_isLeftStickProhibited = leftStick;
|
||||
hid::g_isRightStickProhibited = rightStick;
|
||||
}
|
||||
|
||||
bool hid::IsInputAllowed()
|
||||
|
||||
@@ -33,6 +33,8 @@ namespace hid
|
||||
extern EInputDeviceExplicit g_inputDeviceExplicit;
|
||||
|
||||
extern uint16_t g_prohibitedButtons;
|
||||
extern bool g_isLeftStickProhibited;
|
||||
extern bool g_isRightStickProhibited;
|
||||
|
||||
void Init();
|
||||
|
||||
@@ -40,7 +42,7 @@ namespace hid
|
||||
uint32_t SetState(uint32_t dwUserIndex, XAMINPUT_VIBRATION* pVibration);
|
||||
uint32_t GetCapabilities(uint32_t dwUserIndex, XAMINPUT_CAPABILITIES* pCaps);
|
||||
|
||||
void SetProhibitedButtons(uint16_t wButtons);
|
||||
void SetProhibitedInputs(uint16_t wButtons = 0, bool leftStick = false, bool rightStick = false);
|
||||
bool IsInputAllowed();
|
||||
bool IsInputDeviceController();
|
||||
std::string GetInputDeviceName();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include <stdafx.h>
|
||||
#include "file_system.h"
|
||||
#include <cpu/guest_thread.h>
|
||||
#include <kernel/xam.h>
|
||||
#include <kernel/xdm.h>
|
||||
#include <kernel/function.h>
|
||||
#include <cpu/guest_thread.h>
|
||||
#include <os/logger.h>
|
||||
#include <mod/mod_loader.h>
|
||||
#include <os/logger.h>
|
||||
#include <user/config.h>
|
||||
#include <stdafx.h>
|
||||
|
||||
struct FileHandle : KernelObject
|
||||
{
|
||||
@@ -365,8 +366,14 @@ std::filesystem::path FileSystem::ResolvePath(const std::string_view& path, bool
|
||||
if (checkForMods)
|
||||
{
|
||||
std::filesystem::path resolvedPath = ModLoader::ResolvePath(path);
|
||||
|
||||
if (!resolvedPath.empty())
|
||||
{
|
||||
if (ModLoader::s_isLogTypeConsole)
|
||||
LOGF_IMPL(Utility, "Mod Loader", "Loading file: \"{}\"", reinterpret_cast<const char*>(resolvedPath.u8string().c_str()));
|
||||
|
||||
return resolvedPath;
|
||||
}
|
||||
}
|
||||
|
||||
thread_local std::string builtPath;
|
||||
|
||||
@@ -466,6 +466,18 @@ uint32_t XamInputGetState(uint32_t userIndex, uint32_t flags, XAMINPUT_STATE* st
|
||||
|
||||
state->Gamepad.wButtons &= ~hid::g_prohibitedButtons;
|
||||
|
||||
if (hid::g_isLeftStickProhibited)
|
||||
{
|
||||
state->Gamepad.sThumbLX = 0;
|
||||
state->Gamepad.sThumbLY = 0;
|
||||
}
|
||||
|
||||
if (hid::g_isRightStickProhibited)
|
||||
{
|
||||
state->Gamepad.sThumbRX = 0;
|
||||
state->Gamepad.sThumbRY = 0;
|
||||
}
|
||||
|
||||
ByteSwapInplace(state->Gamepad.wButtons);
|
||||
ByteSwapInplace(state->Gamepad.sThumbLX);
|
||||
ByteSwapInplace(state->Gamepad.sThumbLY);
|
||||
|
||||
@@ -10,12 +10,12 @@ namespace xdbf
|
||||
{
|
||||
inline std::string& FixInvalidSequences(std::string& str)
|
||||
{
|
||||
static std::vector<std::string> invalidSequences =
|
||||
static std::array<std::string_view, 1> invalidSequences =
|
||||
{
|
||||
"\xE2\x80\x99"
|
||||
};
|
||||
|
||||
static std::vector<std::string> replaceSequences =
|
||||
static std::array<std::string_view, 1> replaceSequences =
|
||||
{
|
||||
"'"
|
||||
};
|
||||
|
||||
@@ -15,6 +15,28 @@
|
||||
360, which is one of the few consoles to have a port of Sonic
|
||||
Unleashed.
|
||||
|
||||
- Ensure your locale is added in the correct order following the language enum.
|
||||
|
||||
Correct:
|
||||
{
|
||||
{ ELanguage::English, "Example" },
|
||||
{ ELanguage::Japanese, "Example" },
|
||||
{ ELanguage::German, "Example" },
|
||||
{ ELanguage::French, "Example" },
|
||||
{ ELanguage::Spanish, "Example" },
|
||||
{ ELanguage::Italian, "Example" }
|
||||
}
|
||||
|
||||
Incorrect:
|
||||
{
|
||||
{ ELanguage::English, "Example" },
|
||||
{ ELanguage::French, "Example" },
|
||||
{ ELanguage::Spanish, "Example" },
|
||||
{ ELanguage::German, "Example" },
|
||||
{ ELanguage::Italian, "Example" },
|
||||
{ ELanguage::Japanese, "Example" }
|
||||
}
|
||||
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*/
|
||||
|
||||
@@ -34,6 +56,7 @@ CONFIG_DEFINE_LOCALE(Language)
|
||||
{ ELanguage::Italian, { "Lingua", "" } }
|
||||
};
|
||||
|
||||
// Notes: do not localise this.
|
||||
CONFIG_DEFINE_ENUM_LOCALE(ELanguage)
|
||||
{
|
||||
{
|
||||
@@ -97,22 +120,42 @@ CONFIG_DEFINE_ENUM_LOCALE(EVoiceLanguage)
|
||||
|
||||
CONFIG_DEFINE_LOCALE(Hints)
|
||||
{
|
||||
{ ELanguage::English, { "Hints", "Show hint rings in stages." } }
|
||||
{ ELanguage::English, { "Hints", "Show hints during gameplay." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(ControlTutorial)
|
||||
{
|
||||
{ ELanguage::English, { "Control Tutorial", "Show controller hints in stages." } }
|
||||
{ ELanguage::English, { "Control Tutorial", "Show controller hints during gameplay." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(AchievementNotifications)
|
||||
{
|
||||
{ ELanguage::English, { "Achievement Notifications", "Show notifications for unlocking achievements.\n\nAchievements will still be rewarded with notifications disabled." } }
|
||||
{ ELanguage::English, { "Achievement Notifications", "Show notifications for unlocking achievements.\n\nAchievements will still be rewarded with notifications disabled." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(TimeOfDayTransition)
|
||||
{
|
||||
{ ELanguage::English, { "Time of Day Transition", "Change how the loading screen appears when switching time of day in the hub areas." } }
|
||||
{ ELanguage::English, { "Time of Day Transition", "Change how the loading screen appears when switching time of day in the hub areas." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(ETimeOfDayTransition)
|
||||
@@ -123,12 +166,52 @@ CONFIG_DEFINE_ENUM_LOCALE(ETimeOfDayTransition)
|
||||
{ ETimeOfDayTransition::Xbox, { "XBOX", "Xbox: the transformation cutscene will play with artificial loading times." } },
|
||||
{ ETimeOfDayTransition::PlayStation, { "PLAYSTATION", "PlayStation: a spinning medal loading screen will be used instead." } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ ETimeOfDayTransition::Xbox, { "", "" } },
|
||||
{ ETimeOfDayTransition::PlayStation, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ ETimeOfDayTransition::Xbox, { "", "" } },
|
||||
{ ETimeOfDayTransition::PlayStation, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ ETimeOfDayTransition::Xbox, { "", "" } },
|
||||
{ ETimeOfDayTransition::PlayStation, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ ETimeOfDayTransition::Xbox, { "", "" } },
|
||||
{ ETimeOfDayTransition::PlayStation, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ ETimeOfDayTransition::Xbox, { "", "" } },
|
||||
{ ETimeOfDayTransition::PlayStation, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(ControllerIcons)
|
||||
{
|
||||
{ ELanguage::English, { "Controller Icons", "Change the icons to match your controller." } }
|
||||
{ ELanguage::English, { "Controller Icons", "Change the icons to match your controller." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(EControllerIcons)
|
||||
@@ -140,17 +223,67 @@ CONFIG_DEFINE_ENUM_LOCALE(EControllerIcons)
|
||||
{ EControllerIcons::Xbox, { "XBOX", "" } },
|
||||
{ EControllerIcons::PlayStation, { "PLAYSTATION", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ EControllerIcons::Auto, { "", "" } },
|
||||
{ EControllerIcons::Xbox, { "", "" } },
|
||||
{ EControllerIcons::PlayStation, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ EControllerIcons::Auto, { "", "" } },
|
||||
{ EControllerIcons::Xbox, { "", "" } },
|
||||
{ EControllerIcons::PlayStation, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ EControllerIcons::Auto, { "", "" } },
|
||||
{ EControllerIcons::Xbox, { "", "" } },
|
||||
{ EControllerIcons::PlayStation, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ EControllerIcons::Auto, { "", "" } },
|
||||
{ EControllerIcons::Xbox, { "", "" } },
|
||||
{ EControllerIcons::PlayStation, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ EControllerIcons::Auto, { "", "" } },
|
||||
{ EControllerIcons::Xbox, { "", "" } },
|
||||
{ EControllerIcons::PlayStation, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(HorizontalCamera)
|
||||
{
|
||||
{ ELanguage::English, { "Horizontal Camera", "Change how the camera moves left and right." } }
|
||||
{ ELanguage::English, { "Horizontal Camera", "Change how the camera moves left and right." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(VerticalCamera)
|
||||
{
|
||||
{ ELanguage::English, { "Vertical Camera", "Change how the camera moves up and down." } }
|
||||
{ ELanguage::English, { "Vertical Camera", "Change how the camera moves up and down." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(ECameraRotationMode)
|
||||
@@ -161,42 +294,112 @@ CONFIG_DEFINE_ENUM_LOCALE(ECameraRotationMode)
|
||||
{ ECameraRotationMode::Normal, { "NORMAL", "" } },
|
||||
{ ECameraRotationMode::Reverse, { "REVERSE", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ ECameraRotationMode::Normal, { "", "" } },
|
||||
{ ECameraRotationMode::Reverse, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ ECameraRotationMode::Normal, { "", "" } },
|
||||
{ ECameraRotationMode::Reverse, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ ECameraRotationMode::Normal, { "", "" } },
|
||||
{ ECameraRotationMode::Reverse, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ ECameraRotationMode::Normal, { "", "" } },
|
||||
{ ECameraRotationMode::Reverse, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ ECameraRotationMode::Normal, { "", "" } },
|
||||
{ ECameraRotationMode::Reverse, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(Vibration)
|
||||
{
|
||||
{ ELanguage::English, { "Vibration", "Toggle controller vibration." } }
|
||||
{ ELanguage::English, { "Vibration", "Toggle controller vibration." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
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." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(MasterVolume)
|
||||
{
|
||||
{ ELanguage::English, { "Master Volume", "Adjust the overall volume." } }
|
||||
{ ELanguage::English, { "Master Volume", "Adjust the overall volume." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(MusicVolume)
|
||||
{
|
||||
{ ELanguage::English, { "Music Volume", "Adjust the volume for the music." } }
|
||||
{ ELanguage::English, { "Music Volume", "Adjust the volume for the music." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(EffectsVolume)
|
||||
{
|
||||
{ ELanguage::English, { "Effects Volume", "Adjust the volume for sound effects." } }
|
||||
{ ELanguage::English, { "Effects Volume", "Adjust the volume for sound effects." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
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." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(ChannelConfiguration)
|
||||
{
|
||||
{ ELanguage::English, { "Channel Configuration", "Change the output mode for your playback device." } }
|
||||
{ ELanguage::English, { "Channel Configuration", "Change the output mode for your audio device." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(EChannelConfiguration)
|
||||
@@ -207,37 +410,102 @@ CONFIG_DEFINE_ENUM_LOCALE(EChannelConfiguration)
|
||||
{ EChannelConfiguration::Stereo, { "STEREO", "" } },
|
||||
{ EChannelConfiguration::Surround, { "SURROUND", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ EChannelConfiguration::Stereo, { "", "" } },
|
||||
{ EChannelConfiguration::Surround, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ EChannelConfiguration::Stereo, { "", "" } },
|
||||
{ EChannelConfiguration::Surround, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ EChannelConfiguration::Stereo, { "", "" } },
|
||||
{ EChannelConfiguration::Surround, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ EChannelConfiguration::Stereo, { "", "" } },
|
||||
{ EChannelConfiguration::Surround, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ EChannelConfiguration::Stereo, { "", "" } },
|
||||
{ EChannelConfiguration::Surround, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(Subtitles)
|
||||
{
|
||||
{ ELanguage::English, { "Subtitles", "Show subtitles during dialogue." } }
|
||||
{ ELanguage::English, { "Subtitles", "Show subtitles during dialogue." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(BattleTheme)
|
||||
{
|
||||
{ ELanguage::English, { "Battle Theme", "Play the Werehog battle theme during combat.\n\nThis option will apply the next time you're in combat." } }
|
||||
{ ELanguage::English, { "Battle Theme", "Play the Werehog battle theme during combat.\n\nThis option will apply the next time you're in combat.\n\nExorcism missions and miniboss themes will be unaffected." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(WindowSize)
|
||||
{
|
||||
{ ELanguage::English, { "Window Size", "Adjust the size of the game window in windowed mode." } }
|
||||
{ ELanguage::English, { "Window Size", "Adjust the size of the game window in windowed mode." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(Monitor)
|
||||
{
|
||||
{ ELanguage::English, { "Monitor", "Change which monitor to display the game on." } }
|
||||
{ ELanguage::English, { "Monitor", "Change which monitor to display the game on." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(AspectRatio)
|
||||
{
|
||||
{ ELanguage::English, { "Aspect Ratio", "Change the aspect ratio." } }
|
||||
{ ELanguage::English, { "Aspect Ratio", "Change the aspect ratio." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(EAspectRatio)
|
||||
@@ -250,37 +518,112 @@ CONFIG_DEFINE_ENUM_LOCALE(EAspectRatio)
|
||||
{ EAspectRatio::Narrow, { "4:3", "4:3: locks the game to a narrow aspect ratio." } },
|
||||
{ EAspectRatio::OriginalNarrow, { "ORIGINAL 4:3", "Original 4:3: locks the game to a narrow aspect ratio and retains parity with the game's original implementation." } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ EAspectRatio::Auto, { "", "" } },
|
||||
{ EAspectRatio::Wide, { "", "" } },
|
||||
{ EAspectRatio::Narrow, { "", "" } },
|
||||
{ EAspectRatio::OriginalNarrow, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ EAspectRatio::Auto, { "", "" } },
|
||||
{ EAspectRatio::Wide, { "", "" } },
|
||||
{ EAspectRatio::Narrow, { "", "" } },
|
||||
{ EAspectRatio::OriginalNarrow, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ EAspectRatio::Auto, { "", "" } },
|
||||
{ EAspectRatio::Wide, { "", "" } },
|
||||
{ EAspectRatio::Narrow, { "", "" } },
|
||||
{ EAspectRatio::OriginalNarrow, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ EAspectRatio::Auto, { "", "" } },
|
||||
{ EAspectRatio::Wide, { "", "" } },
|
||||
{ EAspectRatio::Narrow, { "", "" } },
|
||||
{ EAspectRatio::OriginalNarrow, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ EAspectRatio::Auto, { "", "" } },
|
||||
{ EAspectRatio::Wide, { "", "" } },
|
||||
{ EAspectRatio::Narrow, { "", "" } },
|
||||
{ EAspectRatio::OriginalNarrow, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(ResolutionScale)
|
||||
{
|
||||
{ ELanguage::English, { "Resolution Scale", "Adjust the internal resolution of the game.\n\n%dx%d" } }
|
||||
{ ELanguage::English, { "Resolution Scale", "Adjust the internal resolution of the game.\n\n%dx%d" } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(Fullscreen)
|
||||
{
|
||||
{ ELanguage::English, { "Fullscreen", "Toggle between borderless fullscreen or windowed mode." } }
|
||||
{ ELanguage::English, { "Fullscreen", "Toggle between borderless fullscreen or windowed mode." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(VSync)
|
||||
{
|
||||
{ ELanguage::English, { "V-Sync", "Synchronize the game to the refresh rate of the display to prevent screen tearing." } }
|
||||
{ ELanguage::English, { "V-Sync", "Synchronize the game to the refresh rate of the display to prevent screen tearing." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(FPS)
|
||||
{
|
||||
{ ELanguage::English, { "FPS", "Set the max frame rate the game can run at.\n\nWARNING: this may introduce glitches at frame rates higher than 60 FPS." } }
|
||||
{ ELanguage::English, { "FPS", "Set the max frame rate the game can run at.\n\nWARNING: this may introduce glitches at frame rates higher than 60 FPS." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(Brightness)
|
||||
{
|
||||
{ ELanguage::English, { "Brightness", "Adjust the brightness level until the symbol on the left is barely visible." } }
|
||||
{ ELanguage::English, { "Brightness", "Adjust the brightness level until the symbol on the left is barely visible." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(AntiAliasing)
|
||||
{
|
||||
{ ELanguage::English, { "Anti-Aliasing", "Adjust the amount of smoothing applied to jagged edges." } }
|
||||
{ ELanguage::English, { "Anti-Aliasing", "Adjust the amount of smoothing applied to jagged edges." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(EAntiAliasing)
|
||||
@@ -288,19 +631,59 @@ CONFIG_DEFINE_ENUM_LOCALE(EAntiAliasing)
|
||||
{
|
||||
ELanguage::English,
|
||||
{
|
||||
{ EAntiAliasing::None, { "NONE", "" } },
|
||||
{ EAntiAliasing::None, { "NONE", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ EAntiAliasing::None, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ EAntiAliasing::None, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ EAntiAliasing::None, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ EAntiAliasing::None, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ EAntiAliasing::None, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(TransparencyAntiAliasing)
|
||||
{
|
||||
{ ELanguage::English, { "Transparency Anti-Aliasing", "Apply anti-aliasing to alpha transparent textures." } }
|
||||
{ ELanguage::English, { "Transparency Anti-Aliasing", "Apply anti-aliasing to alpha transparent textures." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(ShadowResolution)
|
||||
{
|
||||
{ ELanguage::English, { "Shadow Resolution", "Set the resolution of real-time shadows." } }
|
||||
{ ELanguage::English, { "Shadow Resolution", "Set the resolution of real-time shadows." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(EShadowResolution)
|
||||
@@ -310,12 +693,47 @@ CONFIG_DEFINE_ENUM_LOCALE(EShadowResolution)
|
||||
{
|
||||
{ EShadowResolution::Original, { "ORIGINAL", "Original: the game will automatically determine the resolution of the shadows." } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ EShadowResolution::Original, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ EShadowResolution::Original, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ EShadowResolution::Original, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ EShadowResolution::Original, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ EShadowResolution::Original, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(GITextureFiltering)
|
||||
{
|
||||
{ ELanguage::English, { "GI Texture Filtering", "Change the quality of the filtering used for global illumination textures." } }
|
||||
{ ELanguage::English, { "GI Texture Filtering", "Change the quality of the filtering used for global illumination textures." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(EGITextureFiltering)
|
||||
@@ -324,14 +742,54 @@ CONFIG_DEFINE_ENUM_LOCALE(EGITextureFiltering)
|
||||
ELanguage::English,
|
||||
{
|
||||
{ EGITextureFiltering::Bilinear, { "BILINEAR", "" } },
|
||||
{ EGITextureFiltering::Bicubic, { "BICUBIC", "" } },
|
||||
{ EGITextureFiltering::Bicubic, { "BICUBIC", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ EGITextureFiltering::Bilinear, { "", "" } },
|
||||
{ EGITextureFiltering::Bicubic, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ EGITextureFiltering::Bilinear, { "", "" } },
|
||||
{ EGITextureFiltering::Bicubic, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ EGITextureFiltering::Bilinear, { "", "" } },
|
||||
{ EGITextureFiltering::Bicubic, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ EGITextureFiltering::Bilinear, { "", "" } },
|
||||
{ EGITextureFiltering::Bicubic, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ EGITextureFiltering::Bilinear, { "", "" } },
|
||||
{ EGITextureFiltering::Bicubic, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(MotionBlur)
|
||||
{
|
||||
{ ELanguage::English, { "Motion Blur", "Change the quality of the motion blur." } }
|
||||
{ ELanguage::English, { "Motion Blur", "Change the quality of the motion blur." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(EMotionBlur)
|
||||
@@ -343,17 +801,67 @@ CONFIG_DEFINE_ENUM_LOCALE(EMotionBlur)
|
||||
{ EMotionBlur::Original, { "ORIGINAL", "" } },
|
||||
{ EMotionBlur::Enhanced, { "ENHANCED", "Enhanced: uses more samples for smoother motion blur at the cost of performance." } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ EMotionBlur::Off, { "", "" } },
|
||||
{ EMotionBlur::Original, { "", "" } },
|
||||
{ EMotionBlur::Enhanced, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ EMotionBlur::Off, { "", "" } },
|
||||
{ EMotionBlur::Original, { "", "" } },
|
||||
{ EMotionBlur::Enhanced, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ EMotionBlur::Off, { "", "" } },
|
||||
{ EMotionBlur::Original, { "", "" } },
|
||||
{ EMotionBlur::Enhanced, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ EMotionBlur::Off, { "", "" } },
|
||||
{ EMotionBlur::Original, { "", "" } },
|
||||
{ EMotionBlur::Enhanced, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ EMotionBlur::Off, { "", "" } },
|
||||
{ EMotionBlur::Original, { "", "" } },
|
||||
{ EMotionBlur::Enhanced, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(XboxColorCorrection)
|
||||
{
|
||||
{ ELanguage::English, { "Xbox Color Correction", "Use the warm tint from the Xbox version of the game." } }
|
||||
{ ELanguage::English, { "Xbox Color Correction", "Use the warm tint from the Xbox version of the game." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(CutsceneAspectRatio)
|
||||
{
|
||||
{ ELanguage::English, { "Cutscene Aspect Ratio", "Change the aspect ratio of the real-time cutscenes." } }
|
||||
{ ELanguage::English, { "Cutscene Aspect Ratio", "Change the aspect ratio of the real-time cutscenes." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(ECutsceneAspectRatio)
|
||||
@@ -362,14 +870,54 @@ CONFIG_DEFINE_ENUM_LOCALE(ECutsceneAspectRatio)
|
||||
ELanguage::English,
|
||||
{
|
||||
{ ECutsceneAspectRatio::Original, { "ORIGINAL", "Original: locks cutscenes to their original 16:9 aspect ratio." } },
|
||||
{ ECutsceneAspectRatio::Unlocked, { "UNLOCKED", "Unlocked: allows cutscenes to adjust their aspect ratio to the window size.\n\nWARNING: this will introduce visual oddities past the original 16:9 aspect ratio." } },
|
||||
{ ECutsceneAspectRatio::Unlocked, { "UNLOCKED", "Unlocked: allows cutscenes to adjust their aspect ratio to the window size.\n\nWARNING: this will introduce visual oddities past the original 16:9 aspect ratio." } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ ECutsceneAspectRatio::Original, { "", "" } },
|
||||
{ ECutsceneAspectRatio::Unlocked, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ ECutsceneAspectRatio::Original, { "", "" } },
|
||||
{ ECutsceneAspectRatio::Unlocked, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ ECutsceneAspectRatio::Original, { "", "" } },
|
||||
{ ECutsceneAspectRatio::Unlocked, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ ECutsceneAspectRatio::Original, { "", "" } },
|
||||
{ ECutsceneAspectRatio::Unlocked, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ ECutsceneAspectRatio::Original, { "", "" } },
|
||||
{ ECutsceneAspectRatio::Unlocked, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_LOCALE(UIAlignmentMode)
|
||||
{
|
||||
{ ELanguage::English, { "UI Alignment Mode", "Change how the UI aligns with the display." } }
|
||||
{ ELanguage::English, { "UI Alignment Mode", "Change how the UI aligns with the display." } },
|
||||
{ ELanguage::Japanese, { "", "" } },
|
||||
{ ELanguage::German, { "", "" } },
|
||||
{ ELanguage::French, { "", "" } },
|
||||
{ ELanguage::Spanish, { "", "" } },
|
||||
{ ELanguage::Italian, { "", "" } }
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALE(EUIAlignmentMode)
|
||||
@@ -378,7 +926,42 @@ CONFIG_DEFINE_ENUM_LOCALE(EUIAlignmentMode)
|
||||
ELanguage::English,
|
||||
{
|
||||
{ EUIAlignmentMode::Edge, { "EDGE", "Edge: the UI will align with the edges of the display." } },
|
||||
{ EUIAlignmentMode::Centre, { "CENTER", "Center: the UI will align with the center of the display." } },
|
||||
{ EUIAlignmentMode::Centre, { "CENTER", "Center: the UI will align with the center of the display." } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Japanese,
|
||||
{
|
||||
{ EUIAlignmentMode::Edge, { "", "" } },
|
||||
{ EUIAlignmentMode::Centre, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::German,
|
||||
{
|
||||
{ EUIAlignmentMode::Edge, { "", "" } },
|
||||
{ EUIAlignmentMode::Centre, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::French,
|
||||
{
|
||||
{ EUIAlignmentMode::Edge, { "", "" } },
|
||||
{ EUIAlignmentMode::Centre, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Spanish,
|
||||
{
|
||||
{ EUIAlignmentMode::Edge, { "", "" } },
|
||||
{ EUIAlignmentMode::Centre, { "", "" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
ELanguage::Italian,
|
||||
{
|
||||
{ EUIAlignmentMode::Edge, { "", "" } },
|
||||
{ EUIAlignmentMode::Centre, { "", "" } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+392
-109
@@ -16,6 +16,28 @@
|
||||
360, which is one of the few consoles to have a port of Sonic
|
||||
Unleashed.
|
||||
|
||||
- Ensure your locale is added in the correct order following the language enum.
|
||||
|
||||
Correct:
|
||||
{
|
||||
{ ELanguage::English, "Example" },
|
||||
{ ELanguage::Japanese, "Example" },
|
||||
{ ELanguage::German, "Example" },
|
||||
{ ELanguage::French, "Example" },
|
||||
{ ELanguage::Spanish, "Example" },
|
||||
{ ELanguage::Italian, "Example" }
|
||||
}
|
||||
|
||||
Incorrect:
|
||||
{
|
||||
{ ELanguage::English, "Example" },
|
||||
{ ELanguage::French, "Example" },
|
||||
{ ELanguage::Spanish, "Example" },
|
||||
{ ELanguage::German, "Example" },
|
||||
{ ELanguage::Italian, "Example" },
|
||||
{ ELanguage::Japanese, "Example" }
|
||||
}
|
||||
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*/
|
||||
|
||||
@@ -24,347 +46,550 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
||||
{
|
||||
"Options_Header_Name",
|
||||
{
|
||||
{ ELanguage::English, "OPTIONS" },
|
||||
{ ELanguage::English, "OPTIONS" },
|
||||
{ ELanguage::Japanese, "OPTION" },
|
||||
{ ELanguage::German, "OPTIONEN" },
|
||||
{ ELanguage::French, "OPTIONS" },
|
||||
{ ELanguage::Spanish, "OPCIONES" },
|
||||
{ ELanguage::Italian, "OPZIONI" }
|
||||
{ ELanguage::German, "OPTIONEN" },
|
||||
{ ELanguage::French, "OPTIONS" },
|
||||
{ ELanguage::Spanish, "OPCIONES" },
|
||||
{ ELanguage::Italian, "OPZIONI" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Options_Category_System",
|
||||
{
|
||||
{ ELanguage::English, "SYSTEM" }
|
||||
{ ELanguage::English, "SYSTEM" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Options_Category_Input",
|
||||
{
|
||||
{ ELanguage::English, "INPUT" }
|
||||
{ ELanguage::English, "INPUT" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Options_Category_Audio",
|
||||
{
|
||||
{ ELanguage::English, "AUDIO" }
|
||||
{ ELanguage::English, "AUDIO" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Options_Category_Video",
|
||||
{
|
||||
{ ELanguage::English, "VIDEO" }
|
||||
{ ELanguage::English, "VIDEO" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: integer values in the options menu (e.g. FPS) when at their maximum value.
|
||||
"Options_Value_Max",
|
||||
{
|
||||
{ ELanguage::English, "MAX" }
|
||||
{ ELanguage::English, "MAX" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Options_Name_WindowSize",
|
||||
{
|
||||
{ ELanguage::English, "Window Size" }
|
||||
{ ELanguage::English, "Window Size" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Options_Desc_WindowSize",
|
||||
{
|
||||
{ ELanguage::English, "Adjust the size of the game window in windowed mode." }
|
||||
{ ELanguage::English, "Adjust the size of the game window in windowed mode." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: description for options that cannot be accessed anywhere but the title screen or world map (e.g. Language).
|
||||
"Options_Desc_NotAvailable",
|
||||
{
|
||||
{ ELanguage::English, "This option is not available at this location." }
|
||||
{ ELanguage::English, "This option is not available at this location." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: currently the description for Window Size when in fullscreen.
|
||||
"Options_Desc_NotAvailableFullscreen",
|
||||
{
|
||||
{ ELanguage::English, "This option is not available in fullscreen mode." }
|
||||
{ ELanguage::English, "This option is not available in fullscreen mode." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: currently the description for Monitor when in fullscreen.
|
||||
"Options_Desc_NotAvailableWindowed",
|
||||
{
|
||||
{ ELanguage::English, "This option is not available in windowed mode." }
|
||||
{ ELanguage::English, "This option is not available in windowed mode." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: currently the description for Monitor when the user only has one display connected.
|
||||
"Options_Desc_NotAvailableHardware",
|
||||
{
|
||||
{ ELanguage::English, "This option is not available with your current hardware configuration." }
|
||||
{ ELanguage::English, "This option is not available with your current hardware configuration." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: description for Transparency Anti-Aliasing when MSAA is disabled.
|
||||
"Options_Desc_NotAvailableMSAA",
|
||||
{
|
||||
{ ELanguage::English, "This option is not available without MSAA." }
|
||||
{ ELanguage::English, "This option is not available without MSAA." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: description for Music Attenuation when the user is not running a supported OS.
|
||||
"Options_Desc_OSNotSupported",
|
||||
{
|
||||
{ ELanguage::English, "This option is not supported by your operating system." }
|
||||
{ ELanguage::English, "This option is not supported by your operating system." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when changing the Language option and backing out of the options menu.
|
||||
"Options_Message_Restart",
|
||||
{
|
||||
{ ELanguage::English, "The game will now restart." }
|
||||
{ ELanguage::English, "The game will now restart." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: used for the button guide at the pause menu.
|
||||
"Achievements_Name",
|
||||
{
|
||||
{ ELanguage::English, "Achievements" }
|
||||
{ ELanguage::English, "Achievements" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: used for the header in the achievements menu.
|
||||
"Achievements_Name_Uppercase",
|
||||
{
|
||||
{ ELanguage::English, "ACHIEVEMENTS" }
|
||||
{ ELanguage::English, "ACHIEVEMENTS" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Achievements_Unlock",
|
||||
{
|
||||
{ ELanguage::English, "Achievement Unlocked!" }
|
||||
{ ELanguage::English, "Achievement Unlocked!" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Header_Installer",
|
||||
{
|
||||
{ ELanguage::English, "INSTALLER" },
|
||||
{ ELanguage::Spanish, "INSTALADOR" },
|
||||
{ ELanguage::Italian, "INSTALLATORE" },
|
||||
{ ELanguage::English, "INSTALLER" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "INSTALADOR" },
|
||||
{ ELanguage::Italian, "INSTALLATORE" },
|
||||
},
|
||||
},
|
||||
{
|
||||
"Installer_Header_Installing",
|
||||
{
|
||||
{ ELanguage::English, "INSTALLING" },
|
||||
{ ELanguage::Spanish, "INSTALANDO" },
|
||||
{ ELanguage::Italian, "INSTALLANDO" },
|
||||
{ ELanguage::English, "INSTALLING" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "INSTALANDO" },
|
||||
{ ELanguage::Italian, "INSTALLANDO" },
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Page_SelectLanguage",
|
||||
{
|
||||
{ ELanguage::English, "Please select a language." },
|
||||
{ ELanguage::Italian, "Seleziona una lingua." }
|
||||
{ ELanguage::English, "Please select a language." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Seleziona una lingua." }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Page_Introduction",
|
||||
{
|
||||
{ ELanguage::English, "Welcome to\nUnleashed Recompiled!\n\nYou'll need an Xbox 360 copy\nof Sonic Unleashed in order to proceed with the installation." },
|
||||
{ ELanguage::Italian, "Benvenuto a\nUnleashed Recompiled!\n\nDovrai avere una copia di\nSonic Unleashed per la Xbox 360\nper proseguire con l'installazione." }
|
||||
{ ELanguage::English, "Welcome to\nUnleashed Recompiled!\n\nYou'll need an Xbox 360 copy\nof Sonic Unleashed in order to proceed with the installation." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Benvenuto a\nUnleashed Recompiled!\n\nDovrai avere una copia di\nSonic Unleashed per la Xbox 360\nper proseguire con l'installazione." }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Page_SelectGameAndUpdate",
|
||||
{
|
||||
{ ELanguage::English, "Add the sources for the game and its title update." }
|
||||
{ ELanguage::English, "Add the sources for the game and its title update." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Page_SelectDLC",
|
||||
{
|
||||
{ ELanguage::English, "Add the sources for the DLC." }
|
||||
{ ELanguage::English, "Add the sources for the DLC." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Page_CheckSpace",
|
||||
{
|
||||
{ ELanguage::English, "The content will be installed to the program's folder.\n\n" },
|
||||
{ ELanguage::Italian, "Il contenuto verrà installato nella cartella di questo programma.\n\n" }
|
||||
{ ELanguage::English, "The content will be installed to the program's folder.\n\n" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Il contenuto verrà installato nella cartella di questo programma.\n\n" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Page_Installing",
|
||||
{
|
||||
{ ELanguage::English, "Please wait while the content is being installed..." },
|
||||
{ ELanguage::Italian, "Attendi mentre il contenuto viene installato... " }
|
||||
{ ELanguage::English, "Please wait while the content is being installed..." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Attendi mentre il contenuto viene installato... " }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Page_InstallSucceeded",
|
||||
{
|
||||
{ ELanguage::English, "Installation complete!\nThis project is brought to you by:" }
|
||||
{ ELanguage::English, "Installation complete!\nThis project is brought to you by:" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Page_InstallFailed",
|
||||
{
|
||||
{ ELanguage::English, "Installation failed.\n\nError:\n\n" },
|
||||
{ ELanguage::Italian, "Installazione fallita.\n\nErrore:\n\n" }
|
||||
{ ELanguage::English, "Installation failed.\n\nError:\n\n" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Installazione fallita.\n\nErrore:\n\n" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Step_Game",
|
||||
{
|
||||
{ ELanguage::English, "GAME" },
|
||||
{ ELanguage::Italian, "GIOCO" }
|
||||
{ ELanguage::English, "GAME" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "GIOCO" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Step_Update",
|
||||
{
|
||||
{ ELanguage::English, "UPDATE" },
|
||||
{ ELanguage::Italian, "AGGIORNAMENTO" }
|
||||
{ ELanguage::English, "UPDATE" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "AGGIORNAMENTO" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Step_RequiredSpace",
|
||||
{
|
||||
{ ELanguage::English, "Required space: %2.2f GiB" },
|
||||
{ ELanguage::Italian, "Spazio necessario: %2.2f GiB" }
|
||||
{ ELanguage::English, "Required space: %2.2f GiB" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Spazio necessario: %2.2f GiB" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Step_AvailableSpace",
|
||||
{
|
||||
{ ELanguage::English, "Available space: %2.2f GiB" },
|
||||
{ ELanguage::Italian, "Spazio disponibile: %2.2f GiB" }
|
||||
{ ELanguage::English, "Available space: %2.2f GiB" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Spazio disponibile: %2.2f GiB" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Button_Next",
|
||||
{
|
||||
{ ELanguage::English, "NEXT" },
|
||||
{ ELanguage::Spanish, "SIGUIENTE" },
|
||||
{ ELanguage::German, "WEITER" },
|
||||
{ ELanguage::Italian, "CONTINUA" }
|
||||
{ ELanguage::English, "NEXT" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "WEITER" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "SIGUIENTE" },
|
||||
{ ELanguage::Italian, "CONTINUA" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Button_Skip",
|
||||
{
|
||||
{ ELanguage::English, "SKIP" },
|
||||
{ ELanguage::Spanish, "SALTAR" },
|
||||
{ ELanguage::German, "ÜBERSPRINGEN" },
|
||||
{ ELanguage::Italian, "SALTA" }
|
||||
{ ELanguage::English, "SKIP" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "ÜBERSPRINGEN" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "SALTAR" },
|
||||
{ ELanguage::Italian, "SALTA" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Button_Retry",
|
||||
{
|
||||
{ ELanguage::English, "RETRY" }
|
||||
{ ELanguage::English, "RETRY" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Button_AddFiles",
|
||||
{
|
||||
{ ELanguage::English, "ADD FILES" },
|
||||
{ ELanguage::Spanish, "AÑADIR ARCHIVOS" },
|
||||
{ ELanguage::German, "DATEIEN HINZUFÜGEN" },
|
||||
{ ELanguage::Italian, "AGGIUNGI FILE" }
|
||||
{ ELanguage::English, "ADD FILES" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "DATEIEN HINZUFÜGEN" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "AÑADIR ARCHIVOS" },
|
||||
{ ELanguage::Italian, "AGGIUNGI FILE" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Installer_Button_AddFolder",
|
||||
{
|
||||
{ ELanguage::English, "ADD FOLDER" },
|
||||
{ ELanguage::Spanish, "AÑADIR CARPETA" },
|
||||
{ ELanguage::German, "ORDNER HINZUFÜGEN" },
|
||||
{ ELanguage::Italian, "AGGIUNGI CARTELLA" }
|
||||
{ ELanguage::English, "ADD FOLDER" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "ORDNER HINZUFÜGEN" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "AÑADIR CARPETA" },
|
||||
{ ELanguage::Italian, "AGGIUNGI CARTELLA" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when using the "Add Files" option and choosing any file that is not an Xbox 360 game dump.
|
||||
"Installer_Message_InvalidFilesList",
|
||||
{
|
||||
{ ELanguage::English, "The following selected files are invalid:" },
|
||||
{ ELanguage::Italian, "I seguenti file non sono validi:" }
|
||||
{ ELanguage::English, "The following selected files are invalid:" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "I seguenti file non sono validi:" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears in the event there are some invalid files after adding the DLC and moving onto the next step.
|
||||
"Installer_Message_InvalidFiles",
|
||||
{
|
||||
{ ELanguage::English, "Some of the files that have\nbeen provided are not valid.\n\nPlease make sure all the\nspecified files are correct\nand try again." },
|
||||
{ ELanguage::Italian, "Alcuni dei file che sono stati\nselezionati non sono validi.\n\nAssicurati che tutti\ni file sono quelli corretti\ne riprova." }
|
||||
{ ELanguage::English, "Some of the files that have\nbeen provided are not valid.\n\nPlease make sure all the\nspecified files are correct\nand try again." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Alcuni dei file che sono stati\nselezionati non sono validi.\n\nAssicurati che tutti\ni file sono quelli corretti\ne riprova." }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when clicking the "Add Files" option for the first time.
|
||||
"Installer_Message_FilePickerTutorial",
|
||||
{
|
||||
{ ELanguage::English, "Select a digital dump with\ncontent from the game.\n\nThese files can be obtained from\nyour Xbox 360 hard drive by\nfollowing the instructions on\nthe GitHub page.\n\nFor choosing a folder with extracted\nand unmodified game files, use\nthe \"Add Folder\" option instead." },
|
||||
{ ELanguage::English, "Select a digital dump with\ncontent from the game.\n\nThese files can be obtained from\nyour Xbox 360 hard drive by\nfollowing the instructions on\nthe GitHub page.\n\nFor choosing a folder with extracted\nand unmodified game files, use\nthe \"Add Folder\" option instead." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when clicking the "Add Folder" option for the first time.
|
||||
"Installer_Message_FolderPickerTutorial",
|
||||
{
|
||||
{ ELanguage::English, "Select a folder that contains the\nunmodified files that have been\nextracted from the game.\n\nThese files can be obtained from\nyour Xbox 360 hard drive by\nfollowing the instructions on\nthe GitHub page.\n\nFor choosing a digital dump,\nuse the\"Add Files\" option instead." },
|
||||
{ ELanguage::English, "Select a folder that contains the\nunmodified files that have been\nextracted from the game.\n\nThese files can be obtained from\nyour Xbox 360 hard drive by\nfollowing the instructions on\nthe GitHub page.\n\nFor choosing a digital dump,\nuse the\"Add Files\" option instead." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when providing a title update that does not match the region or version of the game dump.
|
||||
"Installer_Message_IncompatibleGameData",
|
||||
{
|
||||
{ ELanguage::English, "The specified game and\ntitle update are incompatible.\n\nPlease ensure the files are\nfor the same version and\nregion and try again." },
|
||||
{ ELanguage::Italian, "I file del gioco\ne dell'aggiornamento sono incompatibili.\n\nAssicurati che i file sono\ndella stessa versione\ne regione e riprova." }
|
||||
{ ELanguage::English, "The specified game and\ntitle update are incompatible.\n\nPlease ensure the files are\nfor the same version and\nregion and try again." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "I file del gioco\ne dell'aggiornamento sono incompatibili.\n\nAssicurati che i file sono\ndella stessa versione\ne regione e riprova." }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when clicking Skip at the DLC step.
|
||||
"Installer_Message_DLCWarning",
|
||||
{
|
||||
{ ELanguage::English, "It is highly recommended\nthat you install all of the\nDLC, as it includes high\nquality lighting textures\nfor the base game.\n\nAre you sure you want to\nskip this step?" },
|
||||
{ ELanguage::Italian, "Si consiglia di installare\ntutti i DLC, poichè includono\ntexture di illuminazione di qualità migliore.\n\nSei sicuro di voler saltare?" }
|
||||
{ ELanguage::English, "It is highly recommended\nthat you install all of the\nDLC, as it includes high\nquality lighting textures\nfor the base game.\n\nAre you sure you want to\nskip this step?" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Si consiglia di installare\ntutti i DLC, poichè includono\ntexture di illuminazione di qualità migliore.\n\nSei sicuro di voler saltare?" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when choosing the Install option at the title screen when the user is missing DLC content.
|
||||
"Installer_Message_TitleMissingDLC",
|
||||
{
|
||||
{ ELanguage::English, "This will restart the game to\nallow you to install any DLC\nthat you are missing.\n\nInstalling DLC will improve the\nlighting quality across the game.\n\nWould you like to install missing\ncontent?" },
|
||||
{ ELanguage::Italian, "Questa opzione riavviera il gioco\nper farti installare qualsiasi DLC\nche non hai installato.\n\nL'installazione dei DLC migliorerà la qualità\ndell'illuminazione del gioco.\n\nVuoi installare i DLC mancanti?" }
|
||||
{ ELanguage::English, "This will restart the game to\nallow you to install any DLC\nthat you are missing.\n\nInstalling DLC will improve the\nlighting quality across the game.\n\nWould you like to install missing\ncontent?" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Questa opzione riavviera il gioco\nper farti installare qualsiasi DLC\nche non hai installato.\n\nL'installazione dei DLC migliorerà la qualità\ndell'illuminazione del gioco.\n\nVuoi installare i DLC mancanti?" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when choosing the Install option at the title screen when the user is not missing any content.
|
||||
"Installer_Message_Title",
|
||||
{
|
||||
{ ELanguage::English, "This restarts the game to\nallow you to install any DLC\nthat you may be missing.\n\nYou are not currently\nmissing any DLC.\n\nWould you like to proceed\nanyway?" },
|
||||
{ ELanguage::Italian, "Questa opzione riavviera il gioco\nper farti installare qualsiasi DLC\nche non hai installato.\n\nHai già installato tutti i DLC.\n\nVuoi procedere comunque?" }
|
||||
{ ELanguage::English, "This restarts the game to\nallow you to install any DLC\nthat you may be missing.\n\nYou are not currently\nmissing any DLC.\n\nWould you like to proceed\nanyway?" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Questa opzione riavviera il gioco\nper farti installare qualsiasi DLC\nche non hai installato.\n\nHai già installato tutti i DLC.\n\nVuoi procedere comunque?" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when user chooses "Quit" on the first available installation screen.
|
||||
"Installer_Message_Quit",
|
||||
{
|
||||
{ ELanguage::English, "Are you sure you want to quit?" },
|
||||
{ ELanguage::English, "Are you sure you want to quit?" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when user chooses "Cancel" during installation.
|
||||
"Installer_Message_Cancel",
|
||||
{
|
||||
{ ELanguage::English, "Are you sure you want to cancel the installation?" },
|
||||
{ ELanguage::English, "Are you sure you want to cancel the installation?" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Notes: message appears when pressing B at the title screen.
|
||||
"Title_Message_Quit",
|
||||
{
|
||||
{ ELanguage::English, "Are you sure you want to quit?" },
|
||||
{ ELanguage::Italian, "Sei sicuro di voler uscire?" }
|
||||
{ ELanguage::English, "Are you sure you want to quit?" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Sei sicuro di voler uscire?" }
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -373,12 +598,12 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
||||
// 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::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." }
|
||||
{ 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." }
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -386,7 +611,12 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
||||
// To make this occur, open the file in any editor and just remove a large chunk of data.
|
||||
"Title_Message_AchievementDataCorrupt",
|
||||
{
|
||||
{ ELanguage::English, "The achievement data appears to be\ncorrupted and cannot be loaded.\n\nProceeding from this point will\nclear your achievement data." }
|
||||
{ ELanguage::English, "The achievement data appears to be\ncorrupted and cannot be loaded.\n\nProceeding from this point will\nclear your achievement data." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -394,19 +624,34 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
||||
// To make this occur, lock the ACH-DATA file using an external program so that it cannot be accessed by the game.
|
||||
"Title_Message_AchievementDataIOError",
|
||||
{
|
||||
{ ELanguage::English, "The achievement data could not be loaded.\nYour achievements will not be saved." }
|
||||
{ ELanguage::English, "The achievement data could not be loaded.\nYour achievements will not be saved." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Title_Message_UpdateAvailable",
|
||||
{
|
||||
{ ELanguage::English, "An update is available!\n\nWould you like to visit the\nreleases page to download it?" }
|
||||
{ ELanguage::English, "An update is available!\n\nWould you like to visit the\nreleases page to download it?" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Video_BackendError",
|
||||
{
|
||||
{ ELanguage::English, "Unable to create a D3D12 (Windows) or Vulkan backend.\n\nPlease make sure that:\n\n- Your system meets the minimum requirements.\n- Your GPU drivers are up to date.\n- Your operating system is on the latest version available." }
|
||||
{ ELanguage::English, "Unable to create a D3D12 (Windows) or Vulkan backend.\n\nPlease make sure that:\n\n- Your system meets the minimum requirements.\n- Your GPU drivers are up to date.\n- Your operating system is on the latest version available." },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -434,62 +679,100 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
||||
{
|
||||
"Common_Yes",
|
||||
{
|
||||
{ ELanguage::English, "Yes" },
|
||||
{ ELanguage::Italian, "Sì" }
|
||||
{ ELanguage::English, "Yes" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Sì" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Common_No",
|
||||
{
|
||||
{ ELanguage::English, "No" },
|
||||
{ ELanguage::Italian, "No" }
|
||||
{ ELanguage::English, "No" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "No" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Common_Next",
|
||||
{
|
||||
{ ELanguage::English, "Next" },
|
||||
{ ELanguage::Italian, "Continua" }
|
||||
{ ELanguage::English, "Next" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Continua" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Common_Select",
|
||||
{
|
||||
{ ELanguage::English, "Select" },
|
||||
{ ELanguage::Italian, "Seleziona" }
|
||||
{ ELanguage::English, "Select" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Seleziona" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Common_Back",
|
||||
{
|
||||
{ ELanguage::English, "Back" },
|
||||
{ ELanguage::Italian, "Indietro" }
|
||||
{ ELanguage::English, "Back" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Indietro" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Common_Quit",
|
||||
{
|
||||
{ ELanguage::English, "Quit" },
|
||||
{ ELanguage::English, "Quit" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Common_Cancel",
|
||||
{
|
||||
{ ELanguage::English, "Cancel" }
|
||||
{ ELanguage::English, "Cancel" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Common_Reset",
|
||||
{
|
||||
{ ELanguage::English, "Reset" },
|
||||
{ ELanguage::Italian, "Ripristina" }
|
||||
{ ELanguage::English, "Reset" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Ripristina" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Common_Switch",
|
||||
{
|
||||
{ ELanguage::English, "Switch" },
|
||||
{ ELanguage::Italian, "Cambia" }
|
||||
{ ELanguage::English, "Switch" },
|
||||
{ ELanguage::Japanese, "" },
|
||||
{ ELanguage::German, "" },
|
||||
{ ELanguage::French, "" },
|
||||
{ ELanguage::Spanish, "" },
|
||||
{ ELanguage::Italian, "Cambia" }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#include <cpu/guest_stack_var.h>
|
||||
#include <kernel/function.h>
|
||||
#include <kernel/heap.h>
|
||||
#include <user/config.h>
|
||||
#include <user/paths.h>
|
||||
#include <os/logger.h>
|
||||
#include <os/process.h>
|
||||
#include <xxHashMap.h>
|
||||
|
||||
@@ -117,7 +119,10 @@ void ModLoader::Init()
|
||||
}
|
||||
|
||||
if (configIni.getString("CPKREDIR", "LogType", std::string()) == "console")
|
||||
{
|
||||
os::process::ShowConsole();
|
||||
s_isLogTypeConsole = true;
|
||||
}
|
||||
|
||||
std::string modsDbIniFilePathU8 = configIni.getString("CPKREDIR", "ModsDbIni", "");
|
||||
if (modsDbIniFilePathU8.empty())
|
||||
@@ -208,6 +213,42 @@ void ModLoader::Init()
|
||||
if (!mod.includeDirs.empty())
|
||||
g_mods.emplace_back(std::move(mod));
|
||||
}
|
||||
|
||||
auto codeCount = modsDbIni.get<size_t>("Codes", "CodeCount", 0);
|
||||
|
||||
if (codeCount)
|
||||
{
|
||||
std::vector<std::string> codes{};
|
||||
|
||||
for (size_t i = 0; i < codeCount; i++)
|
||||
{
|
||||
auto name = modsDbIni.getString("Codes", fmt::format("Code{}", i), "");
|
||||
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
codes.push_back(name);
|
||||
}
|
||||
|
||||
for (auto& def : g_configDefinitions)
|
||||
{
|
||||
if (!def->IsHidden() || def->GetSection() != "Codes")
|
||||
continue;
|
||||
|
||||
/* NOTE: this is inefficient, but it happens
|
||||
once on boot for a handful of codes at release
|
||||
and is temporary until we support real code mods. */
|
||||
for (size_t i = 0; i < codes.size(); i++)
|
||||
{
|
||||
if (def->GetName() == codes[i])
|
||||
{
|
||||
LOGF_IMPL(Utility, "Mod Loader", "Loading code: \"{}\"", codes[i]);
|
||||
*(bool*)def->GetValue() = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr uint32_t LZX_SIGNATURE = 0xFF512EE;
|
||||
@@ -337,6 +378,9 @@ PPC_FUNC(sub_82E0D3E8)
|
||||
std::ifstream stream(filePath, std::ios::binary);
|
||||
if (stream.good())
|
||||
{
|
||||
if (ModLoader::s_isLogTypeConsole)
|
||||
LOGF_IMPL(Utility, "Mod Loader", "Loading file: \"{}\"", reinterpret_cast<const char*>(filePath.u8string().c_str()));
|
||||
|
||||
be<uint32_t> signature{};
|
||||
stream.read(reinterpret_cast<char*>(&signature), sizeof(signature));
|
||||
|
||||
@@ -572,6 +616,9 @@ PPC_FUNC(sub_82E0B500)
|
||||
std::ifstream stream(arFilePath, std::ios::binary);
|
||||
if (stream.good())
|
||||
{
|
||||
if (ModLoader::s_isLogTypeConsole)
|
||||
LOGF_IMPL(Utility, "Mod Loader", "Loading file: \"{}\"", reinterpret_cast<const char*>(arFilePath.u8string().c_str()));
|
||||
|
||||
stream.seekg(0, std::ios::end);
|
||||
size_t arFileSize = stream.tellg();
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
struct ModLoader
|
||||
{
|
||||
static inline bool s_isLogTypeConsole;
|
||||
|
||||
static inline std::filesystem::path s_saveFilePath;
|
||||
|
||||
static std::filesystem::path ResolvePath(std::string_view path);
|
||||
|
||||
@@ -24,6 +24,9 @@ void CHudPauseAddOptionsItemMidAsmHook(PPCRegister& pThis)
|
||||
|
||||
bool InjectMenuBehaviour(uint32_t pThis, uint32_t count)
|
||||
{
|
||||
if (App::s_isLoading)
|
||||
return true;
|
||||
|
||||
auto pHudPause = (SWA::CHudPause*)g_memory.Translate(pThis);
|
||||
auto cursorIndex = *(be<uint32_t>*)g_memory.Translate(4 * (*(be<uint32_t>*)g_memory.Translate(pThis + 0x19C) + 0x68) + pThis);
|
||||
|
||||
@@ -116,6 +119,12 @@ bool CHudPauseMiscInjectOptionsMidAsmHook(PPCRegister& pThis)
|
||||
PPC_FUNC_IMPL(__imp__sub_824B0930);
|
||||
PPC_FUNC(sub_824B0930)
|
||||
{
|
||||
if (App::s_isLoading)
|
||||
{
|
||||
__imp__sub_824B0930(ctx, base);
|
||||
return;
|
||||
}
|
||||
|
||||
auto pHudPause = (SWA::CHudPause*)g_memory.Translate(ctx.r3.u32);
|
||||
auto pInputState = SWA::CInputState::GetInstance();
|
||||
|
||||
@@ -163,7 +172,7 @@ PPC_FUNC(sub_824B0930)
|
||||
|
||||
if (*SWA::SGlobals::ms_IsRenderHud && pHudPause->m_IsShown && !pHudPause->m_Submenu && pHudPause->m_Transition == SWA::eTransitionType_Undefined)
|
||||
{
|
||||
ButtonGuide::Open(Button(Localise("Achievements_Name"), EButtonIcon::Back, EButtonAlignment::Left, EFontQuality::Low));
|
||||
ButtonGuide::Open(Button("Achievements_Name", EButtonIcon::Back, EButtonAlignment::Left, EFontQuality::Low));
|
||||
g_isClosed = false;
|
||||
}
|
||||
else if (!g_isClosed)
|
||||
|
||||
@@ -148,9 +148,10 @@ void PressStartSaveLoadThreadMidAsmHook()
|
||||
PPC_FUNC_IMPL(__imp__sub_82587E50);
|
||||
PPC_FUNC(sub_82587E50)
|
||||
{
|
||||
auto isAutoSaveWarningShown = *(bool*)g_memory.Translate(0x83367BC1);
|
||||
auto pTitleStateIntro = (SWA::CTitleStateIntro*)g_memory.Translate(ctx.r3.u32);
|
||||
auto pTime = (be<float>*)((uint8_t*)pTitleStateIntro->GetContextBase() + 0x10C);
|
||||
|
||||
if (isAutoSaveWarningShown)
|
||||
if (*SWA::SGlobals::ms_IsAutoSaveWarningShown)
|
||||
{
|
||||
__imp__sub_82587E50(ctx, base);
|
||||
}
|
||||
@@ -158,7 +159,7 @@ PPC_FUNC(sub_82587E50)
|
||||
{
|
||||
if (auto pInputState = SWA::CInputState::GetInstance())
|
||||
{
|
||||
if (pInputState->GetPadState().IsTapped(SWA::eKeyState_B))
|
||||
if (pInputState->GetPadState().IsTapped(SWA::eKeyState_B) && *pTime > 0.5f)
|
||||
g_quitMessageOpen = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,14 +52,14 @@ static bool ProcessInstallMessage()
|
||||
PPC_FUNC_IMPL(__imp__sub_825882B8);
|
||||
PPC_FUNC(sub_825882B8)
|
||||
{
|
||||
auto pTitleState = (SWA::CTitleStateBase*)g_memory.Translate(ctx.r3.u32);
|
||||
auto pTitleStateMenu = (SWA::CTitleStateMenu*)g_memory.Translate(ctx.r3.u32);
|
||||
auto pGameDocument = SWA::CGameDocument::GetInstance();
|
||||
|
||||
auto pInputState = SWA::CInputState::GetInstance();
|
||||
auto& pPadState = pInputState->GetPadState();
|
||||
auto isAccepted = pPadState.IsTapped(SWA::eKeyState_A) || pPadState.IsTapped(SWA::eKeyState_Start);
|
||||
|
||||
auto pContext = pTitleState->GetContextBase<SWA::CTitleStateBase::CTitleStateContext>();
|
||||
auto pContext = pTitleStateMenu->GetContextBase<SWA::CTitleStateMenu::CTitleStateMenuContext>();
|
||||
auto isNewGameIndex = pContext->m_pTitleMenu->m_CursorIndex == 0;
|
||||
auto isOptionsIndex = pContext->m_pTitleMenu->m_CursorIndex == 2;
|
||||
auto isInstallIndex = pContext->m_pTitleMenu->m_CursorIndex == 3;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "aspect_ratio_patches.h"
|
||||
#include "camera_patches.h"
|
||||
#include "inspire_patches.h"
|
||||
|
||||
// These are here for now to not recompile basically all of the project.
|
||||
namespace Chao::CSD
|
||||
@@ -344,6 +345,16 @@ enum
|
||||
|
||||
LOADING_BLACK_BAR_MIN = 1 << 17,
|
||||
LOADING_BLACK_BAR_MAX = 1 << 18,
|
||||
|
||||
UNSTRETCH_HORIZONTAL = 1 << 19,
|
||||
|
||||
CORNER_EXTRACT = 1 << 20,
|
||||
|
||||
SKIP_INSPIRE = 1 << 21,
|
||||
|
||||
CONTROL_TUTORIAL = 1 << 22,
|
||||
|
||||
LOADING_ARROW = 1 << 23,
|
||||
};
|
||||
|
||||
struct CsdModifier
|
||||
@@ -360,10 +371,14 @@ static const xxHashMap<CsdModifier> g_modifiers =
|
||||
{ HashStr("ui_balloon/window/footer"), { ALIGN_BOTTOM } },
|
||||
|
||||
// ui_boss_gauge
|
||||
{ HashStr("ui_boss_gauge/gauge_bg"), { ALIGN_TOP_RIGHT | SCALE } },
|
||||
{ HashStr("ui_boss_gauge/gauge_2"), { ALIGN_TOP_RIGHT | SCALE } },
|
||||
{ HashStr("ui_boss_gauge/gauge_1"), { ALIGN_TOP_RIGHT | SCALE } },
|
||||
{ HashStr("ui_boss_gauge/gauge_breakpoint"), { ALIGN_TOP_RIGHT | SCALE } },
|
||||
{ HashStr("ui_boss_gauge/gauge_bg"), { ALIGN_TOP_RIGHT | SCALE | SKIP_INSPIRE} },
|
||||
{ HashStr("ui_boss_gauge/gauge_2"), { ALIGN_TOP_RIGHT | SCALE | SKIP_INSPIRE} },
|
||||
{ HashStr("ui_boss_gauge/gauge_1"), { ALIGN_TOP_RIGHT | SCALE | SKIP_INSPIRE} },
|
||||
{ HashStr("ui_boss_gauge/gauge_breakpoint"), { ALIGN_TOP_RIGHT | SCALE | SKIP_INSPIRE} },
|
||||
|
||||
// ui_boss_name
|
||||
{ HashStr("ui_boss_name/name_so/bg"), { UNSTRETCH_HORIZONTAL } },
|
||||
{ HashStr("ui_boss_name/name_so/pale"), { UNSTRETCH_HORIZONTAL } },
|
||||
|
||||
// ui_exstage
|
||||
{ HashStr("ui_exstage/shield/L_gauge"), { ALIGN_BOTTOM_LEFT | SCALE } },
|
||||
@@ -372,10 +387,10 @@ static const xxHashMap<CsdModifier> g_modifiers =
|
||||
{ HashStr("ui_exstage/energy/R_gauge"), { ALIGN_BOTTOM_RIGHT | SCALE } },
|
||||
{ HashStr("ui_exstage/energy/R_gauge_effect"), { ALIGN_BOTTOM_RIGHT | SCALE } },
|
||||
{ HashStr("ui_exstage/energy/R_gauge_effect_2"), { ALIGN_BOTTOM_RIGHT | SCALE } },
|
||||
{ HashStr("ui_exstage/hit/hit_counter_bg"), { ALIGN_RIGHT | SCALE } },
|
||||
{ HashStr("ui_exstage/hit/hit_counter_bg"), { ALIGN_RIGHT | SCALE | OFFSET_SCALE_RIGHT, 986.0f } },
|
||||
{ HashStr("ui_exstage/hit/hit_counter_bg/C"), { ALIGN_RIGHT | SCALE | EXTEND_RIGHT } },
|
||||
{ HashStr("ui_exstage/hit/hit_counter_bg/C/L"), { ALIGN_RIGHT | SCALE } },
|
||||
{ HashStr("ui_exstage/hit/hit_counter_bg/C/R"), { SKIP } },
|
||||
{ HashStr("ui_exstage/hit/hit_counter_bg/C/L"), { SKIP } }, // L/R are mixed up
|
||||
{ HashStr("ui_exstage/hit/hit_counter_bg/C/R"), { ALIGN_RIGHT | SCALE | STORE_LEFT_CORNER } },
|
||||
{ HashStr("ui_exstage/hit/hit_counter_num"), { ALIGN_RIGHT | SCALE } },
|
||||
|
||||
// ui_gate
|
||||
@@ -392,15 +407,19 @@ static const xxHashMap<CsdModifier> g_modifiers =
|
||||
|
||||
// ui_itemresult
|
||||
{ HashStr("ui_itemresult/footer/result_footer"), { ALIGN_BOTTOM } },
|
||||
{ HashStr("ui_itemresult/main/iresult_title"), { ALIGN_TOP } },
|
||||
{ HashStr("ui_itemresult/main/iresult_title"), { ALIGN_TOP | OFFSET_SCALE_LEFT, 688.0f } },
|
||||
{ HashStr("ui_itemresult/main/iresult_title/title_bg/center"), { ALIGN_TOP | EXTEND_LEFT } },
|
||||
{ HashStr("ui_itemresult/main/iresult_title/title_bg/center/h_light"), { ALIGN_TOP | EXTEND_LEFT } },
|
||||
{ HashStr("ui_itemresult/main/iresult_title/title_bg/right"), { ALIGN_TOP | STORE_RIGHT_CORNER } },
|
||||
{ HashStr("ui_itemresult/main/iresult_title/title_brilliance1"), { ALIGN_TOP | STORE_RIGHT_CORNER | OFFSET_SCALE_LEFT, 632.25775f, 1 } },
|
||||
{ HashStr("ui_itemresult/main/iresult_title/title_brilliance2"), { ALIGN_TOP | STORE_RIGHT_CORNER | OFFSET_SCALE_LEFT, 830.0f, 2 } },
|
||||
{ HashStr("ui_itemresult/main/iresult_title/title_brilliance3"), { ALIGN_TOP | STORE_RIGHT_CORNER | OFFSET_SCALE_LEFT, 640.0f, 3 } },
|
||||
|
||||
// ui_loading
|
||||
{ HashStr("ui_loading/bg_1"), { STRETCH } },
|
||||
{ HashStr("ui_loading/bg_1/arrow"), { STRETCH | LOADING_ARROW } },
|
||||
{ HashStr("ui_loading/bg_2"), { STRETCH } },
|
||||
{ HashStr("ui_loading/bg_2/arrow"), { STRETCH | LOADING_ARROW } },
|
||||
{ HashStr("ui_loading/n_2_d/bg/sky"), { STRETCH } },
|
||||
{ HashStr("ui_loading/n_2_d/bg/under"), { STRETCH } },
|
||||
{ HashStr("ui_loading/n_2_d/letterbox/letterbox_under"), { STRETCH } },
|
||||
@@ -575,9 +594,11 @@ static const xxHashMap<CsdModifier> g_modifiers =
|
||||
{ HashStr("ui_playscreen_ev_hit/chance_attack"), { ALIGN_RIGHT | SCALE } },
|
||||
|
||||
// ui_playscreen_su
|
||||
{ HashStr("ui_playscreen_su/su_sonic_gauge"), { ALIGN_BOTTOM_LEFT | SCALE } },
|
||||
{ HashStr("ui_playscreen_su/gaia_gauge"), { ALIGN_BOTTOM_LEFT | SCALE } },
|
||||
{ HashStr("ui_playscreen_su/footer"), { ALIGN_BOTTOM_RIGHT | SCALE } },
|
||||
{ HashStr("ui_playscreen_su/su_sonic_gauge"), { ALIGN_BOTTOM_LEFT | SCALE | OFFSET_SCALE_LEFT, 632.0f } },
|
||||
{ HashStr("ui_playscreen_su/su_sonic_gauge/position/C/R"), { ALIGN_BOTTOM_LEFT | SCALE | STORE_RIGHT_CORNER } },
|
||||
{ HashStr("ui_playscreen_su/gaia_gauge"), { ALIGN_BOTTOM_LEFT | SCALE | OFFSET_SCALE_LEFT, 632.0f } },
|
||||
{ HashStr("ui_playscreen_su/gaia_gauge/position/C/R"), { ALIGN_BOTTOM_LEFT | SCALE | STORE_RIGHT_CORNER } },
|
||||
{ HashStr("ui_playscreen_su/footer"), { ALIGN_BOTTOM_RIGHT | SCALE | CONTROL_TUTORIAL } },
|
||||
|
||||
// ui_prov_playscreen
|
||||
{ HashStr("ui_prov_playscreen/so_speed_gauge"), { ALIGN_BOTTOM_LEFT | SCALE | TORNADO_DEFENSE } },
|
||||
@@ -601,37 +622,43 @@ static const xxHashMap<CsdModifier> g_modifiers =
|
||||
{ HashStr("ui_result/main/result_title/title_bg/center"), { ALIGN_TOP | EXTEND_LEFT } },
|
||||
{ HashStr("ui_result/main/result_title/title_bg/center/h_light"), { ALIGN_TOP | EXTEND_LEFT} },
|
||||
{ HashStr("ui_result/main/result_title/title_bg/right"), { ALIGN_TOP | STORE_RIGHT_CORNER } },
|
||||
{ HashStr("ui_result/main/result_num_1"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_1"), { CORNER_EXTRACT } },
|
||||
{ HashStr("ui_result/main/result_num_1/num_bg"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_1/num_bg/position_1/center_1"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_1/num_bg/position_1/center_1/h_light"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_1/num_bg/position_1/center_1/left"), { STORE_LEFT_CORNER } },
|
||||
{ HashStr("ui_result/main/result_num_1/num_bg/position_1/center_1/right"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_1/num_bg/position_1/center_1/right/h_light"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_2"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_2"), { CORNER_EXTRACT } },
|
||||
{ HashStr("ui_result/main/result_num_2/num_bg"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_2/num_bg/position_2/center_1"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_2/num_bg/position_2/center_1/h_light"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_2/num_bg/position_2/center_1/left"), { STORE_LEFT_CORNER } },
|
||||
{ HashStr("ui_result/main/result_num_2/num_bg/position_2/center_1/right"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_2/num_bg/position_2/center_1/right/h_light"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_3"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_3"), { CORNER_EXTRACT } },
|
||||
{ HashStr("ui_result/main/result_num_3/num_bg"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_3/num_bg/position_3/center_1"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_3/num_bg/position_3/center_1/h_light"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_3/num_bg/position_3/center_1/left"), { STORE_LEFT_CORNER } },
|
||||
{ HashStr("ui_result/main/result_num_3/num_bg/position_3/center_1/right"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_3/num_bg/position_3/center_1/right/h_light"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_4"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_4"), { CORNER_EXTRACT } },
|
||||
{ HashStr("ui_result/main/result_num_4/num_bg"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_4/num_bg/position_4/center_1"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_4/num_bg/position_4/center_1/h_light"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_4/num_bg/position_4/center_1/left"), { STORE_LEFT_CORNER } },
|
||||
{ HashStr("ui_result/main/result_num_4/num_bg/position_4/center_1/right"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_4/num_bg/position_4/center_1/right/h_light"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_5"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_5"), { CORNER_EXTRACT } },
|
||||
{ HashStr("ui_result/main/result_num_5/num_bg"), { OFFSET_SCALE_RIGHT, 669.0f } },
|
||||
{ HashStr("ui_result/main/result_num_5/num_bg/position_5/center_1"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_5/num_bg/position_5/center_1/h_light"), { EXTEND_RIGHT } },
|
||||
{ HashStr("ui_result/main/result_num_5/num_bg/position_5/center_1/left"), { STORE_LEFT_CORNER } },
|
||||
{ HashStr("ui_result/main/result_num_5/num_bg/position_5/center_1/right"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_5/num_bg/position_5/center_1/right/h_light"), { SKIP } },
|
||||
{ HashStr("ui_result/main/result_num_6"), { OFFSET_SCALE_LEFT, 1094.0f } },
|
||||
{ HashStr("ui_result/main/result_num_6"), { CORNER_EXTRACT } },
|
||||
{ HashStr("ui_result/main/result_num_6/num_bg"), { OFFSET_SCALE_LEFT, 1094.0f } },
|
||||
{ HashStr("ui_result/main/result_num_6/num_bg/position_6/center"), { EXTEND_LEFT } },
|
||||
{ HashStr("ui_result/main/result_num_6/num_bg/position_6/center/h_light"), { EXTEND_LEFT } },
|
||||
{ HashStr("ui_result/main/result_num_6/num_bg/position_6/center/right"), { STORE_RIGHT_CORNER } },
|
||||
@@ -728,7 +755,7 @@ static const xxHashMap<CsdModifier> g_modifiers =
|
||||
{ HashStr("ui_townscreen/time_effect"), { ALIGN_TOP_RIGHT | SCALE } },
|
||||
{ HashStr("ui_townscreen/info"), { ALIGN_TOP_LEFT | SCALE } },
|
||||
{ HashStr("ui_townscreen/cam"), { ALIGN_TOP_RIGHT | SCALE } },
|
||||
{ HashStr("ui_townscreen/footer"), { ALIGN_BOTTOM } },
|
||||
{ HashStr("ui_townscreen/footer"), { ALIGN_BOTTOM_RIGHT | SCALE } },
|
||||
|
||||
// ui_worldmap
|
||||
{ HashStr("ui_worldmap/contents/choices/cts_choices_bg"), { STRETCH } },
|
||||
@@ -828,6 +855,11 @@ PPC_FUNC(sub_830C6A00)
|
||||
|
||||
if (g_sceneModifier.has_value())
|
||||
{
|
||||
if (!Config::ControlTutorial && (g_sceneModifier->flags & CONTROL_TUTORIAL) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Tornado Defense bugs out when applying gameplay UI scaling.
|
||||
// This seems consistent with base game behavior, because the UI
|
||||
// is normally squashed, which was probably done to work around this.
|
||||
@@ -837,7 +869,7 @@ PPC_FUNC(sub_830C6A00)
|
||||
g_scenePositionY = 0.0f;
|
||||
}
|
||||
|
||||
if ((g_sceneModifier->flags & (OFFSET_SCALE_LEFT | OFFSET_SCALE_RIGHT)) != 0)
|
||||
if (g_aspectRatio > WIDE_ASPECT_RATIO && (g_sceneModifier->flags & (OFFSET_SCALE_LEFT | OFFSET_SCALE_RIGHT | CORNER_EXTRACT)) != 0)
|
||||
{
|
||||
auto r3 = ctx.r3;
|
||||
auto r4 = ctx.r4;
|
||||
@@ -906,6 +938,12 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
|
||||
return;
|
||||
}
|
||||
|
||||
// That goddamn boss gauge doesn't disappear in the cutscene where Dark Gaia and Chip hug each other
|
||||
if ((modifier.flags & SKIP_INSPIRE) != 0 && !InspirePatches::s_sceneName.empty() && *reinterpret_cast<be<float>*>(base + ctx.r4.u32) >= 1280.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_cornerExtract)
|
||||
{
|
||||
if ((modifier.flags & (STORE_LEFT_CORNER | STORE_RIGHT_CORNER)) != 0)
|
||||
@@ -937,6 +975,22 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
|
||||
return reinterpret_cast<be<float>*>(stack + index * stride);
|
||||
};
|
||||
|
||||
// Subtract half a pixel from loading arrows to prevent transparent pixels surrounding them from leaking into the texture filtering.
|
||||
if (Video::s_viewportHeight > 720 && (modifier.flags & LOADING_ARROW) != 0 && stride == 0x14)
|
||||
{
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
{
|
||||
auto texCoord = getPosition(i) + 4;
|
||||
|
||||
constexpr float OFFSET = 0.5f / 720.0f;
|
||||
|
||||
if (i == 0 || i == 2) // Top
|
||||
*texCoord = (*texCoord + OFFSET);
|
||||
else // Bottom
|
||||
*texCoord = (*texCoord - OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
float offsetX = 0.0f;
|
||||
float offsetY = 0.0f;
|
||||
float pivotX = 0.0f;
|
||||
@@ -944,7 +998,9 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
|
||||
float scaleX = 1.0f;
|
||||
float scaleY = 1.0f;
|
||||
|
||||
if (squash || ((modifier.flags & STRETCH_HORIZONTAL) != 0 && g_aspectRatio >= WIDE_ASPECT_RATIO))
|
||||
bool needsStretch = g_aspectRatio >= WIDE_ASPECT_RATIO;
|
||||
|
||||
if (squash || (needsStretch && (modifier.flags & STRETCH_HORIZONTAL) != 0))
|
||||
{
|
||||
scaleX = Video::s_viewportWidth / 1280.0f;
|
||||
}
|
||||
@@ -952,28 +1008,36 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
|
||||
{
|
||||
scaleX = g_aspectRatioScale;
|
||||
|
||||
if ((modifier.flags & ALIGN_RIGHT) != 0)
|
||||
offsetX = g_aspectRatioOffsetX * 2.0f;
|
||||
else if ((modifier.flags & ALIGN_LEFT) == 0)
|
||||
offsetX = g_aspectRatioOffsetX;
|
||||
|
||||
if ((modifier.flags & SCALE) != 0)
|
||||
if (needsStretch && (modifier.flags & UNSTRETCH_HORIZONTAL) != 0)
|
||||
{
|
||||
scaleX *= g_aspectRatioGameplayScale;
|
||||
pivotX = g_scenePositionX;
|
||||
|
||||
if ((modifier.flags & ALIGN_RIGHT) != 0)
|
||||
offsetX += 1280.0f * (1.0f - g_aspectRatioGameplayScale) * g_aspectRatioScale;
|
||||
else if ((modifier.flags & ALIGN_LEFT) == 0)
|
||||
offsetX += 640.0f * (1.0f - g_aspectRatioGameplayScale) * g_aspectRatioScale;
|
||||
|
||||
offsetX += pivotX * g_aspectRatioScale;
|
||||
pivotX = *getPosition(0);
|
||||
offsetX = pivotX * Video::s_viewportWidth / 1280.0f;
|
||||
}
|
||||
|
||||
if ((modifier.flags & WORLD_MAP) != 0)
|
||||
else
|
||||
{
|
||||
if ((modifier.flags & ALIGN_LEFT) != 0)
|
||||
offsetX += (1.0f - g_aspectRatioNarrowScale) * g_aspectRatioScale * -20.0f;
|
||||
if ((modifier.flags & ALIGN_RIGHT) != 0)
|
||||
offsetX = g_aspectRatioOffsetX * 2.0f;
|
||||
else if ((modifier.flags & ALIGN_LEFT) == 0)
|
||||
offsetX = g_aspectRatioOffsetX;
|
||||
|
||||
if ((modifier.flags & SCALE) != 0)
|
||||
{
|
||||
scaleX *= g_aspectRatioGameplayScale;
|
||||
pivotX = g_scenePositionX;
|
||||
|
||||
if ((modifier.flags & ALIGN_RIGHT) != 0)
|
||||
offsetX += 1280.0f * (1.0f - g_aspectRatioGameplayScale) * g_aspectRatioScale;
|
||||
else if ((modifier.flags & ALIGN_LEFT) == 0)
|
||||
offsetX += 640.0f * (1.0f - g_aspectRatioGameplayScale) * g_aspectRatioScale;
|
||||
|
||||
offsetX += pivotX * g_aspectRatioScale;
|
||||
}
|
||||
|
||||
if ((modifier.flags & WORLD_MAP) != 0)
|
||||
{
|
||||
if ((modifier.flags & ALIGN_LEFT) != 0)
|
||||
offsetX += (1.0f - g_aspectRatioNarrowScale) * g_aspectRatioScale * -20.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1198,8 +1262,8 @@ PPC_FUNC(sub_830D1EF0)
|
||||
y = g_aspectRatioOffsetY + (y + 0.5f) * g_aspectRatioScale;
|
||||
}
|
||||
|
||||
vertex[i].x = ((round(x) - 0.5f) / Video::s_viewportWidth) * 2.0f - 1.0f;
|
||||
vertex[i].y = ((round(y) - 0.5f) / Video::s_viewportHeight) * -2.0f + 1.0f;
|
||||
vertex[i].x = ((x - 0.5f) / Video::s_viewportWidth) * 2.0f - 1.0f;
|
||||
vertex[i].y = ((y - 0.5f) / Video::s_viewportHeight) * -2.0f + 1.0f;
|
||||
}
|
||||
|
||||
bool letterboxTop = PPC_LOAD_U8(r3.u32 + PRIMITIVE_2D_PADDING_OFFSET + 0x1);
|
||||
@@ -1553,3 +1617,38 @@ PPC_FUNC(sub_82449088)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The shadow offseting is buggy for FCO text just like Werehog button guide,
|
||||
// making them appear thicker than they actually are.
|
||||
PPC_FUNC_IMPL(__imp__sub_82E54950);
|
||||
PPC_FUNC(sub_82E54950)
|
||||
{
|
||||
if (Config::AspectRatio == EAspectRatio::OriginalNarrow)
|
||||
{
|
||||
// Luckily, they have shadow offset scale values that are only used in this function.
|
||||
uint32_t x = PPC_LOAD_U32(0x8332B7B8);
|
||||
uint32_t y = PPC_LOAD_U32(0x8332B7BC);
|
||||
|
||||
PPCRegister scaled;
|
||||
|
||||
// X
|
||||
scaled.u32 = x;
|
||||
scaled.f32 *= 1.5f;
|
||||
PPC_STORE_U32(0x8332B7B8, scaled.u32);
|
||||
|
||||
// Y
|
||||
scaled.u32 = y;
|
||||
scaled.f32 *= 1.5f;
|
||||
PPC_STORE_U32(0x8332B7BC, scaled.u32);
|
||||
|
||||
__imp__sub_82E54950(ctx, base);
|
||||
|
||||
// Restore old values.
|
||||
PPC_STORE_U32(0x8332B7B8, x);
|
||||
PPC_STORE_U32(0x8332B7BC, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
__imp__sub_82E54950(ctx, base);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,17 @@ void HighFrameRateDeltaTimeFixMidAsmHook(PPCRegister& f1)
|
||||
f1.f64 = threshold;
|
||||
}
|
||||
|
||||
// This hook expects the vector register to store delta time at the first index.
|
||||
void HighFrameRateDeltaTimeFixVectorMidAsmHook(PPCVRegister& v62)
|
||||
{
|
||||
// Having 60 FPS threshold ensures we still retain
|
||||
// the original game behavior when locked to 30/60 FPS.
|
||||
constexpr double threshold = 1.0 / 60.0;
|
||||
|
||||
if (v62.f32[3] < threshold)
|
||||
v62.f32[3] = threshold;
|
||||
}
|
||||
|
||||
void CameraDeltaTimeFixMidAsmHook(PPCRegister& dest, PPCRegister& src)
|
||||
{
|
||||
dest.f64 = src.f64 / 30.0;
|
||||
@@ -159,3 +170,28 @@ PPC_FUNC(sub_82B00D00)
|
||||
|
||||
*pElapsedTime = std::max(*pElapsedTime, 0.0f);
|
||||
}
|
||||
|
||||
// Fix for Egg Dragoon's drill missile attack rotating 90 degrees at HFR.
|
||||
void BossEggDragoonDrillMissileCMissileSetRotationMidAsmHook(PPCRegister& r4)
|
||||
{
|
||||
auto pRotation = (Hedgehog::Math::CQuaternion*)g_memory.Translate(r4.u32);
|
||||
auto magnitude = std::sqrt(pRotation->X * pRotation->X + pRotation->Y * pRotation->Y + pRotation->Z * pRotation->Z + pRotation->W * pRotation->W);
|
||||
|
||||
if (magnitude < 0.0f)
|
||||
return;
|
||||
|
||||
auto magnitudeNrm = 1.0f / magnitude;
|
||||
|
||||
pRotation->X = pRotation->X * magnitudeNrm;
|
||||
pRotation->Y = pRotation->Y * magnitudeNrm;
|
||||
pRotation->Z = pRotation->Z * magnitudeNrm;
|
||||
pRotation->W = pRotation->W * magnitudeNrm;
|
||||
}
|
||||
|
||||
bool SparkleLocusMidAsmHook()
|
||||
{
|
||||
// There is an epsilon check in sparkle locus particle code that seems to never pass at high frame rates, which causes vertex corruption.
|
||||
// Checking for equality doesn't fix it either, so we can fix it by forcing it to always execute instead.
|
||||
// This has the side effect of the locus particle eventually snapping to the rest position during pause, but it's better than vertices exploding.
|
||||
return App::s_deltaTime < (1.0 / 60.0);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ static class FrontendListener : public SDLEventListener
|
||||
public:
|
||||
bool OnSDLEvent(SDL_Event* event) override
|
||||
{
|
||||
if (!Config::HUDToggleHotkey || OptionsMenu::s_isVisible)
|
||||
if (!Config::HUDToggleKey || OptionsMenu::s_isVisible)
|
||||
return false;
|
||||
|
||||
switch (event->type)
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
#include <app.h>
|
||||
#include <sdl_events.h>
|
||||
|
||||
std::string InspirePatches::s_sceneName;
|
||||
|
||||
static SWA::Inspire::CScene* g_pScene;
|
||||
static std::string g_sceneName;
|
||||
static bool g_isFirstFrameChecked;
|
||||
static uint32_t g_eventDispatchCount;
|
||||
|
||||
@@ -31,6 +32,11 @@ static std::unordered_map<std::string_view, std::pair<float, float>> g_evilSonic
|
||||
{ "evrt_m8_04", { 0, 2314 } } // Dark Gaia Appears
|
||||
};
|
||||
|
||||
// Sonic's mouth EXPLODES for a single frame in Temple Entrance cutscene.
|
||||
// Looks very nasty. Let's hide morph models inbetween certain frames to solve it.
|
||||
static bool g_loadedMouthExplosionAnimation;
|
||||
static bool g_hideMorphModels;
|
||||
|
||||
// SWA::Inspire::CScene
|
||||
PPC_FUNC_IMPL(__imp__sub_82B98D80);
|
||||
PPC_FUNC(sub_82B98D80)
|
||||
@@ -49,9 +55,12 @@ PPC_FUNC(sub_82B98D30)
|
||||
__imp__sub_82B98D30(ctx, base);
|
||||
|
||||
g_pScene = nullptr;
|
||||
g_sceneName.clear();
|
||||
InspirePatches::s_sceneName.clear();
|
||||
|
||||
SDL_User_EvilSonic(App::s_isWerehog);
|
||||
|
||||
g_loadedMouthExplosionAnimation = false;
|
||||
g_hideMorphModels = false;
|
||||
}
|
||||
|
||||
PPC_FUNC_IMPL(__imp__sub_82B9BA98);
|
||||
@@ -59,11 +68,31 @@ PPC_FUNC(sub_82B9BA98)
|
||||
{
|
||||
auto sceneName = (Hedgehog::Base::CSharedString*)g_memory.Translate(ctx.r5.u32);
|
||||
|
||||
g_sceneName = sceneName->c_str();
|
||||
InspirePatches::s_sceneName = sceneName->c_str();
|
||||
|
||||
__imp__sub_82B9BA98(ctx, base);
|
||||
}
|
||||
|
||||
void AnimationDataMakeMidAsmHook(PPCRegister& r31, PPCRegister& r29, PPCRegister& r28)
|
||||
{
|
||||
uint8_t* base = g_memory.base;
|
||||
|
||||
if (r28.u32 == 0x222E0 &&
|
||||
strcmp(reinterpret_cast<const char*>(base + PPC_LOAD_U32(r31.u32)), "t0_04_SN") == 0 &&
|
||||
XXH3_64bits(base + r29.u32, r28.u32) == 0xEC634F0F379F478A)
|
||||
{
|
||||
g_loadedMouthExplosionAnimation = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Hedgehog::Mirage::CSingleMorphElement::Render
|
||||
PPC_FUNC_IMPL(__imp__sub_82E32048);
|
||||
PPC_FUNC(sub_82E32048)
|
||||
{
|
||||
if (!g_hideMorphModels)
|
||||
__imp__sub_82E32048(ctx, base);
|
||||
}
|
||||
|
||||
void InspirePatches::DrawDebug()
|
||||
{
|
||||
if (!g_pScene)
|
||||
@@ -72,7 +101,7 @@ void InspirePatches::DrawDebug()
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("Name: %s", g_sceneName.c_str());
|
||||
ImGui::Text("Name: %s", InspirePatches::s_sceneName.c_str());
|
||||
ImGui::Text("Frame: %f", g_pScene->m_pData->Frame.get());
|
||||
ImGui::Text("Cut: %d", g_pScene->m_pData->Cut.get());
|
||||
|
||||
@@ -97,17 +126,20 @@ void InspirePatches::DrawDebug()
|
||||
|
||||
void InspirePatches::Update()
|
||||
{
|
||||
if (!g_pScene || !g_sceneName.size())
|
||||
if (!g_pScene || !InspirePatches::s_sceneName.size())
|
||||
return;
|
||||
|
||||
if (!g_isFirstFrameChecked && std::find(g_alwaysEvilSonic.begin(), g_alwaysEvilSonic.end(), g_sceneName) != g_alwaysEvilSonic.end())
|
||||
g_hideMorphModels = g_loadedMouthExplosionAnimation && g_pScene->m_pData->Frame >= 185.0f &&
|
||||
g_pScene->m_pData->Frame < 195.0f && InspirePatches::s_sceneName == "evrt_t0_04";
|
||||
|
||||
if (!g_isFirstFrameChecked && std::find(g_alwaysEvilSonic.begin(), g_alwaysEvilSonic.end(), InspirePatches::s_sceneName) != g_alwaysEvilSonic.end())
|
||||
{
|
||||
SDL_User_EvilSonic(true);
|
||||
g_isFirstFrameChecked = true;
|
||||
return;
|
||||
}
|
||||
|
||||
auto findResult = g_evilSonicTimings.find(g_sceneName);
|
||||
auto findResult = g_evilSonicTimings.find(InspirePatches::s_sceneName);
|
||||
|
||||
if (findResult != g_evilSonicTimings.end())
|
||||
{
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
class InspirePatches
|
||||
{
|
||||
public:
|
||||
static std::string s_sceneName;
|
||||
|
||||
static void DrawDebug();
|
||||
static void Update();
|
||||
};
|
||||
|
||||
@@ -13,6 +13,17 @@ bool DisableHintsMidAsmHook()
|
||||
return !Config::Hints;
|
||||
}
|
||||
|
||||
// Disable Perfect Dark Gaia hints.
|
||||
PPC_FUNC_IMPL(__imp__sub_82AC36E0);
|
||||
PPC_FUNC(sub_82AC36E0)
|
||||
{
|
||||
auto pPerfectDarkGaiaChipHintName = (xpointer<char>*)g_memory.Translate(0x8338EF10);
|
||||
|
||||
strcpy(pPerfectDarkGaiaChipHintName->get(), Config::Hints ? "V_CHP_067\0" : "end\0");
|
||||
|
||||
__imp__sub_82AC36E0(ctx, base);
|
||||
}
|
||||
|
||||
bool DisableControlTutorialMidAsmHook()
|
||||
{
|
||||
return !Config::ControlTutorial;
|
||||
@@ -32,13 +43,6 @@ bool DisableDLCIconMidAsmHook()
|
||||
return Config::DisableDLCIcon;
|
||||
}
|
||||
|
||||
void ToggleSubtitlesMidAsmHook(PPCRegister& r27)
|
||||
{
|
||||
auto pApplicationDocument = (SWA::CApplicationDocument*)g_memory.Translate(r27.u32);
|
||||
|
||||
pApplicationDocument->m_InspireSubtitles = Config::Subtitles;
|
||||
}
|
||||
|
||||
void WerehogBattleMusicMidAsmHook(PPCRegister& r11)
|
||||
{
|
||||
if (Config::BattleTheme)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include <api/SWA.h>
|
||||
#include <user/config.h>
|
||||
#include <SWA/CharacterUtility/CharacterProxy.h>
|
||||
#include <hid/hid.h>
|
||||
#include <app.h>
|
||||
|
||||
// CObjFlame::CObjFlame
|
||||
// SWA::CObjFlame::CObjFlame
|
||||
// A field is not zero initialized,
|
||||
// causing collisions to constantly get created
|
||||
// and slow down the game.
|
||||
@@ -28,7 +29,7 @@ void ObjBigBarrelAllocMidAsmHook(PPCRegister& r3)
|
||||
r3.u32 += sizeof(ObjBigBarrelEx);
|
||||
}
|
||||
|
||||
// CObjBigBarrel::CObjBigBarrel
|
||||
// SWA::CObjBigBarrel::CObjBigBarrel
|
||||
PPC_FUNC_IMPL(__imp__sub_8271AC08);
|
||||
PPC_FUNC(sub_8271AC08)
|
||||
{
|
||||
|
||||
@@ -97,7 +97,7 @@ void PostUnleashMidAsmHook(PPCRegister& r30)
|
||||
|
||||
void SetXButtonHomingMidAsmHook(PPCRegister& r30)
|
||||
{
|
||||
r30.u32 = Config::HomingAttackOnBoost;
|
||||
r30.u32 = !Config::HomingAttackOnJump;
|
||||
}
|
||||
|
||||
// SWA::Player::CEvilSonicContext
|
||||
|
||||
@@ -15,25 +15,31 @@ PPC_FUNC(sub_824DCF38)
|
||||
|
||||
App::s_isLoading = true;
|
||||
|
||||
if (Config::TimeOfDayTransition == ETimeOfDayTransition::PlayStation)
|
||||
if (ctx.r4.u32 == SWA::eLoadingDisplayType_WerehogMovie)
|
||||
{
|
||||
if (ctx.r4.u32 == SWA::eLoadingDisplayType_WerehogMovie)
|
||||
if (Config::TimeOfDayTransition == ETimeOfDayTransition::PlayStation)
|
||||
{
|
||||
ctx.r4.u32 = SWA::eLoadingDisplayType_ChangeTimeOfDay;
|
||||
pLoading->m_IsNightToDay = App::s_isWerehog;
|
||||
}
|
||||
|
||||
if (Config::UseArrowsForTimeOfDayTransition)
|
||||
ctx.r4.u32 = SWA::eLoadingDisplayType_Arrows;
|
||||
}
|
||||
|
||||
if (auto pGameDocument = SWA::CGameDocument::GetInstance())
|
||||
if (Config::FixEggmanlandUsingEventGalleryTransition)
|
||||
{
|
||||
auto stageName = pGameDocument->m_pMember->m_StageName.c_str();
|
||||
|
||||
if (stageName && strlen(stageName))
|
||||
if (auto pGameDocument = SWA::CGameDocument::GetInstance())
|
||||
{
|
||||
/* Fix restarting Eggmanland as the Werehog
|
||||
erroneously using the Event Gallery transition. */
|
||||
if (ctx.r4.u32 == SWA::eLoadingDisplayType_EventGallery && !strcmp(stageName, "Act_EggmanLand"))
|
||||
ctx.r4.u32 = SWA::eLoadingDisplayType_NowLoading;
|
||||
auto stageName = pGameDocument->m_pMember->m_StageName.c_str();
|
||||
|
||||
if (stageName && strlen(stageName))
|
||||
{
|
||||
/* Fix restarting Eggmanland as the Werehog
|
||||
erroneously using the Event Gallery transition. */
|
||||
if (ctx.r4.u32 == SWA::eLoadingDisplayType_EventGallery && !strcmp(stageName, "Act_EggmanLand"))
|
||||
ctx.r4.u32 = SWA::eLoadingDisplayType_NowLoading;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,8 +76,12 @@ PPC_FUNC(sub_830D25D8)
|
||||
auto device = reinterpret_cast<GuestDevice*>(base + PPC_LOAD_U32(ctx.r4.u32));
|
||||
|
||||
// Set first sampler to use linear filtering.
|
||||
device->samplerStates[0].data[3] = (device->samplerStates[0].data[3].get() & ~0x1f80000) | 0x1280000;
|
||||
device->dirtyFlags[3] = device->dirtyFlags[3].get() | 0x80000000ull;
|
||||
// NOTE: We only check for height here since all 2D primitives get centered.
|
||||
if (Video::s_viewportHeight > 720)
|
||||
{
|
||||
device->samplerStates[0].data[3] = (device->samplerStates[0].data[3].get() & ~0x1f80000) | 0x1280000;
|
||||
device->dirtyFlags[3] = device->dirtyFlags[3].get() | 0x80000000ull;
|
||||
}
|
||||
|
||||
__imp__sub_830D25D8(ctx, base);
|
||||
}
|
||||
@@ -113,3 +117,27 @@ PPC_FUNC(sub_8260BBF8)
|
||||
SetDefaultMaterialParameters(reinterpret_cast<GuestDevice*>(base + PPC_LOAD_U32(PPC_LOAD_U32(ctx.r4.u32))));
|
||||
__imp__sub_8260BBF8(ctx, base);
|
||||
}
|
||||
|
||||
// The pedestal in Gaia Temple is placed on an opaque mesh slot, despite using additive blending.
|
||||
// This somehow works. Except when the delta time is too stable, it flashes black for one frame.
|
||||
// We can fix it by detecting the asset runtime, and swapping the mesh slots to transparent by hand.
|
||||
|
||||
// Hedgehog::Mirage::CModelData::Make
|
||||
PPC_FUNC_IMPL(__imp__sub_82E38650);
|
||||
PPC_FUNC(sub_82E38650)
|
||||
{
|
||||
if (ctx.r5.u32 == 0xBB90 && XXH3_64bits(base + ctx.r4.u32, ctx.r5.u32) == 0xB524C8C3B80C3F54)
|
||||
{
|
||||
// Mesh Count
|
||||
std::swap(
|
||||
*reinterpret_cast<uint32_t*>(base + ctx.r4.u32 + 0x18),
|
||||
*reinterpret_cast<uint32_t*>(base + ctx.r4.u32 + 0x20));
|
||||
|
||||
// Mesh Offset
|
||||
std::swap(
|
||||
*reinterpret_cast<uint32_t*>(base + ctx.r4.u32 + 0x1C),
|
||||
*reinterpret_cast<uint32_t*>(base + ctx.r4.u32 + 0x24));
|
||||
}
|
||||
|
||||
__imp__sub_82E38650(ctx, base);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_MILESTONE="Beta 2"
|
||||
VERSION_MILESTONE="Beta 3"
|
||||
VERSION_MAJOR=1
|
||||
VERSION_MINOR=0
|
||||
VERSION_REVISION=0
|
||||
|
||||
@@ -48,13 +48,11 @@ static std::unique_ptr<GuestTexture> g_upTrophyIcon;
|
||||
static int g_firstVisibleRowIndex;
|
||||
static int g_selectedRowIndex;
|
||||
static double g_rowSelectionTime;
|
||||
static double g_lastTappedTime;
|
||||
static double g_lastIncrementTime;
|
||||
|
||||
static bool g_upWasHeld;
|
||||
static bool g_downWasHeld;
|
||||
static bool g_leftWasHeld;
|
||||
static bool g_rightWasHeld;
|
||||
static bool g_upRSWasHeld;
|
||||
static bool g_downRSWasHeld;
|
||||
|
||||
static void ResetSelection()
|
||||
{
|
||||
@@ -67,7 +65,7 @@ static void ResetSelection()
|
||||
|
||||
static void DrawContainer(ImVec2 min, ImVec2 max, ImU32 gradientTop, ImU32 gradientBottom, float alpha = 1, float cornerRadius = 25)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
DrawPauseContainer(min, max, alpha);
|
||||
|
||||
@@ -76,8 +74,9 @@ static void DrawContainer(ImVec2 min, ImVec2 max, ImU32 gradientTop, ImU32 gradi
|
||||
|
||||
static void DrawHeaderContainer(const char* text)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto fontSize = Scale(24);
|
||||
auto minTextSize = Scale(294.575989);
|
||||
auto textSize = g_fntNewRodinUB->CalcTextSizeA(fontSize, FLT_MAX, 0, text);
|
||||
auto cornerRadius = 23;
|
||||
auto textMarginX = Scale(16) + (Scale(cornerRadius) / 2);
|
||||
@@ -101,13 +100,12 @@ static void DrawHeaderContainer(const char* text)
|
||||
: Lerp(0, 1, colourMotion);
|
||||
|
||||
ImVec2 min = { g_aspectRatioOffsetX + Scale(containerMarginX), g_aspectRatioOffsetY + Scale(136) };
|
||||
ImVec2 max = { min.x + textMarginX * 2 + textSize.x + Scale(5), g_aspectRatioOffsetY + Scale(196) };
|
||||
ImVec2 max = { std::max(min.x + minTextSize, min.x + textMarginX * 2 + textSize.x + Scale(5)), g_aspectRatioOffsetY + Scale(196) };
|
||||
|
||||
DrawPauseHeaderContainer(min, max, alpha);
|
||||
|
||||
SetTextSkew((min.y + max.y) / 2.0f, Scale(3.0f));
|
||||
|
||||
// TODO: Apply bevel.
|
||||
DrawTextWithOutline
|
||||
(
|
||||
g_fntNewRodinUB,
|
||||
@@ -124,7 +122,7 @@ static void DrawHeaderContainer(const char* text)
|
||||
|
||||
static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievement, bool isUnlocked)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
auto clipRectMin = drawList->GetClipRectMin();
|
||||
auto clipRectMax = drawList->GetClipRectMax();
|
||||
@@ -339,7 +337,7 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen
|
||||
|
||||
static void DrawTrophySparkles(ImVec2 min, ImVec2 max, int recordCount, int trophyFrameIndex)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
constexpr auto recordsHalfTotal = ACH_RECORDS / 2;
|
||||
|
||||
@@ -427,7 +425,7 @@ static void DrawTrophySparkles(ImVec2 min, ImVec2 max, int recordCount, int trop
|
||||
|
||||
static void DrawAchievementTotal(ImVec2 min, ImVec2 max)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
// Transparency fade animation.
|
||||
auto alpha = Cubic(0, 1, ComputeMotion(g_appearTime, COUNTER_INTRO_FADE_START, COUNTER_INTRO_FADE_END));
|
||||
@@ -511,7 +509,7 @@ static void DrawAchievementTotal(ImVec2 min, ImVec2 max)
|
||||
|
||||
static void DrawContentContainer()
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
// Expand/retract animation.
|
||||
auto motion = g_isClosing
|
||||
@@ -566,15 +564,12 @@ static void DrawContentContainer()
|
||||
// Draw separators.
|
||||
for (int i = 1; i <= 3; i++)
|
||||
{
|
||||
auto lineMarginLeft = Scale(35);
|
||||
auto lineMarginRight = Scale(55);
|
||||
auto lineMarginY = Scale(2);
|
||||
ImVec2 lineMin = { clipRectMin.x + Scale(35), clipRectMin.y + itemHeight * i + Scale(2) };
|
||||
ImVec2 lineMax = { clipRectMax.x - Scale(55), lineMin.y + Scale(1.3f) };
|
||||
|
||||
ImVec2 lineMin = { clipRectMin.x + lineMarginLeft, clipRectMin.y + itemHeight * i + lineMarginY };
|
||||
ImVec2 lineMax = { clipRectMax.x - lineMarginRight, clipRectMin.y + itemHeight * i + lineMarginY };
|
||||
|
||||
drawList->AddLine(lineMin, lineMax, IM_COL32(163, 163, 163, 255));
|
||||
drawList->AddLine({ lineMin.x, lineMin.y + Scale(1) }, { lineMax.x, lineMax.y + Scale(1) }, IM_COL32(143, 148, 143, 255));
|
||||
SetAdditive(true);
|
||||
drawList->AddRectFilled(lineMin, lineMax, IM_COL32(160, 160, 160, 60));
|
||||
SetAdditive(false);
|
||||
}
|
||||
|
||||
for (auto& tpl : g_achievements)
|
||||
@@ -601,26 +596,41 @@ static void DrawContentContainer()
|
||||
bool downIsHeld = inputState->GetPadState().IsDown(SWA::eKeyState_DpadDown) ||
|
||||
inputState->GetPadState().LeftStickVertical < -0.5f;
|
||||
|
||||
bool leftIsHeld = inputState->GetPadState().IsDown(SWA::eKeyState_DpadLeft) ||
|
||||
inputState->GetPadState().LeftStickHorizontal < -0.5f;
|
||||
|
||||
bool rightIsHeld = inputState->GetPadState().IsDown(SWA::eKeyState_DpadRight) ||
|
||||
inputState->GetPadState().LeftStickHorizontal > 0.5f;
|
||||
|
||||
bool upRSIsHeld = inputState->GetPadState().RightStickVertical > 0.5f;
|
||||
bool downRSIsHeld = inputState->GetPadState().RightStickVertical < -0.5f;
|
||||
|
||||
bool isReachedTop = g_selectedRowIndex == 0;
|
||||
bool isReachedBottom = g_selectedRowIndex == rowCount - 1;
|
||||
|
||||
bool scrollUp = !g_upWasHeld && upIsHeld;
|
||||
bool scrollDown = !g_downWasHeld && downIsHeld;
|
||||
bool scrollPageUp = !g_leftWasHeld && leftIsHeld && !isReachedTop;
|
||||
bool scrollPageDown = !g_rightWasHeld && rightIsHeld && !isReachedBottom;
|
||||
bool jumpToTop = !g_upRSWasHeld && upRSIsHeld && !isReachedTop;
|
||||
bool jumpToBottom = !g_downRSWasHeld && downRSIsHeld && !isReachedBottom;
|
||||
|
||||
int prevSelectedRowIndex = g_selectedRowIndex;
|
||||
auto time = ImGui::GetTime();
|
||||
auto fastScroll = (time - g_lastTappedTime) > 0.6;
|
||||
auto fastScrollSpeed = 1.0 / 3.5;
|
||||
static auto fastScrollSpeedUp = false;
|
||||
|
||||
if (scrollUp || scrollDown)
|
||||
g_lastTappedTime = time;
|
||||
|
||||
if (!upIsHeld && !downIsHeld)
|
||||
fastScrollSpeedUp = false;
|
||||
|
||||
if (fastScrollSpeedUp)
|
||||
fastScrollSpeed /= 2;
|
||||
|
||||
if (fastScroll)
|
||||
{
|
||||
if ((time - g_lastIncrementTime) < fastScrollSpeed)
|
||||
{
|
||||
fastScroll = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_lastIncrementTime = time;
|
||||
|
||||
scrollUp = upIsHeld;
|
||||
scrollDown = downIsHeld;
|
||||
fastScrollSpeedUp = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (scrollUp)
|
||||
{
|
||||
@@ -634,40 +644,15 @@ static void DrawContentContainer()
|
||||
if (g_selectedRowIndex >= rowCount)
|
||||
g_selectedRowIndex = 0;
|
||||
}
|
||||
else if (scrollPageUp)
|
||||
{
|
||||
g_selectedRowIndex -= 3;
|
||||
if (g_selectedRowIndex < 0)
|
||||
g_selectedRowIndex = 0;
|
||||
}
|
||||
else if (scrollPageDown)
|
||||
{
|
||||
g_selectedRowIndex += 3;
|
||||
if (g_selectedRowIndex >= rowCount)
|
||||
g_selectedRowIndex = rowCount - 1;
|
||||
}
|
||||
else if (jumpToTop)
|
||||
{
|
||||
g_selectedRowIndex = 0;
|
||||
}
|
||||
else if (jumpToBottom)
|
||||
{
|
||||
g_selectedRowIndex = rowCount - 1;
|
||||
}
|
||||
|
||||
// lol
|
||||
if (scrollUp || scrollDown || scrollPageUp || scrollPageDown || jumpToTop || jumpToBottom)
|
||||
if (scrollUp || scrollDown)
|
||||
{
|
||||
g_rowSelectionTime = ImGui::GetTime();
|
||||
g_rowSelectionTime = time;
|
||||
Game_PlaySound("sys_actstg_pausecursor");
|
||||
}
|
||||
|
||||
g_upWasHeld = upIsHeld;
|
||||
g_downWasHeld = downIsHeld;
|
||||
g_leftWasHeld = leftIsHeld;
|
||||
g_rightWasHeld = rightIsHeld;
|
||||
g_upRSWasHeld = upRSIsHeld;
|
||||
g_downRSWasHeld = downRSIsHeld;
|
||||
|
||||
int visibleRowCount = int(floor((clipRectMax.y - clipRectMin.y) / itemHeight));
|
||||
|
||||
@@ -778,12 +763,12 @@ void AchievementMenu::Open()
|
||||
return std::get<1>(a) > std::get<1>(b);
|
||||
});
|
||||
|
||||
ButtonGuide::Open(Button(Localise("Common_Back"), EButtonIcon::B));
|
||||
ButtonGuide::Open(Button("Common_Back", EButtonIcon::B));
|
||||
|
||||
ResetSelection();
|
||||
Game_PlaySound("sys_actstg_pausewinopen");
|
||||
|
||||
hid::SetProhibitedButtons(XAMINPUT_GAMEPAD_START);
|
||||
hid::SetProhibitedInputs(XAMINPUT_GAMEPAD_START);
|
||||
}
|
||||
|
||||
void AchievementMenu::Close()
|
||||
@@ -793,7 +778,7 @@ void AchievementMenu::Close()
|
||||
g_appearTime = ImGui::GetTime();
|
||||
g_isClosing = true;
|
||||
|
||||
hid::SetProhibitedButtons(0);
|
||||
hid::SetProhibitedInputs();
|
||||
}
|
||||
|
||||
ButtonGuide::Close();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <app.h>
|
||||
#include <exports.h>
|
||||
#include <decompressor.h>
|
||||
#include <patches/inspire_patches.h>
|
||||
|
||||
constexpr double OVERLAY_CONTAINER_COMMON_MOTION_START = 0;
|
||||
constexpr double OVERLAY_CONTAINER_COMMON_MOTION_END = 11;
|
||||
@@ -30,7 +31,7 @@ static ImFont* g_fntSeurat;
|
||||
|
||||
static bool DrawContainer(ImVec2 min, ImVec2 max, float cornerRadius = 25)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
// Expand/retract animation.
|
||||
auto containerMotion = ComputeMotion(g_appearTime, OVERLAY_CONTAINER_COMMON_MOTION_START, OVERLAY_CONTAINER_COMMON_MOTION_END);
|
||||
@@ -80,15 +81,68 @@ void AchievementOverlay::Init()
|
||||
g_fntSeurat = ImFontAtlasSnapshot::GetFont("FOT-SeuratPro-M.otf");
|
||||
}
|
||||
|
||||
// Dequeue achievements only when we can actually play sounds.
|
||||
// Loading thread does not update this object.
|
||||
static bool g_soundAdministratorUpdated;
|
||||
|
||||
PPC_FUNC_IMPL(__imp__sub_82B43480);
|
||||
PPC_FUNC(sub_82B43480)
|
||||
{
|
||||
g_soundAdministratorUpdated = true;
|
||||
__imp__sub_82B43480(ctx, base);
|
||||
}
|
||||
|
||||
// Dequeue achievements only in the main thread. This is also extra thread safety.
|
||||
static std::thread::id g_mainThreadId = std::this_thread::get_id();
|
||||
|
||||
static bool CanDequeueAchievement()
|
||||
{
|
||||
if (g_soundAdministratorUpdated && std::this_thread::get_id() == g_mainThreadId && !AchievementOverlay::s_queue.empty())
|
||||
{
|
||||
// Check if we can actually play any audio right now. If not, we'll wait until we can.
|
||||
uint32_t audioCenter = *reinterpret_cast<be<uint32_t>*>(g_memory.Translate(0x83362FFC));
|
||||
if (audioCenter != NULL)
|
||||
{
|
||||
uint32_t member = *reinterpret_cast<be<uint32_t>*>(g_memory.Translate(audioCenter + 0x4));
|
||||
uint32_t category = !InspirePatches::s_sceneName.empty() ? 10 : 7; // EVENT category is used during Inspire cutscenes.
|
||||
|
||||
// Check if the volume is non zero.
|
||||
return *reinterpret_cast<uint32_t*>(g_memory.Translate(member + 0x7C + category * 0x10 + 0x8)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AchievementOverlay::Draw()
|
||||
{
|
||||
if (!AchievementOverlay::s_isVisible && CanDequeueAchievement())
|
||||
{
|
||||
s_isVisible = true;
|
||||
g_isClosing = false;
|
||||
g_appearTime = ImGui::GetTime();
|
||||
g_achievement = g_xdbfWrapper.GetAchievement((EXDBFLanguage)Config::Language.Value, s_queue.front());
|
||||
s_queue.pop();
|
||||
|
||||
if (Config::Language == ELanguage::English)
|
||||
g_achievement.Name = xdbf::FixInvalidSequences(g_achievement.Name);
|
||||
|
||||
Game_PlaySound("obj_navi_appear");
|
||||
}
|
||||
|
||||
if (!s_isVisible)
|
||||
{
|
||||
g_soundAdministratorUpdated = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui::GetTime() - g_appearTime >= OVERLAY_DURATION)
|
||||
AchievementOverlay::Close();
|
||||
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
// Close function can use this bool so reset it after.
|
||||
g_soundAdministratorUpdated = false;
|
||||
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
|
||||
auto strAchievementUnlocked = Localise("Achievements_Unlock").c_str();
|
||||
@@ -167,21 +221,7 @@ void AchievementOverlay::Draw()
|
||||
|
||||
void AchievementOverlay::Open(int id)
|
||||
{
|
||||
if (s_isVisible && !g_isClosing)
|
||||
{
|
||||
s_queue.emplace(id);
|
||||
return;
|
||||
}
|
||||
|
||||
s_isVisible = true;
|
||||
g_isClosing = false;
|
||||
g_appearTime = ImGui::GetTime();
|
||||
g_achievement = g_xdbfWrapper.GetAchievement((EXDBFLanguage)Config::Language.Value, id);
|
||||
|
||||
if (Config::Language == ELanguage::English)
|
||||
g_achievement.Name = xdbf::FixInvalidSequences(g_achievement.Name);
|
||||
|
||||
Game_PlaySound("obj_navi_appear");
|
||||
s_queue.push(id);
|
||||
}
|
||||
|
||||
void AchievementOverlay::Close()
|
||||
@@ -192,10 +232,6 @@ void AchievementOverlay::Close()
|
||||
g_isClosing = true;
|
||||
}
|
||||
|
||||
if (s_queue.size())
|
||||
{
|
||||
if (CanDequeueAchievement())
|
||||
s_isVisible = false;
|
||||
AchievementOverlay::Open(s_queue.front());
|
||||
s_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ static void DrawGuide(float* offset, ImVec2 regionMin, ImVec2 regionMax, EButton
|
||||
EButtonAlignment alignment, ImVec2 iconMin, ImVec2 iconMax, EFontQuality fontQuality,
|
||||
ImVec2 textSize, float fontSize, const char* text)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto _icon = icon;
|
||||
auto iconWidth = Scale(g_iconWidths[icon]);
|
||||
auto dualIconMarginX = Scale(25);
|
||||
@@ -235,7 +235,7 @@ void ButtonGuide::Draw()
|
||||
if (!s_isVisible)
|
||||
return;
|
||||
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
|
||||
ImVec2 regionMin = { g_aspectRatioOffsetX + Scale(g_sideMargins), g_aspectRatioOffsetY * 2.0f + Scale(720.0f - 102.0f) };
|
||||
@@ -260,9 +260,10 @@ void ButtonGuide::Draw()
|
||||
if (btn.Visibility && !*btn.Visibility)
|
||||
continue;
|
||||
|
||||
auto str = Localise(btn.Name.c_str()).c_str();
|
||||
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
|
||||
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
|
||||
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, btn.Name.c_str());
|
||||
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str);
|
||||
|
||||
if (i > 0)
|
||||
offsetLeft += textSize.x + iconWidth + textMarginX;
|
||||
@@ -270,7 +271,7 @@ void ButtonGuide::Draw()
|
||||
ImVec2 iconMin = { regionMin.x + offsetLeft - iconWidth - iconMarginX, regionMin.y };
|
||||
ImVec2 iconMax = { regionMin.x + offsetLeft - iconMarginX, regionMin.y + iconHeight };
|
||||
|
||||
DrawGuide(&offsetLeft, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, btn.Name.c_str());
|
||||
DrawGuide(&offsetLeft, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, str);
|
||||
}
|
||||
|
||||
// Draw right aligned icons.
|
||||
@@ -284,9 +285,10 @@ void ButtonGuide::Draw()
|
||||
if (btn.Visibility && !*btn.Visibility)
|
||||
continue;
|
||||
|
||||
auto str = Localise(btn.Name.c_str()).c_str();
|
||||
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
|
||||
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
|
||||
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, btn.Name.c_str());
|
||||
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str);
|
||||
|
||||
if (i < g_buttons.size() - 1)
|
||||
offsetRight += textSize.x + iconWidth + textMarginX;
|
||||
@@ -294,7 +296,7 @@ void ButtonGuide::Draw()
|
||||
ImVec2 iconMin = { regionMax.x - offsetRight - iconWidth - iconMarginX, regionMin.y };
|
||||
ImVec2 iconMax = { regionMax.x - offsetRight - iconMarginX, regionMin.y + iconHeight };
|
||||
|
||||
DrawGuide(&offsetRight, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, btn.Name.c_str());
|
||||
DrawGuide(&offsetRight, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ void Fader::Draw()
|
||||
|
||||
auto colour = IM_COL32(g_colour & 0xFF, (g_colour >> 8) & 0xFF, (g_colour >> 16) & 0xFF, 255 * alpha);
|
||||
|
||||
ImGui::GetForegroundDrawList()->AddRectFilled({ 0, 0 }, ImGui::GetIO().DisplaySize, colour);
|
||||
ImGui::GetBackgroundDrawList()->AddRectFilled({ 0, 0 }, ImGui::GetIO().DisplaySize, colour);
|
||||
}
|
||||
|
||||
static void DoFade(bool isFadeIn, float duration, std::function<void()> endCallback, float endCallbackDelay)
|
||||
|
||||
@@ -173,27 +173,6 @@ void GameWindow::Init(const char* sdlVideoDriver)
|
||||
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||
#endif
|
||||
|
||||
Config::WindowSize.LockCallback = [](ConfigDef<int32_t>* def)
|
||||
{
|
||||
// Try matching the current window size with a known configuration.
|
||||
if (def->Value < 0)
|
||||
def->Value = FindNearestDisplayMode();
|
||||
};
|
||||
|
||||
Config::WindowSize.ApplyCallback = [](ConfigDef<int32_t>* def)
|
||||
{
|
||||
auto displayModes = GetDisplayModes();
|
||||
|
||||
// Use largest supported resolution if overflowed.
|
||||
if (def->Value >= displayModes.size())
|
||||
def->Value = displayModes.size() - 1;
|
||||
|
||||
auto& mode = displayModes[def->Value];
|
||||
auto centre = SDL_WINDOWPOS_CENTERED_DISPLAY(GetDisplay());
|
||||
|
||||
SetDimensions(mode.w, mode.h, centre, centre);
|
||||
};
|
||||
|
||||
s_x = Config::WindowX;
|
||||
s_y = Config::WindowY;
|
||||
s_width = Config::WindowWidth;
|
||||
|
||||
@@ -169,7 +169,7 @@ double ComputeMotion(double duration, double offset, double total)
|
||||
|
||||
void DrawPauseContainer(ImVec2 min, ImVec2 max, float alpha)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
auto commonWidth = Scale(35);
|
||||
auto commonHeight = Scale(35);
|
||||
@@ -200,7 +200,7 @@ void DrawPauseContainer(ImVec2 min, ImVec2 max, float alpha)
|
||||
|
||||
void DrawPauseHeaderContainer(ImVec2 min, ImVec2 max, float alpha)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
auto commonWidth = Scale(35);
|
||||
|
||||
@@ -217,14 +217,14 @@ void DrawPauseHeaderContainer(ImVec2 min, ImVec2 max, float alpha)
|
||||
|
||||
void DrawTextBasic(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 colour, const char* text)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
drawList->AddText(font, fontSize, pos, colour, text, nullptr);
|
||||
}
|
||||
|
||||
void DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2& position, const ImVec2& min, const ImVec2& max, ImU32 color, const char* text, double time, double delay, double speed)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto rectWidth = max.x - min.x;
|
||||
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, text);
|
||||
auto textX = position.x - fmodf(std::max(0.0, ImGui::GetTime() - (time + delay)) * speed, textSize.x + rectWidth);
|
||||
@@ -278,7 +278,7 @@ void DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2& posit
|
||||
|
||||
void DrawTextWithMarqueeShadow(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 colour, const char* text, double time, double delay, double speed, float offset, float radius, ImU32 shadowColour)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto rectWidth = max.x - min.x;
|
||||
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, text);
|
||||
auto textX = pos.x - fmodf(std::max(0.0, ImGui::GetTime() - (time + delay)) * speed, textSize.x + rectWidth);
|
||||
@@ -296,7 +296,7 @@ void DrawTextWithMarqueeShadow(const ImFont* font, float fontSize, const ImVec2&
|
||||
|
||||
void DrawTextWithOutline(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 color, const char* text, float outlineSize, ImU32 outlineColor, uint32_t shaderModifier)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
SetOutline(outlineSize);
|
||||
drawList->AddText(font, fontSize, pos, outlineColor, text);
|
||||
@@ -313,10 +313,16 @@ void DrawTextWithOutline(const ImFont* font, float fontSize, const ImVec2& pos,
|
||||
|
||||
void DrawTextWithShadow(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 colour, const char* text, float offset, float radius, ImU32 shadowColour)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
offset = Scale(offset);
|
||||
|
||||
// Original 4:3 has thicker text shadows.
|
||||
if (Config::AspectRatio == EAspectRatio::OriginalNarrow)
|
||||
{
|
||||
radius *= 1.5f;
|
||||
}
|
||||
|
||||
SetOutline(radius);
|
||||
drawList->AddText(font, fontSize, { pos.x + offset, pos.y + offset }, shadowColour, text);
|
||||
ResetOutline();
|
||||
@@ -732,7 +738,7 @@ ImU32 ColourLerp(ImU32 c0, ImU32 c1, float t)
|
||||
|
||||
void DrawVersionString(const ImFont* font, const ImU32 col)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
auto fontSize = Scale(12);
|
||||
auto textMargin = Scale(2);
|
||||
@@ -743,7 +749,7 @@ void DrawVersionString(const ImFont* font, const ImU32 col)
|
||||
|
||||
void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
static auto breatheStart = ImGui::GetTime();
|
||||
auto alpha = BREATHE_MOTION(1.0f, 0.55f, breatheStart, 0.92f);
|
||||
@@ -787,7 +793,7 @@ void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop)
|
||||
|
||||
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto lightSize = Scale(14);
|
||||
auto lightCol = IM_COL32(255, 255, 255, 255 * alpha);
|
||||
|
||||
|
||||
@@ -464,7 +464,7 @@ static void ResetCursorRects()
|
||||
static void DrawBackground()
|
||||
{
|
||||
auto &res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
drawList->AddRectFilled({ 0.0, 0.0 }, res, IM_COL32_BLACK);
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ static void DrawLeftImage()
|
||||
int a = std::lround(255.0 * imageAlpha);
|
||||
GuestTexture *guestTexture = g_installTextures[installTextureIndex % g_installTextures.size()].get();
|
||||
auto &res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
ImVec2 min = { g_aspectRatioOffsetX + Scale(IMAGE_X), g_aspectRatioOffsetY + Scale(IMAGE_Y) };
|
||||
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));
|
||||
@@ -491,7 +491,7 @@ static void DrawLeftImage()
|
||||
|
||||
static void DrawHeaderIconsForInstallPhase(double iconsPosX, double iconsPosY, double iconsScale)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
// Arrow Circle Icon
|
||||
ImVec2 arrowCircleMin = { g_aspectRatioOffsetX + Scale(iconsPosX - iconsScale / 2), Scale(iconsPosY - iconsScale / 2) };
|
||||
@@ -546,7 +546,7 @@ static void DrawHeaderIconsForInstallPhase(double iconsPosX, double iconsPosY, d
|
||||
|
||||
static void DrawHeaderIcons()
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
float iconsPosX = 256.0f;
|
||||
float iconsPosY = 80.0f;
|
||||
@@ -582,7 +582,7 @@ static void DrawScanlineBars()
|
||||
}
|
||||
|
||||
auto &res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_SCANLINE);
|
||||
|
||||
@@ -680,7 +680,7 @@ static void DrawScanlineBars()
|
||||
static void DrawContainer(ImVec2 min, ImVec2 max, bool isTextArea)
|
||||
{
|
||||
auto &res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
double gridAlpha = ComputeMotionInstaller(g_appearTime, g_disappearTime,
|
||||
isTextArea ? CONTAINER_INNER_TIME : CONTAINER_OUTER_TIME,
|
||||
@@ -711,7 +711,7 @@ static void DrawContainer(ImVec2 min, ImVec2 max, bool isTextArea)
|
||||
static void DrawDescriptionContainer()
|
||||
{
|
||||
auto &res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto fontSize = Scale(28.0f);
|
||||
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
|
||||
|
||||
@@ -792,24 +792,41 @@ static void DrawDescriptionContainer()
|
||||
);
|
||||
|
||||
drawList->PopClipRect();
|
||||
|
||||
drawList->PopClipRect();
|
||||
|
||||
if (g_currentPage == WizardPage::InstallSucceeded)
|
||||
{
|
||||
auto descTextSize = MeasureCentredParagraph(g_seuratFont, fontSize, lineWidth, lineMargin, descriptionText);
|
||||
|
||||
auto hedgeDevStr = "hedge-dev";
|
||||
auto hedgeDevTextSize = g_seuratFont->CalcTextSizeA(fontSize, FLT_MAX, 0, hedgeDevStr);
|
||||
auto hedgeDevTextMarginX = Scale(15);
|
||||
|
||||
auto imageScale = hedgeDevTextSize.x / 3;
|
||||
auto imageMarginY = Scale(15);
|
||||
|
||||
auto colWhite = IM_COL32(255, 255, 255, 255 * textAlpha);
|
||||
|
||||
auto containerLeft = g_aspectRatioOffsetX + Scale(CONTAINER_X);
|
||||
auto containerTop = g_aspectRatioOffsetY + Scale(CONTAINER_Y);
|
||||
auto containerRight = containerLeft + Scale(CONTAINER_WIDTH);
|
||||
auto containerBottom = containerTop + Scale(CONTAINER_HEIGHT);
|
||||
|
||||
auto marqueeTextSize = g_seuratFont->CalcTextSizeA(fontSize, FLT_MAX, 0, g_creditsStr.c_str());
|
||||
auto marqueeTextMarginX = Scale(5);
|
||||
auto marqueeTextMarginY = Scale(15);
|
||||
|
||||
ImVec2 marqueeTextPos = { descriptionMax.x, containerBottom - marqueeTextSize.y - marqueeTextMarginY };
|
||||
ImVec2 marqueeTextMin = { containerLeft, marqueeTextPos.y };
|
||||
ImVec2 marqueeTextMax = { containerRight, containerBottom };
|
||||
|
||||
auto imageScale = hedgeDevTextSize.x / 3;
|
||||
auto imageMarginY = Scale(2);
|
||||
|
||||
ImVec2 imageRegionMin = { containerLeft, textY + descTextSize.y };
|
||||
ImVec2 imageRegionMax = { containerRight, containerBottom - (marqueeTextMax.y - marqueeTextMin.y) };
|
||||
|
||||
ImVec2 imageMin =
|
||||
{
|
||||
/* X */ g_aspectRatioOffsetX + Scale(CONTAINER_X) + (Scale(CONTAINER_WIDTH) / 2) - (imageScale / 2) - (hedgeDevTextSize.x / 2) - hedgeDevTextMarginX,
|
||||
/* Y */ g_aspectRatioOffsetY + Scale(CONTAINER_Y) + (Scale(CONTAINER_HEIGHT) / 2) - (imageScale / 2) + imageMarginY
|
||||
/* X */ imageRegionMin.x + ((imageRegionMax.x - imageRegionMin.x) / 2) - (imageScale / 2) - (hedgeDevTextSize.x / 2) - hedgeDevTextMarginX,
|
||||
/* Y */ imageRegionMin.y + ((imageRegionMax.y - imageRegionMin.y) / 2) - (imageScale / 2) - imageMarginY
|
||||
};
|
||||
|
||||
ImVec2 imageMax = { imageMin.x + imageScale, imageMin.y + imageScale };
|
||||
@@ -825,16 +842,8 @@ static void DrawDescriptionContainer()
|
||||
hedgeDevStr
|
||||
);
|
||||
|
||||
auto marqueeTextSize = g_seuratFont->CalcTextSizeA(fontSize, FLT_MAX, 0, g_creditsStr.c_str());
|
||||
auto marqueeTextMarginX = Scale(5);
|
||||
auto marqueeTextMarginY = Scale(15);
|
||||
|
||||
ImVec2 textPos = { descriptionMax.x, g_aspectRatioOffsetY + Scale(CONTAINER_Y) + Scale(CONTAINER_HEIGHT) - marqueeTextSize.y - marqueeTextMarginY };
|
||||
ImVec2 textMin = { g_aspectRatioOffsetX + Scale(CONTAINER_X), textPos.y };
|
||||
ImVec2 textMax = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + Scale(CONTAINER_WIDTH), g_aspectRatioOffsetY + Scale(CONTAINER_Y) + Scale(CONTAINER_HEIGHT) };
|
||||
|
||||
SetHorizontalMarqueeFade(textMin, textMax, Scale(32));
|
||||
DrawTextWithMarquee(g_seuratFont, fontSize, textPos, textMin, textMax, colWhite, g_creditsStr.c_str(), g_installerEndTime, 0.9, Scale(200));
|
||||
SetHorizontalMarqueeFade(marqueeTextMin, marqueeTextMax, Scale(32));
|
||||
DrawTextWithMarquee(g_seuratFont, fontSize, marqueeTextPos, marqueeTextMin, marqueeTextMax, colWhite, g_creditsStr.c_str(), g_installerEndTime, 0.9, Scale(200));
|
||||
ResetMarqueeFade();
|
||||
}
|
||||
|
||||
@@ -863,7 +872,7 @@ static void DrawDescriptionContainer()
|
||||
|
||||
if (g_currentPage == WizardPage::InstallSucceeded && textAlpha >= 1.0)
|
||||
{
|
||||
ButtonGuide::Open(Button(Localise("Common_Select"), selectIcon));
|
||||
ButtonGuide::Open(Button("Common_Select", selectIcon));
|
||||
}
|
||||
else if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
|
||||
{
|
||||
@@ -875,15 +884,15 @@ static void DrawDescriptionContainer()
|
||||
|
||||
std::array<Button, 2> buttons =
|
||||
{
|
||||
Button(Localise("Common_Select"), selectIcon),
|
||||
Button(Localise(backKey), backIcon)
|
||||
Button("Common_Select", selectIcon),
|
||||
Button(backKey, backIcon)
|
||||
};
|
||||
|
||||
ButtonGuide::Open(buttons);
|
||||
}
|
||||
else if (g_currentPage == WizardPage::Installing)
|
||||
{
|
||||
ButtonGuide::Open(Button(Localise("Common_Cancel"), backIcon));
|
||||
ButtonGuide::Open(Button("Common_Cancel", backIcon));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -896,7 +905,7 @@ static void DrawDescriptionContainer()
|
||||
static void DrawButtonContainer(ImVec2 min, ImVec2 max, int baser, int baseg, float alpha)
|
||||
{
|
||||
auto &res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_SCANLINE_BUTTON);
|
||||
drawList->AddRectFilledMultiColor(min, max, IM_COL32(baser, baseg + 130, 0, 223 * alpha), IM_COL32(baser, baseg + 130, 0, 178 * alpha), IM_COL32(baser, baseg + 130, 0, 223 * alpha), IM_COL32(baser, baseg + 130, 0, 178 * alpha));
|
||||
drawList->AddRectFilledMultiColor(min, max, IM_COL32(baser, baseg, 0, 13 * alpha), IM_COL32(baser, baseg, 0, 0), IM_COL32(baser, baseg, 0, 55 * alpha), IM_COL32(baser, baseg, 0, 6 * alpha));
|
||||
@@ -924,7 +933,7 @@ static void DrawButton(ImVec2 min, ImVec2 max, const char *buttonText, bool sour
|
||||
buttonPressed = false;
|
||||
|
||||
auto &res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
float alpha = ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_INNER_TIME, CONTAINER_INNER_DURATION);
|
||||
if (!buttonEnabled)
|
||||
{
|
||||
@@ -1030,7 +1039,7 @@ static void DrawSourceButton(ButtonColumn buttonColumn, float yRatio, const char
|
||||
static void DrawProgressBar(float progressRatio)
|
||||
{
|
||||
auto &res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
float alpha = 1.0;
|
||||
const uint32_t innerColor0 = IM_COL32(0, 65, 0, 255 * alpha);
|
||||
const uint32_t innerColor1 = IM_COL32(0, 32, 0, 255 * alpha);
|
||||
@@ -1532,7 +1541,7 @@ static void DrawHorizontalBorder(bool bottomBorder)
|
||||
const uint32_t FADE_COLOR_LEFT = IM_COL32(155, 155, 155, 0);
|
||||
const uint32_t SOLID_COLOR = IM_COL32(155, 200, 155, 255);
|
||||
const uint32_t FADE_COLOR_RIGHT = IM_COL32(155, 225, 155, 0);
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
double borderScale = 1.0 - ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_LINE_ANIMATION_TIME, CONTAINER_LINE_ANIMATION_DURATION);
|
||||
float midX = g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH / 5);
|
||||
float minX = std::lerp(g_aspectRatioOffsetX + Scale(CONTAINER_X - BORDER_SIZE - BORDER_OVERSHOOT), midX, borderScale);
|
||||
@@ -1564,7 +1573,7 @@ static void DrawVerticalBorder(bool rightBorder)
|
||||
{
|
||||
const uint32_t SOLID_COLOR = IM_COL32(155, rightBorder ? 225 : 155, 155, 255);
|
||||
const uint32_t FADE_COLOR = IM_COL32(155, rightBorder ? 225 : 155, 155, 0);
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
double borderScale = 1.0 - ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_LINE_ANIMATION_TIME, CONTAINER_LINE_ANIMATION_DURATION);
|
||||
float minX = g_aspectRatioOffsetX + (rightBorder ? Scale(CONTAINER_X + CONTAINER_WIDTH) : Scale(CONTAINER_X - BORDER_SIZE));
|
||||
float maxX = minX + Scale(BORDER_SIZE);
|
||||
@@ -1661,7 +1670,7 @@ static void PickerDrawForeground()
|
||||
{
|
||||
if (g_currentPickerVisible)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
drawList->AddRectFilled({ 0.0f, 0.0f }, ImGui::GetIO().DisplaySize, IM_COL32(0, 0, 0, 190));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ g_sdlEventListenerForMessageWindow;
|
||||
|
||||
bool DrawContainer(float appearTime, ImVec2 centre, ImVec2 max, bool isForeground = true)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
ImVec2 _min = { centre.x - max.x, centre.y - max.y };
|
||||
ImVec2 _max = { centre.x + max.x, centre.y + max.y };
|
||||
@@ -201,7 +201,7 @@ bool DrawContainer(float appearTime, ImVec2 centre, ImVec2 max, bool isForegroun
|
||||
|
||||
void DrawButton(int rowIndex, float yOffset, float width, float height, std::string& text)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
auto clipRectMin = drawList->GetClipRectMin();
|
||||
auto clipRectMax = drawList->GetClipRectMax();
|
||||
@@ -245,7 +245,7 @@ void DrawNextButtonGuide(bool isController, bool isKeyboard)
|
||||
if (App::s_isInit)
|
||||
icon = EButtonIcon::A;
|
||||
|
||||
ButtonGuide::Open(Button(Localise("Common_Next"), icon));
|
||||
ButtonGuide::Open(Button("Common_Next", icon));
|
||||
}
|
||||
|
||||
static void ResetSelection()
|
||||
@@ -275,7 +275,7 @@ void MessageWindow::Draw()
|
||||
if (!s_isVisible)
|
||||
return;
|
||||
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
|
||||
ImVec2 centre = { res.x / 2, res.y / 2 };
|
||||
@@ -425,8 +425,8 @@ void MessageWindow::Draw()
|
||||
|
||||
std::array<Button, 2> buttons =
|
||||
{
|
||||
Button(Localise("Common_Select"), selectIcon),
|
||||
Button(Localise("Common_Back"), backIcon),
|
||||
Button("Common_Select", selectIcon),
|
||||
Button("Common_Back", backIcon),
|
||||
};
|
||||
|
||||
ButtonGuide::Open(buttons);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "options_menu.h"
|
||||
#include "options_menu_thumbnails.h"
|
||||
#include "tv_static.h"
|
||||
|
||||
#include <api/SWA.h>
|
||||
#include <apu/audio.h>
|
||||
@@ -18,6 +19,7 @@
|
||||
#include <app.h>
|
||||
#include <decompressor.h>
|
||||
#include <exports.h>
|
||||
#include <sdl_listener.h>
|
||||
|
||||
#include <res/images/options_menu/miles_electric.dds.h>
|
||||
|
||||
@@ -101,6 +103,24 @@ static double g_appearTime = 0.0;
|
||||
|
||||
static std::unique_ptr<GuestTexture> g_upMilesElectric;
|
||||
|
||||
static float g_rightStickY;
|
||||
|
||||
class SDLEventListenerForOptionsMenu : public SDLEventListener
|
||||
{
|
||||
public:
|
||||
bool OnSDLEvent(SDL_Event* event) override
|
||||
{
|
||||
if (!OptionsMenu::s_isVisible || !hid::IsInputAllowed())
|
||||
return false;
|
||||
|
||||
if (event->type == SDL_CONTROLLERAXISMOTION && event->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY)
|
||||
g_rightStickY = event->caxis.value / 32767.0f;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
g_sdlEventListenerForOptionsMenu;
|
||||
|
||||
static void DrawTitle()
|
||||
{
|
||||
static constexpr double fadeOffset = 3.0;
|
||||
@@ -127,7 +147,7 @@ static void DrawTitle()
|
||||
g_titleAnimBegin = false;
|
||||
}
|
||||
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto x = Scale(122);
|
||||
auto y = Scale(56);
|
||||
|
||||
@@ -238,7 +258,7 @@ static void DrawScanlineBars()
|
||||
float height = Scale(105.0f);
|
||||
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
if (OptionsMenu::s_pauseMenuType != SWA::eMenuType_WorldMap)
|
||||
{
|
||||
@@ -350,7 +370,7 @@ static void DrawContainer(ImVec2 min, ImVec2 max, bool drawRightOutline)
|
||||
max.y = Lerp(center, max.y, containerHeight);
|
||||
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
double outerAlpha = g_isStage ? 1.0 : ComputeMotion(g_appearTime, CONTAINER_OUTER_TIME, CONTAINER_OUTER_DURATION);
|
||||
double innerAlpha = g_isStage ? 1.0 : ComputeMotion(g_appearTime, CONTAINER_INNER_TIME, CONTAINER_INNER_DURATION);
|
||||
@@ -454,40 +474,47 @@ static bool DrawCategories()
|
||||
Game_PlaySound("sys_actstg_score");
|
||||
}
|
||||
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto clipRectMin = drawList->GetClipRectMin();
|
||||
auto clipRectMax = drawList->GetClipRectMax();
|
||||
|
||||
constexpr float NARROW_PADDING_GRID_COUNT = 1.5f;
|
||||
constexpr float WIDE_PADDING_GRID_COUNT = 3.0f;
|
||||
|
||||
float gridSize = Scale(GRID_SIZE);
|
||||
float textPadding = gridSize * Lerp(NARROW_PADDING_GRID_COUNT, WIDE_PADDING_GRID_COUNT, g_aspectRatioNarrowScale);
|
||||
float tabPadding = gridSize;
|
||||
|
||||
float size = Scale(32.0f);
|
||||
ImVec2 textSizes[g_categoryCount];
|
||||
float tabWidthSum = 0.0f;
|
||||
float clipRectWidth = clipRectMax.x - clipRectMin.x;
|
||||
|
||||
float textWidthSum = 0.0f;
|
||||
for (size_t i = 0; i < g_categoryCount; i++)
|
||||
{
|
||||
textSizes[i] = g_dfsogeistdFont->CalcTextSizeA(size, FLT_MAX, 0.0f, GetCategory(i).c_str());
|
||||
tabWidthSum += textSizes[i].x + textPadding * 2.0f;
|
||||
textWidthSum += textSizes[i].x;
|
||||
}
|
||||
|
||||
float textSquashRatio = 1.0f;
|
||||
float maxTextWidthSum = clipRectWidth - (gridSize * 4.0f * (g_categoryCount - 1));
|
||||
if (textWidthSum > maxTextWidthSum)
|
||||
{
|
||||
textSquashRatio = maxTextWidthSum / textWidthSum;
|
||||
for (auto& textSize : textSizes)
|
||||
textSize.x *= textSquashRatio;
|
||||
|
||||
textWidthSum = maxTextWidthSum;
|
||||
}
|
||||
tabWidthSum += (g_categoryCount - 1) * tabPadding;
|
||||
|
||||
float tabHeight = gridSize * 4.0f;
|
||||
float xOffset = ((clipRectMax.x - clipRectMin.x) - tabWidthSum) / 2.0f;
|
||||
float textPadding = (clipRectWidth - textWidthSum) / (g_categoryCount + 1.0f);
|
||||
float xOffset = textPadding;
|
||||
xOffset -= (1.0 - motion) * gridSize * 4.0;
|
||||
|
||||
ImVec2 minVec[g_categoryCount];
|
||||
ImVec2 textPositions[g_categoryCount];
|
||||
|
||||
for (size_t i = 0; i < g_categoryCount; i++)
|
||||
{
|
||||
ImVec2 min = { clipRectMin.x + xOffset, clipRectMin.y };
|
||||
float tabPadding = std::min(textPadding / 2.0f, gridSize * 3.0f);
|
||||
|
||||
xOffset += textSizes[i].x + textPadding * 2.0f;
|
||||
ImVec2 max = { clipRectMin.x + xOffset, clipRectMin.y + tabHeight };
|
||||
xOffset += tabPadding;
|
||||
ImVec2 min = { clipRectMin.x + xOffset - tabPadding, clipRectMin.y };
|
||||
ImVec2 max = { min.x + textSizes[i].x + tabPadding * 2.0f, min.y + tabHeight};
|
||||
|
||||
if (g_categoryIndex == i)
|
||||
{
|
||||
@@ -551,21 +578,23 @@ static bool DrawCategories()
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
||||
}
|
||||
|
||||
min.x += textPadding;
|
||||
|
||||
// Store to draw again later, otherwise the tab background gets drawn on top of text during the animation.
|
||||
minVec[i] = min;
|
||||
textPositions[i] = { clipRectMin.x + xOffset, clipRectMin.y };
|
||||
xOffset += textSizes[i].x + textPadding;
|
||||
}
|
||||
|
||||
SetScale({ textSquashRatio, 1.0f });
|
||||
|
||||
for (size_t i = 0; i < g_categoryCount; i++)
|
||||
{
|
||||
auto& min = minVec[i];
|
||||
auto& pos = textPositions[i];
|
||||
uint8_t alpha = (i == g_categoryIndex ? 235 : 128) * motion;
|
||||
|
||||
|
||||
SetOrigin({ pos.x, pos.y });
|
||||
SetGradient
|
||||
(
|
||||
min,
|
||||
{ min.x + textSizes[i].x, min.y + textSizes[i].y },
|
||||
pos,
|
||||
{ pos.x + textSizes[i].x, pos.y + textSizes[i].y },
|
||||
IM_COL32(128, 255, 0, alpha),
|
||||
IM_COL32(255, 192, 0, alpha)
|
||||
);
|
||||
@@ -574,17 +603,19 @@ static bool DrawCategories()
|
||||
(
|
||||
g_dfsogeistdFont,
|
||||
size,
|
||||
min,
|
||||
pos,
|
||||
IM_COL32_WHITE,
|
||||
GetCategory(i).c_str(),
|
||||
4,
|
||||
IM_COL32_BLACK,
|
||||
IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL
|
||||
);
|
||||
|
||||
ResetGradient();
|
||||
}
|
||||
|
||||
SetScale({ 1.0f, 1.0f });
|
||||
SetOrigin({ 0.0f, 0.0f });
|
||||
ResetGradient();
|
||||
|
||||
if (g_isStage || (ImGui::GetTime() - g_appearTime) >= (CONTAINER_FULL_DURATION / 60.0))
|
||||
{
|
||||
drawList->PushClipRect({ clipRectMin.x, clipRectMin.y + gridSize * 6.0f }, { clipRectMax.x - gridSize, clipRectMax.y - gridSize });
|
||||
@@ -601,7 +632,7 @@ static void DrawSelectionArrows(ImVec2 min, ImVec2 max, bool isLeftTapped, bool
|
||||
static bool isLeftArrowMotion = false;
|
||||
static bool isRightArrowMotion = false;
|
||||
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto gridSize = Scale(GRID_SIZE);
|
||||
auto width = gridSize * 2.5f;
|
||||
auto padding = gridSize;
|
||||
@@ -725,7 +756,7 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||
bool isAccessible, std::string* inaccessibleReason = nullptr,
|
||||
T valueMin = T(0), T valueCenter = T(0.5), T valueMax = T(1), bool isSlider = true)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto clipRectMin = drawList->GetClipRectMin();
|
||||
auto clipRectMax = drawList->GetClipRectMax();
|
||||
auto& padState = SWA::CInputState::GetInstance()->GetPadState();
|
||||
@@ -1153,10 +1184,12 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||
|
||||
static void DrawConfigOptions()
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto clipRectMin = drawList->GetClipRectMin();
|
||||
auto clipRectMax = drawList->GetClipRectMax();
|
||||
|
||||
drawList->PushClipRect({ clipRectMin.x, clipRectMin.y }, { clipRectMax.x, clipRectMax.y - Scale(5.0f) });
|
||||
|
||||
g_selectedItem = nullptr;
|
||||
|
||||
float gridSize = Scale(GRID_SIZE);
|
||||
@@ -1178,7 +1211,7 @@ static void DrawConfigOptions()
|
||||
DrawConfigOption(rowCount++, yOffset, &Config::Hints, !isStage, cmnReason);
|
||||
DrawConfigOption(rowCount++, yOffset, &Config::ControlTutorial, !isStage, cmnReason);
|
||||
DrawConfigOption(rowCount++, yOffset, &Config::AchievementNotifications, true);
|
||||
DrawConfigOption(rowCount++, yOffset, &Config::TimeOfDayTransition, true);
|
||||
DrawConfigOption(rowCount++, yOffset, &Config::TimeOfDayTransition, !Config::UseArrowsForTimeOfDayTransition);
|
||||
break;
|
||||
|
||||
case 1: // INPUT
|
||||
@@ -1333,13 +1366,15 @@ static void DrawConfigOptions()
|
||||
if (disableMoveAnimation)
|
||||
g_prevSelectedRowIndex = g_selectedRowIndex;
|
||||
|
||||
drawList->PopClipRect();
|
||||
|
||||
// Pop clip rect from DrawCategories
|
||||
drawList->PopClipRect();
|
||||
|
||||
// Draw scroll bar
|
||||
if (rowCount > visibleRowCount)
|
||||
{
|
||||
float totalHeight = (clipRectMax.y - clipRectMin.y);
|
||||
float totalHeight = (clipRectMax.y - clipRectMin.y) - Scale(2.0f);
|
||||
float heightRatio = float(visibleRowCount) / float(rowCount);
|
||||
|
||||
float offsetRatio = float(g_firstVisibleRowIndex) / float(rowCount);
|
||||
@@ -1351,7 +1386,7 @@ static void DrawConfigOptions()
|
||||
drawList->AddRectFilled
|
||||
(
|
||||
{ clipRectMax.x, minY },
|
||||
{ clipRectMax.x + gridSize, minY + totalHeight * heightRatio },
|
||||
{ clipRectMax.x + gridSize - Scale(1.0f), minY + totalHeight * heightRatio},
|
||||
IM_COL32(0, 128, 0, 255)
|
||||
);
|
||||
}
|
||||
@@ -1359,7 +1394,7 @@ static void DrawConfigOptions()
|
||||
|
||||
static void DrawSettingsPanel(ImVec2 settingsMin, ImVec2 settingsMax)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
SetProceduralOrigin(settingsMin);
|
||||
DrawContainer(settingsMin, settingsMax, true);
|
||||
@@ -1383,7 +1418,7 @@ static void DrawSettingsPanel(ImVec2 settingsMin, ImVec2 settingsMax)
|
||||
|
||||
static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
SetProceduralOrigin(infoMin);
|
||||
DrawContainer(infoMin, infoMax, false);
|
||||
@@ -1402,7 +1437,27 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
||||
ImVec2 thumbnailMin = { clipRectMin.x, clipRectMin.y + Scale(GRID_SIZE / 2.0f) };
|
||||
ImVec2 thumbnailMax = { clipRectMax.x, thumbnailMin.y + thumbnailHeight };
|
||||
|
||||
drawList->AddImage(thumbnail, thumbnailMin, thumbnailMax);
|
||||
if (g_isStage)
|
||||
{
|
||||
drawList->AddImage(thumbnail, thumbnailMin, thumbnailMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
float time = g_appearTime + CONTAINER_FULL_DURATION / 60.0;
|
||||
|
||||
drawList->AddImage(
|
||||
thumbnail,
|
||||
thumbnailMin,
|
||||
thumbnailMax,
|
||||
{ 0.0f, 0.0f },
|
||||
{ 1.0f, 1.0f },
|
||||
IM_COL32(255, 255, 255, 255 * TVStatic::ComputeThumbnailAlpha(time)));
|
||||
|
||||
TVStatic::Draw(
|
||||
{ (thumbnailMin.x + thumbnailMax.x) / 2.0f, (thumbnailMin.y + thumbnailMax.y) / 2.0f },
|
||||
{ (thumbnailMax.x - thumbnailMin.x), (thumbnailMax.y - thumbnailMin.y) },
|
||||
time);
|
||||
}
|
||||
|
||||
if (g_inaccessibleReason)
|
||||
{
|
||||
@@ -1472,23 +1527,19 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
||||
|
||||
if (scrollMax > 0.0f)
|
||||
{
|
||||
if (auto pInputState = SWA::CInputState::GetInstance())
|
||||
{
|
||||
auto& rPadState = pInputState->GetPadState();
|
||||
auto& vert = rPadState.RightStickVertical;
|
||||
auto vert = -g_rightStickY;
|
||||
|
||||
if (fabs(vert) > 0.25f)
|
||||
{
|
||||
isManualScrolling = true;
|
||||
scrollOffset += vert * scrollSpeed * App::s_deltaTime;
|
||||
}
|
||||
else if (isManualScrolling && fabs(vert) <= 0.25f)
|
||||
{
|
||||
isScrolling = false;
|
||||
isManualScrolling = false;
|
||||
scrollTimer = 0.0f;
|
||||
scrollDirection = vert > 0.0f ? 1.0f : -1.0f;
|
||||
}
|
||||
if (fabs(vert) > 0.25f)
|
||||
{
|
||||
isManualScrolling = true;
|
||||
scrollOffset += vert * scrollSpeed * App::s_deltaTime;
|
||||
}
|
||||
else if (isManualScrolling && fabs(vert) <= 0.25f)
|
||||
{
|
||||
isScrolling = false;
|
||||
isManualScrolling = false;
|
||||
scrollTimer = 0.0f;
|
||||
scrollDirection = vert > 0.0f ? 1.0f : -1.0f;
|
||||
}
|
||||
|
||||
if (!isManualScrolling)
|
||||
@@ -1532,7 +1583,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
||||
scrollDirection = 1.0f;
|
||||
}
|
||||
|
||||
SetVerticalMarqueeFade(clipRectMin, clipRectMax, Scale(24), Lerp(Scale(24), 0.0f, scrollOffset / scrollMax));
|
||||
SetVerticalMarqueeFade({ clipRectMin.x, clipRectMin.y + Scale(5.5f) }, clipRectMax, Scale(10), Scale(10));
|
||||
|
||||
DrawRubyAnnotatedText
|
||||
(
|
||||
@@ -1580,7 +1631,7 @@ static void SetOptionsMenuVisible(bool isVisible)
|
||||
|
||||
static bool DrawMilesElectric()
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
|
||||
// Compensate for the lack of CSD UI dimming the background.
|
||||
@@ -1633,7 +1684,7 @@ static bool DrawMilesElectric()
|
||||
|
||||
static bool DrawFadeTransition()
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
|
||||
auto scaleMotion = ComputeMotion(g_appearTime, 0, MILES_ELECTRIC_SCALE_DURATION);
|
||||
@@ -1658,6 +1709,8 @@ void OptionsMenu::Init()
|
||||
LoadThumbnails();
|
||||
|
||||
g_upMilesElectric = LOAD_ZSTD_TEXTURE(g_miles_electric);
|
||||
|
||||
TVStatic::Init();
|
||||
}
|
||||
|
||||
void OptionsMenu::Draw()
|
||||
@@ -1678,7 +1731,7 @@ void OptionsMenu::Draw()
|
||||
|
||||
if (!g_isClosing)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
|
||||
if (g_isStage)
|
||||
@@ -1737,16 +1790,16 @@ void OptionsMenu::Open(bool isPause, SWA::EMenuType pauseMenuType)
|
||||
|
||||
std::array<Button, 4> buttons =
|
||||
{
|
||||
Button(Localise("Common_Switch"), EButtonIcon::LBRB, EButtonAlignment::Left, &g_isControlsVisible),
|
||||
Button(Localise("Common_Reset"), EButtonIcon::X, &g_canReset),
|
||||
Button(Localise("Common_Select"), EButtonIcon::A, &g_isControlsVisible),
|
||||
Button(Localise("Common_Back"), EButtonIcon::B, &g_isControlsVisible)
|
||||
Button("Common_Switch", EButtonIcon::LBRB, EButtonAlignment::Left, &g_isControlsVisible),
|
||||
Button("Common_Reset", EButtonIcon::X, &g_canReset),
|
||||
Button("Common_Select", EButtonIcon::A, &g_isControlsVisible),
|
||||
Button("Common_Back", EButtonIcon::B, &g_isControlsVisible)
|
||||
};
|
||||
|
||||
ButtonGuide::Open(buttons);
|
||||
ButtonGuide::SetSideMargins(250);
|
||||
|
||||
hid::SetProhibitedButtons(XAMINPUT_GAMEPAD_START);
|
||||
hid::SetProhibitedInputs(XAMINPUT_GAMEPAD_START, false, true);
|
||||
}
|
||||
|
||||
void OptionsMenu::Close()
|
||||
@@ -1760,7 +1813,7 @@ void OptionsMenu::Close()
|
||||
ButtonGuide::Close();
|
||||
Config::Save();
|
||||
|
||||
hid::SetProhibitedButtons(0);
|
||||
hid::SetProhibitedInputs();
|
||||
}
|
||||
|
||||
// Skip Miles Electric animation at main menu.
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
#include <ui/options_menu_thumbnails.h>
|
||||
#include <decompressor.h>
|
||||
#include <hid/hid.h>
|
||||
|
||||
// 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/allow_background_input.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/antialiasing.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/antialiasing_none.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/antialiasing_2x.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/antialiasing_4x.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/antialiasing_8x.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/brightness.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/control_tutorial.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/channel_stereo.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/channel_surround.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/control_tutorial_xb.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/control_tutorial_ps.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/controller_icons.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/default.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/effects_volume.dds.h>
|
||||
@@ -24,7 +31,8 @@
|
||||
#include <res/images/options_menu/thumbnails/motion_blur_off.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/motion_blur_original.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/motion_blur_enhanced.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/movie_scale_mode.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/movie_scale_fit.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/movie_scale_fill.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/music_attenuation.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/music_volume.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/resolution_scale.dds.h>
|
||||
@@ -35,15 +43,17 @@
|
||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x4096.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x8192.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/subtitles.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/time_of_day_transition_xbox.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/time_of_day_transition_playstation.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/time_transition_xb.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/time_transition_ps.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/transparency_antialiasing_false.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/transparency_antialiasing_true.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/ui_alignment_mode.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/ui_alignment_centre.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/ui_alignment_edge.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/vertical_camera.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/voice_language.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_on.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/vsync_off.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/window_size.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/xbox_color_correction.dds.h>
|
||||
|
||||
@@ -53,22 +63,28 @@ static std::unordered_map<std::string_view, std::unique_ptr<GuestTexture>> g_nam
|
||||
static std::unordered_map<const IConfigDef*, std::unique_ptr<GuestTexture>> g_configThumbnails;
|
||||
|
||||
static VALUE_THUMBNAIL_MAP(ETimeOfDayTransition) g_timeOfDayTransitionThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(EChannelConfiguration) g_channelConfigurationThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(EAntiAliasing) g_msaaAntiAliasingThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(bool) g_vsyncThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(bool) g_transparencyAntiAliasingThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(EShadowResolution) g_shadowResolutionThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(EGITextureFiltering) g_giTextureFilteringThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(EMotionBlur) g_motionBlurThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(bool) g_xboxColorCorrectionThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(ECutsceneAspectRatio) g_cutsceneAspectRatioThumbnails;
|
||||
static VALUE_THUMBNAIL_MAP(EUIAlignmentMode) g_uiAlignmentThumbnails;
|
||||
|
||||
void LoadThumbnails()
|
||||
{
|
||||
g_namedThumbnails["Default"] = LOAD_ZSTD_TEXTURE(g_default);
|
||||
g_namedThumbnails["WindowSize"] = LOAD_ZSTD_TEXTURE(g_window_size);
|
||||
g_namedThumbnails["ControlTutorialXB"] = LOAD_ZSTD_TEXTURE(g_control_tutorial_xb);
|
||||
g_namedThumbnails["ControlTutorialPS"] = LOAD_ZSTD_TEXTURE(g_control_tutorial_ps);
|
||||
|
||||
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::ControlTutorial] = LOAD_ZSTD_TEXTURE(g_control_tutorial);
|
||||
g_configThumbnails[&Config::AchievementNotifications] = LOAD_ZSTD_TEXTURE(g_achievement_notifications);
|
||||
|
||||
g_timeOfDayTransitionThumbnails[ETimeOfDayTransition::Xbox] = LOAD_ZSTD_TEXTURE(g_time_of_day_transition_xbox);
|
||||
@@ -82,6 +98,10 @@ void LoadThumbnails()
|
||||
g_configThumbnails[&Config::MasterVolume] = LOAD_ZSTD_TEXTURE(g_master_volume);
|
||||
g_configThumbnails[&Config::MusicVolume] = LOAD_ZSTD_TEXTURE(g_music_volume);
|
||||
g_configThumbnails[&Config::EffectsVolume] = LOAD_ZSTD_TEXTURE(g_effects_volume);
|
||||
|
||||
g_channelConfigurationThumbnails[EChannelConfiguration::Stereo] = LOAD_ZSTD_TEXTURE(g_channel_stereo);
|
||||
g_channelConfigurationThumbnails[EChannelConfiguration::Surround] = LOAD_ZSTD_TEXTURE(g_channel_surround);
|
||||
|
||||
g_configThumbnails[&Config::MusicAttenuation] = LOAD_ZSTD_TEXTURE(g_music_attenuation);
|
||||
g_configThumbnails[&Config::BattleTheme] = LOAD_ZSTD_TEXTURE(g_battle_theme);
|
||||
g_configThumbnails[&Config::WindowSize] = LOAD_ZSTD_TEXTURE(g_window_size);
|
||||
@@ -89,10 +109,17 @@ void LoadThumbnails()
|
||||
g_configThumbnails[&Config::AspectRatio] = LOAD_ZSTD_TEXTURE(g_aspect_ratio);
|
||||
g_configThumbnails[&Config::ResolutionScale] = LOAD_ZSTD_TEXTURE(g_resolution_scale);
|
||||
g_configThumbnails[&Config::Fullscreen] = LOAD_ZSTD_TEXTURE(g_fullscreen);
|
||||
g_configThumbnails[&Config::VSync] = LOAD_ZSTD_TEXTURE(g_vsync);
|
||||
|
||||
g_vsyncThumbnails[false] = LOAD_ZSTD_TEXTURE(g_vsync_off);
|
||||
g_vsyncThumbnails[true] = LOAD_ZSTD_TEXTURE(g_vsync_on);
|
||||
|
||||
g_configThumbnails[&Config::FPS] = LOAD_ZSTD_TEXTURE(g_fps);
|
||||
g_configThumbnails[&Config::Brightness] = LOAD_ZSTD_TEXTURE(g_brightness);
|
||||
g_configThumbnails[&Config::AntiAliasing] = LOAD_ZSTD_TEXTURE(g_antialiasing);
|
||||
|
||||
g_msaaAntiAliasingThumbnails[EAntiAliasing::None] = LOAD_ZSTD_TEXTURE(g_antialiasing_none);
|
||||
g_msaaAntiAliasingThumbnails[EAntiAliasing::MSAA2x] = LOAD_ZSTD_TEXTURE(g_antialiasing_2x);
|
||||
g_msaaAntiAliasingThumbnails[EAntiAliasing::MSAA4x] = LOAD_ZSTD_TEXTURE(g_antialiasing_4x);
|
||||
g_msaaAntiAliasingThumbnails[EAntiAliasing::MSAA8x] = LOAD_ZSTD_TEXTURE(g_antialiasing_8x);
|
||||
|
||||
g_transparencyAntiAliasingThumbnails[false] = LOAD_ZSTD_TEXTURE(g_transparency_antialiasing_false);
|
||||
g_transparencyAntiAliasingThumbnails[true] = LOAD_ZSTD_TEXTURE(g_transparency_antialiasing_true);
|
||||
@@ -111,8 +138,13 @@ void LoadThumbnails()
|
||||
g_motionBlurThumbnails[EMotionBlur::Original] = LOAD_ZSTD_TEXTURE(g_motion_blur_original);
|
||||
g_motionBlurThumbnails[EMotionBlur::Enhanced] = LOAD_ZSTD_TEXTURE(g_motion_blur_enhanced);
|
||||
|
||||
g_cutsceneAspectRatioThumbnails[ECutsceneAspectRatio::Original] = LOAD_ZSTD_TEXTURE(g_movie_scale_fit);
|
||||
g_cutsceneAspectRatioThumbnails[ECutsceneAspectRatio::Unlocked] = LOAD_ZSTD_TEXTURE(g_movie_scale_fill);
|
||||
|
||||
g_uiAlignmentThumbnails[EUIAlignmentMode::Centre] = LOAD_ZSTD_TEXTURE(g_ui_alignment_centre);
|
||||
g_uiAlignmentThumbnails[EUIAlignmentMode::Edge] = LOAD_ZSTD_TEXTURE(g_ui_alignment_edge);
|
||||
|
||||
g_configThumbnails[&Config::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
|
||||
g_configThumbnails[&Config::UIAlignmentMode] = LOAD_ZSTD_TEXTURE(g_ui_alignment_mode);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -148,10 +180,23 @@ GuestTexture* GetThumbnail(const IConfigDef* cfg)
|
||||
{
|
||||
auto texture = g_namedThumbnails["Default"].get();
|
||||
|
||||
if (cfg == &Config::ControlTutorial)
|
||||
{
|
||||
bool isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation;
|
||||
|
||||
if (Config::ControllerIcons == EControllerIcons::Auto)
|
||||
isPlayStation = hid::g_inputDeviceController == hid::EInputDevice::PlayStation;
|
||||
|
||||
texture = isPlayStation ? g_namedThumbnails["ControlTutorialPS"].get() : g_namedThumbnails["ControlTutorialXB"].get();
|
||||
}
|
||||
if (cfg == &Config::TimeOfDayTransition)
|
||||
{
|
||||
TryGetValueThumbnail<ETimeOfDayTransition>(cfg, &g_timeOfDayTransitionThumbnails, &texture);
|
||||
}
|
||||
else if (cfg == &Config::AntiAliasing)
|
||||
{
|
||||
TryGetValueThumbnail<EAntiAliasing>(cfg, &g_msaaAntiAliasingThumbnails, &texture);
|
||||
}
|
||||
else if (cfg == &Config::TransparencyAntiAliasing)
|
||||
{
|
||||
TryGetValueThumbnail<bool>(cfg, &g_transparencyAntiAliasingThumbnails, &texture);
|
||||
@@ -168,6 +213,26 @@ GuestTexture* GetThumbnail(const IConfigDef* cfg)
|
||||
{
|
||||
TryGetValueThumbnail<EMotionBlur>(cfg, &g_motionBlurThumbnails, &texture);
|
||||
}
|
||||
else if (cfg == &Config::XboxColorCorrection)
|
||||
{
|
||||
TryGetValueThumbnail<bool>(cfg, &g_xboxColorCorrectionThumbnails, &texture);
|
||||
}
|
||||
else if (cfg == &Config::CutsceneAspectRatio)
|
||||
{
|
||||
TryGetValueThumbnail<ECutsceneAspectRatio>(cfg, &g_cutsceneAspectRatioThumbnails, &texture);
|
||||
}
|
||||
else if (cfg == &Config::VSync)
|
||||
{
|
||||
TryGetValueThumbnail<bool>(cfg, &g_vsyncThumbnails, &texture);
|
||||
}
|
||||
else if (cfg == &Config::ChannelConfiguration)
|
||||
{
|
||||
TryGetValueThumbnail<EChannelConfiguration>(cfg, &g_channelConfigurationThumbnails, &texture);
|
||||
}
|
||||
else if (cfg == &Config::UIAlignmentMode)
|
||||
{
|
||||
TryGetValueThumbnail<EUIAlignmentMode>(cfg, &g_uiAlignmentThumbnails, &texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
#include "tv_static.h"
|
||||
#include "imgui_utils.h"
|
||||
|
||||
#include <decompressor.h>
|
||||
#include <gpu/video.h>
|
||||
#include <patches/aspect_ratio_patches.h>
|
||||
#include <res/images/options_menu/options_static.dds.h>
|
||||
#include <res/images/options_menu/options_static_flash.dds.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct FloatLinear
|
||||
{
|
||||
float value;
|
||||
float time;
|
||||
|
||||
static float Sample(const FloatLinear& a, const FloatLinear& b, float time)
|
||||
{
|
||||
const float t = std::clamp((time - a.time) / (b.time - a.time), 0.0f, 1.0f);
|
||||
return (b.value - a.value) * t + a.value;
|
||||
}
|
||||
};
|
||||
|
||||
struct FloatHermite
|
||||
{
|
||||
float value;
|
||||
float time;
|
||||
float inTangent;
|
||||
float outTangent;
|
||||
|
||||
static float Sample(const FloatHermite& a, const FloatHermite& b, float time)
|
||||
{
|
||||
const float t = std::clamp((time - a.time) / (b.time - a.time), 0.0f, 1.0f);
|
||||
|
||||
float valueDelta = b.value - a.value;
|
||||
float frameDelta = b.time - a.time;
|
||||
|
||||
float biasSquaric = t * t;
|
||||
float biasCubic = biasSquaric * t;
|
||||
|
||||
float valueCubic = (a.outTangent + a.inTangent) * frameDelta - valueDelta * 2.0f;
|
||||
float valueSquaric = valueDelta * 3.0f - (a.inTangent * 2.0f + a.outTangent) * frameDelta;
|
||||
float valueLinear = frameDelta * a.inTangent;
|
||||
|
||||
return valueCubic * biasCubic + valueSquaric * biasSquaric + valueLinear * t + a.value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
static auto Sample(const std::array<T, N>& keys, float time)
|
||||
{
|
||||
T firstKey = keys[0];
|
||||
T lastKey = keys[N - 1];
|
||||
|
||||
if (time < firstKey.time)
|
||||
return firstKey.value;
|
||||
|
||||
if (time > lastKey.time)
|
||||
return lastKey.value;
|
||||
|
||||
size_t keyIndex = 0;
|
||||
for (auto key : keys)
|
||||
{
|
||||
if (key.time >= time)
|
||||
break;
|
||||
|
||||
keyIndex++;
|
||||
}
|
||||
|
||||
if (keyIndex >= N)
|
||||
return keys[N - 1].value;
|
||||
|
||||
return T::Sample(keys[keyIndex - 1], keys[keyIndex], time);
|
||||
}
|
||||
|
||||
static std::unique_ptr<GuestTexture> g_flashTexture;
|
||||
static std::unique_ptr<GuestTexture> g_noiseTexture;
|
||||
|
||||
static constexpr float FRAME_OFFSET = 65.0f;
|
||||
static constexpr float FRAME_SCALE = 1.0f / 60.0f;
|
||||
static constexpr float FRAME_DURATION = 32.0f;
|
||||
|
||||
static std::array g_flashScaleX =
|
||||
{
|
||||
FloatHermite{ 0, 67 * FRAME_SCALE, 0, 0.673736f },
|
||||
FloatHermite{ 2, 70 * FRAME_SCALE, -0.003465f, -0.682543f },
|
||||
FloatHermite{ 0, 73 * FRAME_SCALE, 0, 0 },
|
||||
};
|
||||
static std::array g_flashScaleY =
|
||||
{
|
||||
FloatHermite{ 0, 67 * FRAME_SCALE, 0, 0.67238f },
|
||||
FloatHermite{ 2, 70 * FRAME_SCALE, -0.001741f, -0.664096f },
|
||||
FloatHermite{ 0, 73 * FRAME_SCALE, 0, 0 },
|
||||
};
|
||||
static std::array g_flashColor =
|
||||
{
|
||||
FloatLinear{ 255.0f, 67 * FRAME_SCALE },
|
||||
FloatLinear{ 160.0f, 70 * FRAME_SCALE },
|
||||
FloatLinear{ 255.0f, 73 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_flashAlpha =
|
||||
{
|
||||
FloatLinear{ 255.0f, 70 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 73 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseScale =
|
||||
{
|
||||
FloatLinear{ 0.0f, 70 * FRAME_SCALE },
|
||||
FloatLinear{ 1.0f, 75 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseTL_gradTL =
|
||||
{
|
||||
FloatLinear{ 0.0f, 77 * FRAME_SCALE },
|
||||
FloatLinear{ (192 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 90 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseTL_gradBL =
|
||||
{
|
||||
FloatLinear{ 0.0f, 73 * FRAME_SCALE },
|
||||
FloatLinear{ (223 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 94 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseTL_gradTR =
|
||||
{
|
||||
FloatLinear{ 0.0f, 74 * FRAME_SCALE },
|
||||
FloatLinear{ (223 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 93 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseTL_gradBR =
|
||||
{
|
||||
FloatLinear{ 0.0f, 70 * FRAME_SCALE },
|
||||
FloatLinear{ 1.0f, 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 97 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseTR_gradTL =
|
||||
{
|
||||
FloatLinear{ 0.0f, 74 * FRAME_SCALE },
|
||||
FloatLinear{ (223 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 93 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseTR_gradBL =
|
||||
{
|
||||
FloatLinear{ 0.0f, 70 * FRAME_SCALE },
|
||||
FloatLinear{ 1.0f, 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 97 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseTR_gradTR =
|
||||
{
|
||||
FloatLinear{ 0.0f, 77 * FRAME_SCALE },
|
||||
FloatLinear{ (192 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 90 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseTR_gradBR =
|
||||
{
|
||||
FloatLinear{ 0.0f, 73 * FRAME_SCALE },
|
||||
FloatLinear{ (223 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 94 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseBL_gradTL =
|
||||
{
|
||||
FloatLinear{ 0.0f, 73 * FRAME_SCALE },
|
||||
FloatLinear{ (223 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 94 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseBL_gradBL =
|
||||
{
|
||||
FloatLinear{ 0.0f, 77 * FRAME_SCALE },
|
||||
FloatLinear{ (192 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 90 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseBL_gradTR =
|
||||
{
|
||||
FloatLinear{ 0.0f, 70 * FRAME_SCALE },
|
||||
FloatLinear{ 1.0f, 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 97 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseBL_gradBR =
|
||||
{
|
||||
FloatLinear{ 0.0f, 74 * FRAME_SCALE },
|
||||
FloatLinear{ (223 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 93 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseBR_gradTL =
|
||||
{
|
||||
FloatLinear{ 0.0f, 70 * FRAME_SCALE },
|
||||
FloatLinear{ 1.0f, 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 97 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseBR_gradBL =
|
||||
{
|
||||
FloatLinear{ 0.0f, 74 * FRAME_SCALE },
|
||||
FloatLinear{ (223 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 93 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseBR_gradTR =
|
||||
{
|
||||
FloatLinear{ 0.0f, 73 * FRAME_SCALE },
|
||||
FloatLinear{ (223 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 94 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_noiseBR_gradBR =
|
||||
{
|
||||
FloatLinear{ 0.0f, 77 * FRAME_SCALE },
|
||||
FloatLinear{ (192 / 255.0f), 85 * FRAME_SCALE },
|
||||
FloatLinear{ 0.0f, 90 * FRAME_SCALE },
|
||||
};
|
||||
static std::array g_thumbnailAlpha =
|
||||
{
|
||||
FloatLinear{ 0.0f, 85 * FRAME_SCALE },
|
||||
FloatLinear{ 1.0f, 90 * FRAME_SCALE },
|
||||
};
|
||||
|
||||
static std::pair<ImVec2, ImVec2> ComputeRect(const ImVec2& center, const ImVec2& scale)
|
||||
{
|
||||
ImVec2 min = { center.x - scale.x / 2.0f, center.y - scale.y / 2.0f };
|
||||
ImVec2 max = { center.x + scale.x / 2.0f, center.y + scale.y / 2.0f };
|
||||
|
||||
return std::make_pair(min, max);
|
||||
}
|
||||
|
||||
static void DrawFlash(const ImVec2& center, const ImVec2& resolution, float time)
|
||||
{
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
float baseScale = resolution.y / 135.0f * 100.0f;
|
||||
auto [min, max] = ComputeRect(center, { Sample(g_flashScaleX, time) * baseScale, Sample(g_flashScaleY, time) * baseScale});
|
||||
|
||||
float color = Sample(g_flashColor, time);
|
||||
float alpha = Sample(g_flashAlpha, time);
|
||||
|
||||
drawList->AddImage(g_flashTexture.get(), min, max, { 0.0f, 0.0f }, { 1.0f, 1.0f }, IM_COL32(color, 255, color, alpha));
|
||||
}
|
||||
|
||||
static void PrimRectUVColorCorners(ImDrawList* This, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max,
|
||||
ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left, bool reverse_order = false)
|
||||
{
|
||||
ImVec2 a(p_min), c(p_max), uv_a(uv_min), uv_c(uv_max);
|
||||
ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y);
|
||||
|
||||
if (reverse_order)
|
||||
{
|
||||
ImVec2 _a = a; a = b; b = _a;
|
||||
ImVec2 _c = c; c = d; d = _c;
|
||||
|
||||
ImVec2 _uv_a = uv_a; uv_a = uv_b; uv_b = _uv_a;
|
||||
ImVec2 _uv_c = uv_c; uv_c = uv_d; uv_d = _uv_c;
|
||||
}
|
||||
|
||||
ImDrawIdx idx = (ImDrawIdx)This->_VtxCurrentIdx;
|
||||
This->_IdxWritePtr[0] = idx; This->_IdxWritePtr[1] = (ImDrawIdx)(idx + 1); This->_IdxWritePtr[2] = (ImDrawIdx)(idx + 2);
|
||||
This->_IdxWritePtr[3] = idx; This->_IdxWritePtr[4] = (ImDrawIdx)(idx + 2); This->_IdxWritePtr[5] = (ImDrawIdx)(idx + 3);
|
||||
This->_VtxWritePtr[0].pos = a; This->_VtxWritePtr[0].uv = uv_a; This->_VtxWritePtr[0].col = reverse_order ? col_upr_right : col_upr_left;
|
||||
This->_VtxWritePtr[1].pos = b; This->_VtxWritePtr[1].uv = uv_b; This->_VtxWritePtr[1].col = reverse_order ? col_upr_left : col_upr_right;
|
||||
This->_VtxWritePtr[2].pos = c; This->_VtxWritePtr[2].uv = uv_c; This->_VtxWritePtr[2].col = reverse_order ? col_bot_left : col_bot_right;
|
||||
This->_VtxWritePtr[3].pos = d; This->_VtxWritePtr[3].uv = uv_d; This->_VtxWritePtr[3].col = reverse_order ? col_bot_right : col_bot_left;
|
||||
This->_VtxWritePtr += 4;
|
||||
This->_VtxCurrentIdx += 4;
|
||||
This->_IdxWritePtr += 6;
|
||||
}
|
||||
|
||||
static void AddImageGradient(ImDrawList* DrawList, ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max,
|
||||
ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left, bool reverse_order = false)
|
||||
{
|
||||
if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
const bool push_texture_id = user_texture_id && (user_texture_id != DrawList->_CmdHeader.TextureId);
|
||||
if (push_texture_id)
|
||||
DrawList->PushTextureID(user_texture_id);
|
||||
|
||||
DrawList->PrimReserve(6, 4);
|
||||
|
||||
const ImVec2 uv = DrawList->_Data->TexUvWhitePixel;
|
||||
|
||||
PrimRectUVColorCorners(DrawList, p_min, p_max,
|
||||
user_texture_id ? uv_min : uv,
|
||||
user_texture_id ? uv_max : uv,
|
||||
col_upr_left, col_upr_right, col_bot_right, col_bot_left,
|
||||
reverse_order);
|
||||
|
||||
if (push_texture_id)
|
||||
DrawList->PopTextureID();
|
||||
}
|
||||
|
||||
static void DrawStatic(const ImVec2& center, const ImVec2& resolution, float time)
|
||||
{
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
const float scaleFactor = Sample(g_noiseScale, time);
|
||||
|
||||
const ImVec2 scale2D = { 1, scaleFactor };
|
||||
|
||||
auto [min, max] = ComputeRect(center, {scale2D.x * resolution.x, scale2D.y * resolution.y});
|
||||
|
||||
// Texture pixel size divided by image resolution (which must be divisible by 4) to get proper UV clipping.
|
||||
ImVec2 UV_MAX = { 270.0f / 272.0f,
|
||||
135.0f / 136.0f };
|
||||
|
||||
// Corner points
|
||||
|
||||
ImVec2 topCenter = { center.x, min.y };
|
||||
ImVec2 bottomCenter = { center.x, max.y };
|
||||
|
||||
ImVec2 centerLeft = { min.x, center.y };
|
||||
ImVec2 centerRight = { max.x, center.y };
|
||||
|
||||
bool flipUV = time >= (73 * FRAME_SCALE);
|
||||
|
||||
const float UV_1 = flipUV ? 0.0f : 1.0f;
|
||||
const float UV_0 = flipUV ? 1.0f : 0.0f;
|
||||
|
||||
// Top Left
|
||||
AddImageGradient(
|
||||
drawList,
|
||||
g_noiseTexture.get(),
|
||||
min,
|
||||
center,
|
||||
ImVec2(UV_0 * UV_MAX.x, 0.0f * UV_MAX.y),
|
||||
ImVec2(0.5f * UV_MAX.x, 0.5f * UV_MAX.y),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseTL_gradTL, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseTL_gradTR, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseTL_gradBR, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseTL_gradBL, time)),
|
||||
true);
|
||||
|
||||
// Top Right
|
||||
AddImageGradient(
|
||||
drawList,
|
||||
g_noiseTexture.get(),
|
||||
topCenter,
|
||||
centerRight,
|
||||
ImVec2(0.5f * UV_MAX.x, 0.0f * UV_MAX.y),
|
||||
ImVec2(UV_1 * UV_MAX.x, 0.5f * UV_MAX.y),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseTR_gradTL, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseTR_gradTR, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseTR_gradBR, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseTR_gradBL, time)),
|
||||
true);
|
||||
|
||||
// Bottom Right
|
||||
AddImageGradient(
|
||||
drawList,
|
||||
g_noiseTexture.get(),
|
||||
center,
|
||||
max,
|
||||
ImVec2(0.5f * UV_MAX.x, 0.5f * UV_MAX.y),
|
||||
ImVec2(UV_1 * UV_MAX.x, 1.0f * UV_MAX.y),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseBR_gradTL, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseBR_gradTR, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseBR_gradBR, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseBR_gradBL, time)),
|
||||
true);
|
||||
|
||||
// Bottom Left
|
||||
AddImageGradient(
|
||||
drawList,
|
||||
g_noiseTexture.get(),
|
||||
centerLeft,
|
||||
bottomCenter,
|
||||
ImVec2(UV_0 * UV_MAX.x, 0.5f * UV_MAX.y),
|
||||
ImVec2(0.5f * UV_MAX.x, 1.0f * UV_MAX.y),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseBL_gradTL, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseBL_gradTR, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseBL_gradBR, time)),
|
||||
IM_COL32(255, 255, 255, 255 * Sample(g_noiseBL_gradBL, time)),
|
||||
true);
|
||||
}
|
||||
|
||||
void TVStatic::Init()
|
||||
{
|
||||
g_flashTexture = LOAD_ZSTD_TEXTURE(g_options_static_flash);
|
||||
g_noiseTexture = LOAD_ZSTD_TEXTURE(g_options_static);
|
||||
}
|
||||
|
||||
static float ComputeTime(double appearTime)
|
||||
{
|
||||
return (ImGui::GetTime() - appearTime) + FRAME_OFFSET * FRAME_SCALE;
|
||||
}
|
||||
|
||||
float TVStatic::ComputeThumbnailAlpha(double appearTime)
|
||||
{
|
||||
return Sample(g_thumbnailAlpha, ComputeTime(appearTime));
|
||||
}
|
||||
|
||||
void TVStatic::Draw(const ImVec2& center, const ImVec2& resolution, double appearTime)
|
||||
{
|
||||
float time = ComputeTime(appearTime);
|
||||
|
||||
DrawStatic(center, resolution, time);
|
||||
DrawFlash(center, resolution, time);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
struct TVStatic
|
||||
{
|
||||
static void Init();
|
||||
static float ComputeThumbnailAlpha(double appearTime);
|
||||
static void Draw(const ImVec2& center, const ImVec2& resolution, double appearTime);
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "config.h"
|
||||
#include <os/logger.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/paths.h>
|
||||
#include <exports.h>
|
||||
|
||||
std::vector<IConfigDef*> g_configDefinitions;
|
||||
|
||||
@@ -302,6 +302,7 @@ CONFIG_DEFINE_ENUM_TEMPLATE(EVoiceLanguage)
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EGraphicsAPI)
|
||||
{
|
||||
{ "Auto", EGraphicsAPI::Auto },
|
||||
#ifdef UNLEASHED_RECOMP_D3D12
|
||||
{ "D3D12", EGraphicsAPI::D3D12 },
|
||||
#endif
|
||||
@@ -406,11 +407,6 @@ CONFIG_DEFINE_ENUM_TEMPLATE(EUIAlignmentMode)
|
||||
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
|
||||
@@ -447,13 +443,6 @@ ConfigDef<T, isHidden>::ConfigDef(std::string section, std::string name, CONFIG_
|
||||
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;
|
||||
|
||||
@@ -472,7 +461,7 @@ void ConfigDef<T, isHidden>::ReadValue(toml::v3::ex::parse_result& toml)
|
||||
|
||||
if constexpr (std::is_same<T, std::string>::value)
|
||||
{
|
||||
Value = section[Name].value_or<std::string>(DefaultValue);
|
||||
Value = section[Name].value_or(DefaultValue);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<T>)
|
||||
{
|
||||
@@ -722,8 +711,54 @@ std::filesystem::path Config::GetConfigPath()
|
||||
return GetUserPath() / "config.toml";
|
||||
}
|
||||
|
||||
void Config::CreateCallbacks()
|
||||
{
|
||||
Config::WindowSize.LockCallback = [](ConfigDef<int32_t>* def)
|
||||
{
|
||||
// Try matching the current window size with a known configuration.
|
||||
if (def->Value < 0)
|
||||
def->Value = GameWindow::FindNearestDisplayMode();
|
||||
};
|
||||
|
||||
Config::WindowSize.ApplyCallback = [](ConfigDef<int32_t>* def)
|
||||
{
|
||||
auto displayModes = GameWindow::GetDisplayModes();
|
||||
|
||||
// Use largest supported resolution if overflowed.
|
||||
if (def->Value >= displayModes.size())
|
||||
def->Value = displayModes.size() - 1;
|
||||
|
||||
auto& mode = displayModes[def->Value];
|
||||
auto centre = SDL_WINDOWPOS_CENTERED_DISPLAY(GameWindow::GetDisplay());
|
||||
|
||||
GameWindow::SetDimensions(mode.w, mode.h, centre, centre);
|
||||
};
|
||||
|
||||
Config::Monitor.Callback = [](ConfigDef<int32_t>* def)
|
||||
{
|
||||
GameWindow::SetDisplay(def->Value);
|
||||
};
|
||||
|
||||
Config::Fullscreen.Callback = [](ConfigDef<bool>* def)
|
||||
{
|
||||
GameWindow::SetFullscreen(def->Value);
|
||||
GameWindow::SetDisplay(Config::Monitor);
|
||||
};
|
||||
|
||||
Config::ResolutionScale.Callback = [](ConfigDef<float>* def)
|
||||
{
|
||||
def->Value = std::clamp(def->Value, 0.25f, 2.0f);
|
||||
};
|
||||
}
|
||||
|
||||
void Config::Load()
|
||||
{
|
||||
if (!s_isCallbacksCreated)
|
||||
{
|
||||
CreateCallbacks();
|
||||
s_isCallbacksCreated = true;
|
||||
}
|
||||
|
||||
auto configPath = GetConfigPath();
|
||||
|
||||
if (!std::filesystem::exists(configPath))
|
||||
@@ -757,6 +792,8 @@ void Config::Load()
|
||||
|
||||
void Config::Save()
|
||||
{
|
||||
LOGN("Saving configuration...");
|
||||
|
||||
auto userPath = GetUserPath();
|
||||
|
||||
if (!std::filesystem::exists(userPath))
|
||||
|
||||
@@ -25,6 +25,10 @@ public:
|
||||
#define CONFIG_LOCALE std::unordered_map<ELanguage, std::tuple<std::string, std::string>>
|
||||
#define CONFIG_ENUM_LOCALE(type) std::unordered_map<ELanguage, std::unordered_map<type, std::tuple<std::string, std::string>>>
|
||||
|
||||
#define CONFIG_CALLBACK(name) if (name.Callback) name.Callback(&name)
|
||||
#define CONFIG_LOCK_CALLBACK(name) if (name.LockCallback) name.LockCallback(&name)
|
||||
#define CONFIG_APPLY_CALLBACK(name) if (name.ApplyCallback) name.ApplyCallback(&name)
|
||||
|
||||
#define WINDOWPOS_CENTRED 0x2FFF0000
|
||||
|
||||
extern std::vector<IConfigDef*> g_configDefinitions;
|
||||
@@ -62,6 +66,7 @@ enum class EChannelConfiguration : uint32_t
|
||||
|
||||
enum class EGraphicsAPI : uint32_t
|
||||
{
|
||||
Auto,
|
||||
#ifdef UNLEASHED_RECOMP_D3D12
|
||||
D3D12,
|
||||
#endif
|
||||
@@ -173,9 +178,6 @@ public:
|
||||
// CONFIG_DEFINE_ENUM_LOCALISED
|
||||
ConfigDef(std::string section, std::string name, CONFIG_LOCALE* nameLocale, T defaultValue, std::unordered_map<std::string, T>* enumTemplate, CONFIG_ENUM_LOCALE(T)* enumLocale);
|
||||
|
||||
// CONFIG_DEFINE_CALLBACK
|
||||
ConfigDef(std::string section, std::string name, T defaultValue, std::function<void(ConfigDef<T, isHidden>*)> callback);
|
||||
|
||||
ConfigDef(const ConfigDef&) = delete;
|
||||
ConfigDef(ConfigDef&&) = delete;
|
||||
~ConfigDef();
|
||||
@@ -220,15 +222,17 @@ public:
|
||||
#define CONFIG_DEFINE_LOCALISED(section, type, name, defaultValue) CONFIG_DECLARE(type, name)
|
||||
#define CONFIG_DEFINE_ENUM(section, type, name, defaultValue) CONFIG_DECLARE(type, name)
|
||||
#define CONFIG_DEFINE_ENUM_LOCALISED(section, type, name, defaultValue) CONFIG_DECLARE(type, name)
|
||||
#define CONFIG_DEFINE_CALLBACK(section, type, name, defaultValue, readCallback) CONFIG_DECLARE(type, name)
|
||||
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
#include "config_def.h"
|
||||
|
||||
static inline bool s_isCallbacksCreated;
|
||||
|
||||
static std::filesystem::path GetConfigPath();
|
||||
|
||||
static void CreateCallbacks();
|
||||
static void Load();
|
||||
static void Save();
|
||||
};
|
||||
|
||||
@@ -46,45 +46,22 @@ CONFIG_DEFINE_ENUM_LOCALISED("Audio", EChannelConfiguration, ChannelConfiguratio
|
||||
CONFIG_DEFINE_LOCALISED("Audio", bool, MusicAttenuation, false);
|
||||
CONFIG_DEFINE_LOCALISED("Audio", bool, BattleTheme, true);
|
||||
|
||||
#ifdef UNLEASHED_RECOMP_D3D12
|
||||
CONFIG_DEFINE_ENUM("Video", EGraphicsAPI, GraphicsAPI, EGraphicsAPI::D3D12);
|
||||
#else
|
||||
CONFIG_DEFINE_ENUM("Video", EGraphicsAPI, GraphicsAPI, EGraphicsAPI::Vulkan);
|
||||
#endif
|
||||
|
||||
CONFIG_DEFINE("Video", std::string, GraphicsDevice, "");
|
||||
CONFIG_DEFINE_ENUM("Video", EGraphicsAPI, GraphicsAPI, EGraphicsAPI::Auto);
|
||||
CONFIG_DEFINE("Video", int32_t, WindowX, WINDOWPOS_CENTRED);
|
||||
CONFIG_DEFINE("Video", int32_t, WindowY, WINDOWPOS_CENTRED);
|
||||
CONFIG_DEFINE_LOCALISED("Video", int32_t, WindowSize, -1);
|
||||
CONFIG_DEFINE("Video", int32_t, WindowWidth, 1280);
|
||||
CONFIG_DEFINE("Video", int32_t, WindowHeight, 720);
|
||||
CONFIG_DEFINE_ENUM("Video", EWindowState, WindowState, EWindowState::Normal);
|
||||
|
||||
CONFIG_DEFINE_CALLBACK("Video", int32_t, Monitor, 0,
|
||||
{
|
||||
def->Locale = &g_Monitor_locale;
|
||||
|
||||
Window_SetDisplay(def->Value);
|
||||
});
|
||||
|
||||
CONFIG_DEFINE_LOCALISED("Video", int32_t, Monitor, 0);
|
||||
CONFIG_DEFINE_ENUM_LOCALISED("Video", EAspectRatio, AspectRatio, EAspectRatio::Auto);
|
||||
|
||||
CONFIG_DEFINE_CALLBACK("Video", float, ResolutionScale, 1.0f,
|
||||
{
|
||||
def->Locale = &g_ResolutionScale_locale;
|
||||
def->Value = std::clamp(def->Value, 0.25f, 2.0f);
|
||||
});
|
||||
|
||||
CONFIG_DEFINE_CALLBACK("Video", bool, Fullscreen, true,
|
||||
{
|
||||
def->Locale = &g_Fullscreen_locale;
|
||||
|
||||
Window_SetFullscreen(def->Value);
|
||||
Window_SetDisplay(Monitor);
|
||||
});
|
||||
|
||||
CONFIG_DEFINE_LOCALISED("Video", float, ResolutionScale, 1.0f);
|
||||
CONFIG_DEFINE_LOCALISED("Video", bool, Fullscreen, true);
|
||||
CONFIG_DEFINE_LOCALISED("Video", bool, VSync, true);
|
||||
CONFIG_DEFINE_ENUM("Video", ETripleBuffering, TripleBuffering, ETripleBuffering::Auto);
|
||||
CONFIG_DEFINE_LOCALISED("Video", int32_t, FPS, 60);
|
||||
CONFIG_DEFINE("Video", bool, ShowFPS, false);
|
||||
CONFIG_DEFINE("Video", uint32_t, MaxFrameLatency, 2);
|
||||
CONFIG_DEFINE_LOCALISED("Video", float, Brightness, 0.5f);
|
||||
CONFIG_DEFINE_ENUM_LOCALISED("Video", EAntiAliasing, AntiAliasing, EAntiAliasing::MSAA4x);
|
||||
@@ -98,15 +75,21 @@ CONFIG_DEFINE_LOCALISED("Video", bool, XboxColorCorrection, false);
|
||||
CONFIG_DEFINE_ENUM_LOCALISED("Video", ECutsceneAspectRatio, CutsceneAspectRatio, ECutsceneAspectRatio::Original);
|
||||
CONFIG_DEFINE_ENUM_LOCALISED("Video", EUIAlignmentMode, UIAlignmentMode, EUIAlignmentMode::Edge);
|
||||
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, AllowCancellingUnleash, false);
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, DisableAutoSaveWarning, false);
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, DisableDLCIcon, false);
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, DisableDWMRoundedCorners, false);
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, FixUnleashOutOfControlDrain, false);
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, HomingAttackOnBoost, true);
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, HUDToggleHotkey, false);
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, SaveScoreAtCheckpoints, false);
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, SkipIntroLogos, false);
|
||||
CONFIG_DEFINE_HIDDEN("Exports", bool, UseOfficialTitleOnTitleBar, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, AllowCancellingUnleash, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableAutoSaveWarning, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableDLCIcon, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableDWMRoundedCorners, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableEventCollisionDebugView, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableGIMipLevelDebugView, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableObjectCollisionDebugView, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableStageCollisionDebugView, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, FixEggmanlandUsingEventGalleryTransition, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, FixUnleashOutOfControlDrain, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, HomingAttackOnJump, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, HUDToggleKey, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, SaveScoreAtCheckpoints, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, SkipIntroLogos, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, UseArrowsForTimeOfDayTransition, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, UseOfficialTitleOnTitleBar, false);
|
||||
|
||||
CONFIG_DEFINE("Update", time_t, LastChecked, 0);
|
||||
|
||||
@@ -116,6 +116,66 @@ name = "DisableHintsMidAsmHook"
|
||||
address = 0x827A2E34
|
||||
jump_address_on_true = 0x827A2E4C
|
||||
|
||||
# Disable Egg Dragoon hint "V_WHG_083" ("That lit-up part on the bottom looks fishy. I'll try aiming for that.")
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x82AA3224
|
||||
jump_address_on_true = 0x82AA3228
|
||||
|
||||
# Disable Egg Dragoon hint "V_CHP_057" ("That green round thing looks suspicious! Give it a bonk, Sonic!")
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x82AB1A00
|
||||
jump_address_on_true = 0x82AB1A04
|
||||
|
||||
# Disable Dark Moray hints
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x829F7538
|
||||
jump_address_on_true = 0x829F753C
|
||||
|
||||
# Disable Dark Moray hint "snow_boss_01" ("Ack, Sonic! You're frozen! Move the left stick left and right quickly to break free!")
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x829F7C90
|
||||
jump_address_on_true = 0x829F7C94
|
||||
|
||||
# Disable Dark Guardian hint "V_CHP_051" ("Ooh, ooh! Sonic! What if you took the boxes over to the blue place!")
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x82A33008
|
||||
jump_address_on_true = 0x82A33054
|
||||
|
||||
# Disable Dark Guardian hint "V_CHP_055" ("Looks like those annoying nightmares stay gone for a while if you clear 'em out!")
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x82A1DE14
|
||||
jump_address_on_true = 0x82A1DE34
|
||||
|
||||
# Disable Dark Guardian hint "V_WHG_076" ("I keep beating him down and he gets right back up! There's gotta be a better way.")
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x82A260D8
|
||||
jump_address_on_true = 0x82A26198
|
||||
|
||||
# Disable Dark Guardian hint "V_WHG_078" ("Looks like I can push this box thing.")
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x82A2F934
|
||||
jump_address_on_true = 0x82A2F94C
|
||||
|
||||
# Disable Dark Gaia Phoenix hint "V_WHG_070" ("Ngh! Looks like I can't get at it while it's covered in fire...")
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x829D2388
|
||||
jump_address_on_true = 0x829D238C
|
||||
|
||||
# Disable Dark Gaia Phoenix hint "V_WHG_071" ("Looks like he runs out of breath eventually. That's my chance.")
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x829E409C
|
||||
jump_address_on_true = 0x829E40A0
|
||||
|
||||
# Disable navigation volumes
|
||||
[[midasm_hook]]
|
||||
name = "DisableControlTutorialMidAsmHook"
|
||||
@@ -355,6 +415,11 @@ name = "WerehogBattleMusicMidAsmHook"
|
||||
address = 0x82B47728
|
||||
registers = ["r11"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "WerehogBattleMusicMidAsmHook"
|
||||
address = 0x82B47C58
|
||||
registers = ["r11"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "MotionBlurMidAsmHook"
|
||||
address = 0x82BA99D0
|
||||
@@ -522,11 +587,6 @@ address = 0x824B08C0
|
||||
registers = ["r3"]
|
||||
return_on_true = true
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "ToggleSubtitlesMidAsmHook"
|
||||
address = 0x82B9BB74
|
||||
registers = ["r27"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "AchievementManagerUnlockMidAsmHook"
|
||||
address = 0x82BCFF28
|
||||
@@ -662,6 +722,12 @@ name = "PostureDPadSupportXMidAsmHook"
|
||||
address = 0x8266B6AC
|
||||
registers = ["r29", "f0"]
|
||||
|
||||
# SWA::Player::CSonicStateStompingLand
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportMidAsmHook"
|
||||
address = 0x8231F824
|
||||
registers = ["r29", "f12", "f13"]
|
||||
|
||||
# SWA::Boss::Temple::CTemple (shared)
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportMidAsmHook"
|
||||
@@ -680,6 +746,12 @@ name = "PostureDPadSupportMidAsmHook"
|
||||
address = 0x82A7B288
|
||||
registers = ["r30", "f13", "f10"]
|
||||
|
||||
# SWA::Boss::Temple::CTempleStateBoost / SWA::Boss::Temple::CTempleStateDamage / SWA::Boss::Temple::CTempleStateGuard
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportXMidAsmHook"
|
||||
address = 0x82A72358
|
||||
registers = ["r30", "f13"]
|
||||
|
||||
# SWA::Player::CSuperSonicPostureInputSpaceHurrier
|
||||
[[midasm_hook]]
|
||||
name = "PostureSpaceHurrierDPadSupportXMidAsmHook"
|
||||
@@ -817,6 +889,12 @@ name = "AddPrimitive2DMidAsmHook"
|
||||
address = 0x82581C2C
|
||||
registers = ["r3"]
|
||||
|
||||
# Shop
|
||||
[[midasm_hook]]
|
||||
name = "AddPrimitive2DMidAsmHook"
|
||||
address = 0x82B2BCD8
|
||||
registers = ["r3"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "ObjGetItemFieldOfViewMidAsmHook"
|
||||
address = 0x82692934
|
||||
@@ -957,3 +1035,24 @@ registers = ["r3"]
|
||||
name = "EvilHudGuideUpdateMidAsmHook"
|
||||
address = 0x82449800
|
||||
registers = ["r30", "f30"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "SparkleLocusMidAsmHook"
|
||||
address = 0x82E96804
|
||||
jump_address_on_true = 0x82E96808
|
||||
|
||||
# Rooftop Run barrel fix (works at up to ~400 FPS)
|
||||
[[midasm_hook]]
|
||||
name = "HighFrameRateDeltaTimeFixVectorMidAsmHook"
|
||||
address = 0x827673CC
|
||||
registers = ["v62"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "BossEggDragoonDrillMissileCMissileSetRotationMidAsmHook"
|
||||
address = 0x82A9BADC
|
||||
registers = ["r4"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "AnimationDataMakeMidAsmHook"
|
||||
address = 0x82BB38E4
|
||||
registers = ["r31", "r29", "r28"]
|
||||
|
||||
+1
-1
Submodule UnleashedRecompResources updated: 3a852c76e5...5ba3baac5a
Reference in New Issue
Block a user