mirror of
https://github.com/hedge-dev/UnleashedRecomp
synced 2026-06-09 04:40:26 -04:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f32e2495f | |||
| 0aa1a256dd |
@@ -7,6 +7,9 @@
|
|||||||
[submodule "tools/XenosRecomp"]
|
[submodule "tools/XenosRecomp"]
|
||||||
path = tools/XenosRecomp
|
path = tools/XenosRecomp
|
||||||
url = https://github.com/hedge-dev/XenosRecomp.git
|
url = https://github.com/hedge-dev/XenosRecomp.git
|
||||||
|
[submodule "thirdparty/libmspack"]
|
||||||
|
path = thirdparty/libmspack
|
||||||
|
url = https://github.com/kyz/libmspack
|
||||||
[submodule "UnleashedRecompResources"]
|
[submodule "UnleashedRecompResources"]
|
||||||
path = UnleashedRecompResources
|
path = UnleashedRecompResources
|
||||||
url = https://github.com/hedge-dev/UnleashedRecompResources.git
|
url = https://github.com/hedge-dev/UnleashedRecompResources.git
|
||||||
@@ -37,6 +40,9 @@
|
|||||||
[submodule "thirdparty/concurrentqueue"]
|
[submodule "thirdparty/concurrentqueue"]
|
||||||
path = thirdparty/concurrentqueue
|
path = thirdparty/concurrentqueue
|
||||||
url = https://github.com/cameron314/concurrentqueue.git
|
url = https://github.com/cameron314/concurrentqueue.git
|
||||||
|
[submodule "thirdparty/tiny-AES-c"]
|
||||||
|
path = thirdparty/tiny-AES-c
|
||||||
|
url = https://github.com/kokke/tiny-AES-c.git
|
||||||
[submodule "thirdparty/magic_enum"]
|
[submodule "thirdparty/magic_enum"]
|
||||||
path = thirdparty/magic_enum
|
path = thirdparty/magic_enum
|
||||||
url = https://github.com/Neargye/magic_enum.git
|
url = https://github.com/Neargye/magic_enum.git
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
```
|
```
|
||||||
git clone --recurse-submodules https://github.com/hedge-dev/UnleashedRecomp.git
|
git clone --recurse-submodules https://github.com/hedge-dev/UnleashedRecomp.git
|
||||||
```
|
```
|
||||||
2. Place `default.xex` and `default.xexp` in `./UnleashedRecompLib/private/`.
|
2. Decompress and decrypt `default.xex`, apply the title update patch (`default.xexp`), and place the resulting file in `./UnleashedRecompLib/private/`.
|
||||||
3. Decompress `shader.ar` and place the resulting file in `./UnleashedRecompLib/private/`.
|
3. Decompress `shader.ar` and place the resulting file in `./UnleashedRecompLib/private/`.
|
||||||
4. Open the repository directory in Visual Studio 2022 and wait for CMake generation to complete. If you don't plan to debug, switch to the `x64-Clang-Release` configuration.
|
4. Open the repository directory in Visual Studio 2022 and wait for CMake generation to complete. If you don't plan to debug, switch to the `x64-Clang-Release` configuration.
|
||||||
5. Under Solution Explorer, right-click and choose "Switch to CMake Targets View".
|
5. Under Solution Explorer, right-click and choose "Switch to CMake Targets View".
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ set(UNLEASHED_RECOMP_PATCHES_CXX_SOURCES
|
|||||||
"patches/CTitleStateIntro_patches.cpp"
|
"patches/CTitleStateIntro_patches.cpp"
|
||||||
"patches/CTitleStateMenu_patches.cpp"
|
"patches/CTitleStateMenu_patches.cpp"
|
||||||
"patches/fps_patches.cpp"
|
"patches/fps_patches.cpp"
|
||||||
|
"patches/free_camera_patches.cpp"
|
||||||
"patches/frontend_listener.cpp"
|
"patches/frontend_listener.cpp"
|
||||||
"patches/input_patches.cpp"
|
"patches/input_patches.cpp"
|
||||||
"patches/inspire_patches.cpp"
|
"patches/inspire_patches.cpp"
|
||||||
@@ -165,8 +166,10 @@ set(UNLEASHED_RECOMP_UI_CXX_SOURCES
|
|||||||
set(UNLEASHED_RECOMP_INSTALL_CXX_SOURCES
|
set(UNLEASHED_RECOMP_INSTALL_CXX_SOURCES
|
||||||
"install/installer.cpp"
|
"install/installer.cpp"
|
||||||
"install/iso_file_system.cpp"
|
"install/iso_file_system.cpp"
|
||||||
|
"install/memory_mapped_file.cpp"
|
||||||
"install/update_checker.cpp"
|
"install/update_checker.cpp"
|
||||||
"install/xcontent_file_system.cpp"
|
"install/xcontent_file_system.cpp"
|
||||||
|
"install/xex_patcher.cpp"
|
||||||
"install/hashes/apotos_shamar.cpp"
|
"install/hashes/apotos_shamar.cpp"
|
||||||
"install/hashes/chunnan.cpp"
|
"install/hashes/chunnan.cpp"
|
||||||
"install/hashes/empire_city_adabat.cpp"
|
"install/hashes/empire_city_adabat.cpp"
|
||||||
@@ -199,6 +202,8 @@ set(UNLEASHED_RECOMP_THIRDPARTY_SOURCES
|
|||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot.cpp"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot.cpp"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot_demo.cpp"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot_demo.cpp"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot_items.cpp"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot_items.cpp"
|
||||||
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/libmspack/libmspack/mspack/lzxd.c"
|
||||||
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/tiny-AES-c/aes.c"
|
||||||
"${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/thirdparty/smol-v/source/smolv.cpp"
|
"${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/thirdparty/smol-v/source/smolv.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -208,8 +213,11 @@ set(UNLEASHED_RECOMP_THIRDPARTY_INCLUDES
|
|||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/json/include"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/json/include"
|
||||||
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/libmspack/libmspack/mspack"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/stb"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/stb"
|
||||||
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/tiny-AES-c"
|
||||||
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/TinySHA1"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/unordered_dense/include"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/unordered_dense/include"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/volk"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/volk"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/Vulkan-Headers/include"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/Vulkan-Headers/include"
|
||||||
@@ -493,8 +501,8 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/in
|
|||||||
|
|
||||||
## Options Menu ##
|
## 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/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_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input_ps.dds" ARRAY_NAME "g_allow_background_input_ps" COMPRESSION_TYPE "zstd")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input.dds" ARRAY_NAME "g_allow_background_input" COMPRESSION_TYPE "zstd")
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input_xb.dds" ARRAY_NAME "g_allow_background_input_xb" 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_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_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_4x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" ARRAY_NAME "g_antialiasing_4x" COMPRESSION_TYPE "zstd")
|
||||||
@@ -504,8 +512,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/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/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_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/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_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/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_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/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/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")
|
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")
|
||||||
@@ -525,21 +533,23 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
|
|||||||
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/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_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/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")
|
||||||
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_original.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_original.dds" ARRAY_NAME "g_shadow_resolution_original" COMPRESSION_TYPE "zstd")
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x512.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x512.dds" ARRAY_NAME "g_shadow_resolution_x512" COMPRESSION_TYPE "zstd")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x512.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x512.dds" ARRAY_NAME "g_shadow_resolution_x512" COMPRESSION_TYPE "zstd")
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x1024.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x1024.dds" ARRAY_NAME "g_shadow_resolution_x1024" COMPRESSION_TYPE "zstd")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x1024.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x1024.dds" ARRAY_NAME "g_shadow_resolution_x1024" COMPRESSION_TYPE "zstd")
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x2048.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x2048.dds" ARRAY_NAME "g_shadow_resolution_x2048" COMPRESSION_TYPE "zstd")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x2048.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x2048.dds" ARRAY_NAME "g_shadow_resolution_x2048" COMPRESSION_TYPE "zstd")
|
||||||
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_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/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/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/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_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_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_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/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_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_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/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/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/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_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration_ps.dds" ARRAY_NAME "g_vibration_ps" 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/vibration_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration_xb.dds" ARRAY_NAME "g_vibration_xb" 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_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/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/window_size.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/window_size.dds" ARRAY_NAME "g_window_size" COMPRESSION_TYPE "zstd")
|
||||||
|
|||||||
@@ -21,3 +21,5 @@ namespace Hedgehog::Base
|
|||||||
void operator delete(void* in_pMem, void* in_pObj);
|
void operator delete(void* in_pMem, void* in_pObj);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "hhObject.inl"
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
namespace Hedgehog::Base
|
||||||
|
{
|
||||||
|
inline CObject::CObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CObject::CObject(const swa_null_ctor&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* CObject::operator new(const size_t in_Size)
|
||||||
|
{
|
||||||
|
return __HH_ALLOC(in_Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline void* CObject::operator new(const size_t in_Size, const size_t in_Align)
|
||||||
|
// {
|
||||||
|
// return __HH_ALLOCALIGN(in_Size, in_Align);
|
||||||
|
// }
|
||||||
|
|
||||||
|
inline void CObject::operator delete(void* in_pMem)
|
||||||
|
{
|
||||||
|
return __HH_FREE(in_pMem);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* CObject::operator new(const size_t in_Size, void* in_pObj)
|
||||||
|
{
|
||||||
|
return in_pObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* CObject::operator new(const size_t in_Size, const size_t in_Align, void* in_pObj)
|
||||||
|
{
|
||||||
|
return in_pObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CObject::operator delete(void* in_pMem, void* in_pObj)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,16 @@ namespace Hedgehog::Math
|
|||||||
be<float> Y;
|
be<float> Y;
|
||||||
be<float> Z;
|
be<float> Z;
|
||||||
be<float> W;
|
be<float> W;
|
||||||
|
|
||||||
|
CVector operator*(const float& scalar) const
|
||||||
|
{
|
||||||
|
return { X * scalar, Y * scalar, Z * scalar };
|
||||||
|
}
|
||||||
|
|
||||||
|
CVector operator+(const CVector& v) const
|
||||||
|
{
|
||||||
|
return { X + v.X, Y + v.Y, Z + v.Z };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CVector4
|
class CVector4
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
#include <Hedgehog/Base/hhObject.h>
|
||||||
|
#include <boost/smart_ptr/shared_ptr.h>
|
||||||
|
|
||||||
|
namespace Hedgehog::Universe
|
||||||
|
{
|
||||||
|
class Message : public Base::CObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
be<uint32_t> m_pVftable;
|
||||||
|
be<uint32_t> m_SenderActorID;
|
||||||
|
boost::shared_ptr<Message> m_spSelf;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MessageTypeGet : public Message {};
|
||||||
|
class MessageTypeSet : public Message {};
|
||||||
|
}
|
||||||
@@ -49,6 +49,7 @@
|
|||||||
#include "Hedgehog/MirageCore/RenderData/hhVertexShaderData.h"
|
#include "Hedgehog/MirageCore/RenderData/hhVertexShaderData.h"
|
||||||
#include "Hedgehog/MirageCore/Renderable/hhRenderable.h"
|
#include "Hedgehog/MirageCore/Renderable/hhRenderable.h"
|
||||||
#include "Hedgehog/Sparkle/hhParticleMaterial.h"
|
#include "Hedgehog/Sparkle/hhParticleMaterial.h"
|
||||||
|
#include "Hedgehog/Universe/Engine/hhMessage.h"
|
||||||
#include "Hedgehog/Universe/Engine/hhMessageActor.h"
|
#include "Hedgehog/Universe/Engine/hhMessageActor.h"
|
||||||
#include "Hedgehog/Universe/Engine/hhMessageProcess.h"
|
#include "Hedgehog/Universe/Engine/hhMessageProcess.h"
|
||||||
#include "Hedgehog/Universe/Engine/hhStateMachineBase.h"
|
#include "Hedgehog/Universe/Engine/hhStateMachineBase.h"
|
||||||
@@ -65,7 +66,8 @@
|
|||||||
#include "SWA/CSD/CsdTexListMirage.h"
|
#include "SWA/CSD/CsdTexListMirage.h"
|
||||||
#include "SWA/CSD/GameObjectCSD.h"
|
#include "SWA/CSD/GameObjectCSD.h"
|
||||||
#include "SWA/Camera/Camera.h"
|
#include "SWA/Camera/Camera.h"
|
||||||
#include "SWA/Camera/CameraController.h"
|
#include "SWA/Camera/Controller/CameraController.h"
|
||||||
|
#include "SWA/Camera/Controller/FreeCamera.h"
|
||||||
#include "SWA/CharacterUtility/CharacterProxy.h"
|
#include "SWA/CharacterUtility/CharacterProxy.h"
|
||||||
#include "SWA/ExtraStage/Tails/Enemy/Boss/ExStageBoss.h"
|
#include "SWA/ExtraStage/Tails/Enemy/Boss/ExStageBoss.h"
|
||||||
#include "SWA/ExtraStage/Tails/Enemy/Boss/State/StateBase.h"
|
#include "SWA/ExtraStage/Tails/Enemy/Boss/State/StateBase.h"
|
||||||
@@ -87,13 +89,20 @@
|
|||||||
#include "SWA/Inspire/InspireTextureOverlay.h"
|
#include "SWA/Inspire/InspireTextureOverlay.h"
|
||||||
#include "SWA/Inspire/InspireTextureOverlayInfo.h"
|
#include "SWA/Inspire/InspireTextureOverlayInfo.h"
|
||||||
#include "SWA/Menu/MenuWindowBase.h"
|
#include "SWA/Menu/MenuWindowBase.h"
|
||||||
|
#include "SWA/Message/MsgCameraPauseMove.h"
|
||||||
|
#include "SWA/Message/MsgPopCameraController.h"
|
||||||
|
#include "SWA/Message/MsgSetPosition.h"
|
||||||
|
#include "SWA/Message/MsgSetVelocity.h"
|
||||||
#include "SWA/Movie/MovieDisplayer.h"
|
#include "SWA/Movie/MovieDisplayer.h"
|
||||||
#include "SWA/Movie/MovieManager.h"
|
#include "SWA/Movie/MovieManager.h"
|
||||||
#include "SWA/Object/Common/DashPanel/ObjDashPanel.h"
|
#include "SWA/Object/Common/DashPanel/ObjDashPanel.h"
|
||||||
#include "SWA/Object/SonicStage/EU/RollingBarrel/ObjRollingBarrel.h"
|
#include "SWA/Object/SonicStage/EU/RollingBarrel/ObjRollingBarrel.h"
|
||||||
|
#include "SWA/Player/Character/Base/PlayerContext.h"
|
||||||
#include "SWA/Player/Character/EvilSonic/EvilSonic.h"
|
#include "SWA/Player/Character/EvilSonic/EvilSonic.h"
|
||||||
#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h"
|
#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h"
|
||||||
#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h"
|
#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h"
|
||||||
|
#include "SWA/Player/Character/Speed/PlayerSpeedContext.h"
|
||||||
|
#include "SWA/Replay/Camera/ReplayFreeCamera.h"
|
||||||
#include "SWA/Sequence/Unit/SequenceUnitBase.h"
|
#include "SWA/Sequence/Unit/SequenceUnitBase.h"
|
||||||
#include "SWA/Sequence/Unit/SequenceUnitPlayMovie.h"
|
#include "SWA/Sequence/Unit/SequenceUnitPlayMovie.h"
|
||||||
#include "SWA/Sequence/Utility/SequencePlayMovieWrapper.h"
|
#include "SWA/Sequence/Utility/SequencePlayMovieWrapper.h"
|
||||||
@@ -124,5 +133,6 @@
|
|||||||
#include "SWA/System/MatrixNodeTransform.h"
|
#include "SWA/System/MatrixNodeTransform.h"
|
||||||
#include "SWA/System/PadState.h"
|
#include "SWA/System/PadState.h"
|
||||||
#include "SWA/System/World.h"
|
#include "SWA/System/World.h"
|
||||||
|
#include "SWA/Tool/FreeCameraTool/FreeCameraTool.h"
|
||||||
#include "boost/smart_ptr/make_shared_object.h"
|
#include "boost/smart_ptr/make_shared_object.h"
|
||||||
#include "boost/smart_ptr/shared_ptr.h"
|
#include "boost/smart_ptr/shared_ptr.h"
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <SWA.inl>
|
|
||||||
|
|
||||||
namespace SWA
|
|
||||||
{
|
|
||||||
class CCameraController : public Hedgehog::Universe::CStateMachineBase::CStateBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SWA_INSERT_PADDING(0x04);
|
|
||||||
be<float> m_FieldOfView;
|
|
||||||
SWA_INSERT_PADDING(0x68);
|
|
||||||
};
|
|
||||||
|
|
||||||
SWA_ASSERT_OFFSETOF(CCameraController, m_FieldOfView, 0x64);
|
|
||||||
SWA_ASSERT_SIZEOF(CCameraController, 0xD0);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
|
||||||
|
namespace SWA
|
||||||
|
{
|
||||||
|
class CCameraController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0x08);
|
||||||
|
xpointer<CCamera> m_pCamera;
|
||||||
|
SWA_INSERT_PADDING(0x58);
|
||||||
|
be<float> m_FieldOfView;
|
||||||
|
SWA_INSERT_PADDING(0x08);
|
||||||
|
Hedgehog::Math::CVector m_Position;
|
||||||
|
Hedgehog::Math::CVector m_UpVector;
|
||||||
|
Hedgehog::Math::CQuaternion m_Rotation;
|
||||||
|
SWA_INSERT_PADDING(0x30);
|
||||||
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(CCameraController, m_pCamera, 0x08);
|
||||||
|
SWA_ASSERT_OFFSETOF(CCameraController, m_FieldOfView, 0x64);
|
||||||
|
SWA_ASSERT_SIZEOF(CCameraController, 0xD0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
#include "SWA/Camera/Controller/CameraController.h"
|
||||||
|
|
||||||
|
namespace SWA
|
||||||
|
{
|
||||||
|
class CFreeCamera : public CCameraController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0x10);
|
||||||
|
be<float> m_Speed;
|
||||||
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(CFreeCamera, m_Speed, 0xE0);
|
||||||
|
}
|
||||||
@@ -9,6 +9,9 @@ namespace SWA
|
|||||||
// ms_DrawLightFieldSamplingPoint: サンプリング点をデバッグ表示
|
// ms_DrawLightFieldSamplingPoint: サンプリング点をデバッグ表示
|
||||||
static inline bool* ms_DrawLightFieldSamplingPoint;
|
static inline bool* ms_DrawLightFieldSamplingPoint;
|
||||||
|
|
||||||
|
// N/A
|
||||||
|
static inline be<float>* ms_FreeCameraSpeed;
|
||||||
|
|
||||||
// N/A
|
// N/A
|
||||||
static inline bool* ms_IsAutoSaveWarningShown;
|
static inline bool* ms_IsAutoSaveWarningShown;
|
||||||
|
|
||||||
@@ -33,6 +36,9 @@ namespace SWA
|
|||||||
// ms_IsRenderDebugPositionDraw: デバッグ位置描画
|
// ms_IsRenderDebugPositionDraw: デバッグ位置描画
|
||||||
static inline bool* ms_IsRenderDebugPositionDraw;
|
static inline bool* ms_IsRenderDebugPositionDraw;
|
||||||
|
|
||||||
|
// N/A
|
||||||
|
static inline bool* ms_IsRenderDepthOfField;
|
||||||
|
|
||||||
// ms_IsRenderGameMainHud: ゲームメインHUD 描画
|
// ms_IsRenderGameMainHud: ゲームメインHUD 描画
|
||||||
static inline bool* ms_IsRenderGameMainHud;
|
static inline bool* ms_IsRenderGameMainHud;
|
||||||
|
|
||||||
@@ -57,6 +63,7 @@ namespace SWA
|
|||||||
static void Init()
|
static void Init()
|
||||||
{
|
{
|
||||||
ms_DrawLightFieldSamplingPoint = (bool*)MmGetHostAddress(0x83367BCE);
|
ms_DrawLightFieldSamplingPoint = (bool*)MmGetHostAddress(0x83367BCE);
|
||||||
|
ms_FreeCameraSpeed = (be<float>*)MmGetHostAddress(0x83366DF8);
|
||||||
ms_IgnoreLightFieldData = (bool*)MmGetHostAddress(0x83367BCF);
|
ms_IgnoreLightFieldData = (bool*)MmGetHostAddress(0x83367BCF);
|
||||||
ms_IsAutoSaveWarningShown = (bool*)MmGetHostAddress(0x83367BC1);
|
ms_IsAutoSaveWarningShown = (bool*)MmGetHostAddress(0x83367BC1);
|
||||||
ms_IsCollisionRender = (bool*)MmGetHostAddress(0x833678A6);
|
ms_IsCollisionRender = (bool*)MmGetHostAddress(0x833678A6);
|
||||||
@@ -65,6 +72,7 @@ namespace SWA
|
|||||||
ms_IsRenderDebugDraw = (bool*)MmGetHostAddress(0x8328BB23);
|
ms_IsRenderDebugDraw = (bool*)MmGetHostAddress(0x8328BB23);
|
||||||
ms_IsRenderDebugDrawText = (bool*)MmGetHostAddress(0x8328BB25);
|
ms_IsRenderDebugDrawText = (bool*)MmGetHostAddress(0x8328BB25);
|
||||||
ms_IsRenderDebugPositionDraw = (bool*)MmGetHostAddress(0x8328BB24);
|
ms_IsRenderDebugPositionDraw = (bool*)MmGetHostAddress(0x8328BB24);
|
||||||
|
ms_IsRenderDepthOfField = (bool*)MmGetHostAddress(0x83302720);
|
||||||
ms_IsRenderGameMainHud = (bool*)MmGetHostAddress(0x8328BB27);
|
ms_IsRenderGameMainHud = (bool*)MmGetHostAddress(0x8328BB27);
|
||||||
ms_IsRenderHud = (bool*)MmGetHostAddress(0x8328BB26);
|
ms_IsRenderHud = (bool*)MmGetHostAddress(0x8328BB26);
|
||||||
ms_IsRenderHudPause = (bool*)MmGetHostAddress(0x8328BB28);
|
ms_IsRenderHudPause = (bool*)MmGetHostAddress(0x8328BB28);
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
|
||||||
|
namespace SWA::Message
|
||||||
|
{
|
||||||
|
class MsgCameraPauseMove : public Hedgehog::Universe::MessageTypeSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0x08);
|
||||||
|
bool m_isPaused;
|
||||||
|
|
||||||
|
MsgCameraPauseMove(bool in_isPaused) : m_isPaused(in_isPaused) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(MsgCameraPauseMove, m_isPaused, 0x18);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
|
||||||
|
namespace SWA::Message
|
||||||
|
{
|
||||||
|
class MsgPopCameraController : public Hedgehog::Universe::MessageTypeSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0x08);
|
||||||
|
xpointer<CCameraController> m_pCameraController;
|
||||||
|
SWA_INSERT_PADDING(0x08);
|
||||||
|
xpointer<Hedgehog::Base::CSharedString> m_pCameraName;
|
||||||
|
be<float> m_InterpolateTime;
|
||||||
|
bool m_Field2C;
|
||||||
|
bool m_Field2D;
|
||||||
|
bool m_Field2E;
|
||||||
|
|
||||||
|
MsgPopCameraController(CCameraController* in_pCameraController, float in_interpolateTime)
|
||||||
|
: m_pCameraController(in_pCameraController), m_InterpolateTime(in_interpolateTime) {}
|
||||||
|
|
||||||
|
MsgPopCameraController(Hedgehog::Base::CSharedString* in_pCameraName, float in_interpolateTime)
|
||||||
|
: m_pCameraName(in_pCameraName), m_InterpolateTime(in_interpolateTime) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(MsgPopCameraController, m_pCameraController, 0x18);
|
||||||
|
SWA_ASSERT_OFFSETOF(MsgPopCameraController, m_pCameraName, 0x24);
|
||||||
|
SWA_ASSERT_OFFSETOF(MsgPopCameraController, m_InterpolateTime, 0x28);
|
||||||
|
SWA_ASSERT_OFFSETOF(MsgPopCameraController, m_Field2C, 0x2C);
|
||||||
|
SWA_ASSERT_OFFSETOF(MsgPopCameraController, m_Field2D, 0x2D);
|
||||||
|
SWA_ASSERT_OFFSETOF(MsgPopCameraController, m_Field2E, 0x2E);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
|
||||||
|
namespace SWA::Message
|
||||||
|
{
|
||||||
|
class MsgSetPosition : public Hedgehog::Universe::MessageTypeSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0x10);
|
||||||
|
Hedgehog::Math::CVector m_Position;
|
||||||
|
|
||||||
|
MsgSetPosition(const Hedgehog::Math::CVector& in_rPosition) : m_Position(in_rPosition) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(MsgSetPosition, m_Position, 0x20);
|
||||||
|
SWA_ASSERT_SIZEOF(MsgSetPosition, 0x30);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
|
||||||
|
namespace SWA::Message
|
||||||
|
{
|
||||||
|
class MsgSetVelocity : public Hedgehog::Universe::MessageTypeSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0x10);
|
||||||
|
Hedgehog::Math::CVector m_Velocity;
|
||||||
|
|
||||||
|
MsgSetVelocity(const Hedgehog::Math::CVector& in_rVelocity) : m_Velocity(in_rVelocity) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(MsgSetVelocity, m_Velocity, 0x20);
|
||||||
|
SWA_ASSERT_SIZEOF(MsgSetVelocity, 0x30);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
#include "boost/smart_ptr/shared_ptr.h"
|
||||||
|
|
||||||
|
namespace SWA::Player
|
||||||
|
{
|
||||||
|
class CPlayer;
|
||||||
|
|
||||||
|
class CPlayerContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0x10);
|
||||||
|
boost::shared_ptr<CMatrixNodeTransform> m_spMatrixNode;
|
||||||
|
SWA_INSERT_PADDING(0x18);
|
||||||
|
boost::anonymous_shared_ptr m_spRayCastCollision;
|
||||||
|
SWA_INSERT_PADDING(0xC8);
|
||||||
|
xpointer<CPlayer> m_pPlayer;
|
||||||
|
SWA_INSERT_PADDING(0xF8);
|
||||||
|
boost::shared_ptr<void> m_spParameter;
|
||||||
|
SWA_INSERT_PADDING(0x0C);
|
||||||
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(CPlayerContext, m_spMatrixNode, 0x10);
|
||||||
|
SWA_ASSERT_OFFSETOF(CPlayerContext, m_spRayCastCollision, 0x30);
|
||||||
|
SWA_ASSERT_OFFSETOF(CPlayerContext, m_pPlayer, 0x100);
|
||||||
|
SWA_ASSERT_OFFSETOF(CPlayerContext, m_spParameter, 0x1FC);
|
||||||
|
SWA_ASSERT_SIZEOF(CPlayerContext, 0x210);
|
||||||
|
}
|
||||||
@@ -5,19 +5,26 @@
|
|||||||
|
|
||||||
namespace SWA::Player
|
namespace SWA::Player
|
||||||
{
|
{
|
||||||
class CEvilSonicContext // : public CPlayerContext
|
class CEvilSonicContext : public CPlayerContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SWA_INSERT_PADDING(0x688);
|
SWA_INSERT_PADDING(0x478);
|
||||||
be<float> m_DarkGaiaEnergy;
|
be<float> m_DarkGaiaEnergy;
|
||||||
SWA_INSERT_PADDING(0x138);
|
SWA_INSERT_PADDING(0x138);
|
||||||
be<uint32_t> m_AnimationID;
|
be<uint32_t> m_AnimationID;
|
||||||
SWA_INSERT_PADDING(0x38);
|
SWA_INSERT_PADDING(0x38);
|
||||||
be<float> m_UnkHudGuideF32;
|
be<float> m_Field800; // Related to EvilHudGuide
|
||||||
be<uint32_t> m_UnkHudGuideU32;
|
be<uint32_t> m_Field804; // Related to EvilHudGuide
|
||||||
SWA_INSERT_PADDING(0x18);
|
SWA_INSERT_PADDING(0x18);
|
||||||
be<EGuideType> m_GuideType;
|
be<EGuideType> m_GuideType;
|
||||||
SWA_INSERT_PADDING(0xA8);
|
SWA_INSERT_PADDING(0xA8);
|
||||||
be<uint32_t> m_OutOfControlCount;
|
be<uint32_t> m_OutOfControlCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(CEvilSonicContext, m_DarkGaiaEnergy, 0x688);
|
||||||
|
SWA_ASSERT_OFFSETOF(CEvilSonicContext, m_AnimationID, 0x7C4);
|
||||||
|
SWA_ASSERT_OFFSETOF(CEvilSonicContext, m_Field800, 0x800);
|
||||||
|
SWA_ASSERT_OFFSETOF(CEvilSonicContext, m_Field804, 0x804);
|
||||||
|
SWA_ASSERT_OFFSETOF(CEvilSonicContext, m_GuideType, 0x820);
|
||||||
|
SWA_ASSERT_OFFSETOF(CEvilSonicContext, m_OutOfControlCount, 0x8CC);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
|
||||||
|
namespace SWA::Player
|
||||||
|
{
|
||||||
|
class CPlayerSpeedContext : public CPlayerContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// TODO: Hedgehog::Base::TSynchronizedPtr<CGameDocument>
|
||||||
|
static CPlayerSpeedContext* GetInstance();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "PlayerSpeedContext.inl"
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace SWA::Player
|
||||||
|
{
|
||||||
|
inline CPlayerSpeedContext* CPlayerSpeedContext::GetInstance()
|
||||||
|
{
|
||||||
|
return *(xpointer<CPlayerSpeedContext>*)MmGetHostAddress(0x83362F98);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
#include "SWA/Camera/Controller/CameraController.h"
|
||||||
|
|
||||||
|
namespace SWA
|
||||||
|
{
|
||||||
|
class CReplayFreeCamera : public CCameraController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0x90);
|
||||||
|
be<float> m_Speed;
|
||||||
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(CReplayFreeCamera, m_Speed, 0x160);
|
||||||
|
}
|
||||||
@@ -36,7 +36,9 @@ namespace SWA
|
|||||||
xpointer<CSoundAdministrator> m_pSoundAdministrator;
|
xpointer<CSoundAdministrator> m_pSoundAdministrator;
|
||||||
SWA_INSERT_PADDING(0x48);
|
SWA_INSERT_PADDING(0x48);
|
||||||
xpointer<CGeneralWindow> m_pGeneralWindow;
|
xpointer<CGeneralWindow> m_pGeneralWindow;
|
||||||
SWA_INSERT_PADDING(0xD8);
|
SWA_INSERT_PADDING(0xC0);
|
||||||
|
boost::anonymous_shared_ptr m_spPlayerSwitchManager;
|
||||||
|
SWA_INSERT_PADDING(0x10);
|
||||||
SScoreInfo m_ScoreInfo;
|
SScoreInfo m_ScoreInfo;
|
||||||
SWA_INSERT_PADDING(0x0C);
|
SWA_INSERT_PADDING(0x0C);
|
||||||
};
|
};
|
||||||
@@ -63,6 +65,7 @@ namespace SWA
|
|||||||
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_StageName, 0xAC);
|
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_StageName, 0xAC);
|
||||||
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_pSoundAdministrator, 0xB0);
|
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_pSoundAdministrator, 0xB0);
|
||||||
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_pGeneralWindow, 0xFC);
|
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_pGeneralWindow, 0xFC);
|
||||||
|
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_spPlayerSwitchManager, 0x1C0);
|
||||||
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_ScoreInfo, 0x1D8);
|
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_ScoreInfo, 0x1D8);
|
||||||
SWA_ASSERT_SIZEOF(CGameDocument::CMember, 0x230);
|
SWA_ASSERT_SIZEOF(CGameDocument::CMember, 0x230);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SWA.inl>
|
||||||
|
|
||||||
|
namespace SWA
|
||||||
|
{
|
||||||
|
class CFreeCameraTool : public CGameObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWA_INSERT_PADDING(0x04);
|
||||||
|
xpointer<CFreeCamera> m_pFreeCamera;
|
||||||
|
};
|
||||||
|
|
||||||
|
SWA_ASSERT_OFFSETOF(CFreeCameraTool, m_pFreeCamera, 0xC0);
|
||||||
|
}
|
||||||
+10
-1
@@ -5,6 +5,7 @@
|
|||||||
#include <kernel/function.h>
|
#include <kernel/function.h>
|
||||||
#include <os/process.h>
|
#include <os/process.h>
|
||||||
#include <patches/audio_patches.h>
|
#include <patches/audio_patches.h>
|
||||||
|
#include <patches/free_camera_patches.h>
|
||||||
#include <patches/inspire_patches.h>
|
#include <patches/inspire_patches.h>
|
||||||
#include <ui/game_window.h>
|
#include <ui/game_window.h>
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
@@ -60,7 +61,6 @@ PPC_FUNC(sub_822C1130)
|
|||||||
}
|
}
|
||||||
|
|
||||||
App::s_deltaTime = ctx.f1.f64;
|
App::s_deltaTime = ctx.f1.f64;
|
||||||
App::s_time += App::s_deltaTime;
|
|
||||||
|
|
||||||
// This function can also be called by the loading thread,
|
// This function can also be called by the loading thread,
|
||||||
// which SDL does not like. To prevent the OS from thinking
|
// which SDL does not like. To prevent the OS from thinking
|
||||||
@@ -74,6 +74,7 @@ PPC_FUNC(sub_822C1130)
|
|||||||
}
|
}
|
||||||
|
|
||||||
AudioPatches::Update(App::s_deltaTime);
|
AudioPatches::Update(App::s_deltaTime);
|
||||||
|
FreeCameraPatches::Update();
|
||||||
InspirePatches::Update();
|
InspirePatches::Update();
|
||||||
|
|
||||||
// Apply subtitles option.
|
// Apply subtitles option.
|
||||||
@@ -95,3 +96,11 @@ PPC_FUNC(sub_822C1130)
|
|||||||
__imp__sub_822C1130(ctx, base);
|
__imp__sub_822C1130(ctx, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SWA::CGameModeStage::CGameModeStage
|
||||||
|
PPC_FUNC_IMPL(__imp__sub_82541138);
|
||||||
|
PPC_FUNC(sub_82541138)
|
||||||
|
{
|
||||||
|
App::s_pGameModeStage = (SWA::CGameModeStage*)g_memory.Translate(ctx.r3.u32);
|
||||||
|
|
||||||
|
__imp__sub_82541138(ctx, base);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <api/SWA.h>
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
|
|
||||||
class App
|
class App
|
||||||
@@ -8,13 +9,14 @@ public:
|
|||||||
static inline bool s_isInit;
|
static inline bool s_isInit;
|
||||||
static inline bool s_isMissingDLC;
|
static inline bool s_isMissingDLC;
|
||||||
static inline bool s_isLoading;
|
static inline bool s_isLoading;
|
||||||
static inline bool s_isWerehog;
|
|
||||||
static inline bool s_isSaveDataCorrupt;
|
static inline bool s_isSaveDataCorrupt;
|
||||||
|
|
||||||
|
static inline SWA::CGameModeStage* s_pGameModeStage;
|
||||||
|
static inline SWA::Player::CEvilSonicContext* s_pEvilSonicContext;
|
||||||
|
|
||||||
static inline ELanguage s_language;
|
static inline ELanguage s_language;
|
||||||
|
|
||||||
static inline double s_deltaTime;
|
static inline double s_deltaTime;
|
||||||
static inline double s_time = 0.0; // How much time elapsed since the game started.
|
|
||||||
|
|
||||||
static void Restart(std::vector<std::string> restartArgs = {});
|
static void Restart(std::vector<std::string> restartArgs = {});
|
||||||
static void Exit();
|
static void Exit();
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include <apu/audio.h>
|
#include <apu/audio.h>
|
||||||
#include <cpu/guest_thread.h>
|
#include <cpu/guest_thread.h>
|
||||||
#include <kernel/heap.h>
|
#include <kernel/heap.h>
|
||||||
#include <os/logger.h>
|
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
|
|
||||||
static PPCFunc* g_clientCallback{};
|
static PPCFunc* g_clientCallback{};
|
||||||
@@ -30,9 +29,6 @@ static void CreateAudioDevice()
|
|||||||
g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0);
|
g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_audioDevice)
|
|
||||||
LOGFN_ERROR("Failed to open audio device: {}", SDL_GetError());
|
|
||||||
|
|
||||||
g_downMixToStereo = (obtained.channels == 2);
|
g_downMixToStereo = (obtained.channels == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,13 +36,7 @@ void XAudioInitializeSystem()
|
|||||||
{
|
{
|
||||||
SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback");
|
SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback");
|
||||||
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Unleashed Recompiled");
|
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Unleashed Recompiled");
|
||||||
|
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
|
|
||||||
{
|
|
||||||
LOGFN_ERROR("Failed to init audio subsystem: {}", SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateAudioDevice();
|
CreateAudioDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#define IMGUI_SHADER_MODIFIER_TITLE_BEVEL 8
|
#define IMGUI_SHADER_MODIFIER_TITLE_BEVEL 8
|
||||||
#define IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL 9
|
#define IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL 9
|
||||||
#define IMGUI_SHADER_MODIFIER_RECTANGLE_BEVEL 10
|
#define IMGUI_SHADER_MODIFIER_RECTANGLE_BEVEL 10
|
||||||
#define IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT 11
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
|||||||
@@ -220,8 +220,6 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
|||||||
|
|
||||||
for (size_t i = 0; i < atlas->ConfigData.size(); i++)
|
for (size_t i = 0; i < atlas->ConfigData.size(); i++)
|
||||||
{
|
{
|
||||||
double spaceAdvance = 0.0;
|
|
||||||
|
|
||||||
auto& config = atlas->ConfigData[i];
|
auto& config = atlas->ConfigData[i];
|
||||||
bool increaseSpacing = strstr(config.Name, "Seurat") != nullptr;
|
bool increaseSpacing = strstr(config.Name, "Seurat") != nullptr;
|
||||||
|
|
||||||
@@ -234,15 +232,8 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
|||||||
glyph.getQuadAtlasBounds(u0, v0, u1, v1);
|
glyph.getQuadAtlasBounds(u0, v0, u1, v1);
|
||||||
|
|
||||||
double advance = glyph.getAdvance();
|
double advance = glyph.getAdvance();
|
||||||
if (glyph.getCodepoint() == ' ')
|
if (increaseSpacing && glyph.getCodepoint() == ' ')
|
||||||
{
|
advance *= 1.5;
|
||||||
if (increaseSpacing)
|
|
||||||
{
|
|
||||||
advance *= 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
spaceAdvance = advance;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.DstFont->AddGlyph(
|
config.DstFont->AddGlyph(
|
||||||
&config,
|
&config,
|
||||||
@@ -258,39 +249,6 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
|||||||
advance);
|
advance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used as a zero-width helper for automatic line breaks.
|
|
||||||
// This is useful for languages like Japanese to separate 'words'
|
|
||||||
// so that they don't get split mid-kana by the automatic splitter.
|
|
||||||
config.DstFont->AddGlyph(
|
|
||||||
&config,
|
|
||||||
0x200B,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f);
|
|
||||||
|
|
||||||
// A duplicate of the normal width space character.
|
|
||||||
// Overrides the unicode Four-Per-Em Space character.
|
|
||||||
// This can be used to add visual spacers that are ignored
|
|
||||||
// by the automatic line splitting logic.
|
|
||||||
config.DstFont->AddGlyph(
|
|
||||||
&config,
|
|
||||||
0x2005,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
0.0f,
|
|
||||||
spaceAdvance);
|
|
||||||
|
|
||||||
config.DstFont->BuildLookupTable();
|
config.DstFont->BuildLookupTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2344,7 +2344,7 @@ namespace plume {
|
|||||||
dstWidth = rect.right - rect.left;
|
dstWidth = rect.right - rect.left;
|
||||||
dstHeight = rect.bottom - rect.top;
|
dstHeight = rect.bottom - rect.top;
|
||||||
# elif defined(SDL_VULKAN_ENABLED)
|
# elif defined(SDL_VULKAN_ENABLED)
|
||||||
SDL_GetWindowSizeInPixels(renderWindow, (int *)(&dstWidth), (int *)(&dstHeight));
|
SDL_GetWindowSize(renderWindow, (int *)(&dstWidth), (int *)(&dstHeight));
|
||||||
# elif defined(__ANDROID__)
|
# elif defined(__ANDROID__)
|
||||||
dstWidth = ANativeWindow_getWidth(renderWindow);
|
dstWidth = ANativeWindow_getWidth(renderWindow);
|
||||||
dstHeight = ANativeWindow_getHeight(renderWindow);
|
dstHeight = ANativeWindow_getHeight(renderWindow);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ struct PushConstants
|
|||||||
uint GradientBottomLeft;
|
uint GradientBottomLeft;
|
||||||
uint ShaderModifier;
|
uint ShaderModifier;
|
||||||
uint Texture2DDescriptorIndex;
|
uint Texture2DDescriptorIndex;
|
||||||
float2 DisplaySize;
|
|
||||||
float2 InverseDisplaySize;
|
float2 InverseDisplaySize;
|
||||||
float2 Origin;
|
float2 Origin;
|
||||||
float2 Scale;
|
float2 Scale;
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ float4 SampleLinear(float2 uvTexspace)
|
|||||||
|
|
||||||
float4 PixelAntialiasing(float2 uvTexspace)
|
float4 PixelAntialiasing(float2 uvTexspace)
|
||||||
{
|
{
|
||||||
if ((g_PushConstants.DisplaySize.x * g_PushConstants.InverseDisplaySize.y) >= (4.0 / 3.0))
|
if ((g_PushConstants.InverseDisplaySize.y / g_PushConstants.InverseDisplaySize.x) >= (4.0 / 3.0))
|
||||||
uvTexspace *= g_PushConstants.InverseDisplaySize.y * 720.0;
|
uvTexspace *= g_PushConstants.InverseDisplaySize.y * 720.0f;
|
||||||
else
|
else
|
||||||
uvTexspace *= g_PushConstants.InverseDisplaySize.x * 960.0;
|
uvTexspace *= g_PushConstants.InverseDisplaySize.x * 960.0f;
|
||||||
|
|
||||||
float2 seam = floor(uvTexspace + 0.5);
|
float2 seam = floor(uvTexspace + 0.5);
|
||||||
uvTexspace = (uvTexspace - seam) / fwidth(uvTexspace) + seam;
|
uvTexspace = (uvTexspace - seam) / fwidth(uvTexspace) + seam;
|
||||||
@@ -78,51 +78,6 @@ float median(float r, float g, float b)
|
|||||||
return max(min(r, g), min(max(r, g), b));
|
return max(min(r, g), min(max(r, g), b));
|
||||||
}
|
}
|
||||||
|
|
||||||
float4 SampleSdfFont(float4 color, Texture2D<float4> texture, float2 uv, float2 screenTexSize)
|
|
||||||
{
|
|
||||||
float4 textureColor = texture.Sample(g_SamplerDescriptorHeap[0], uv);
|
|
||||||
|
|
||||||
uint width, height;
|
|
||||||
texture.GetDimensions(width, height);
|
|
||||||
|
|
||||||
float pxRange = 8.0;
|
|
||||||
float2 unitRange = pxRange / float2(width, height);
|
|
||||||
float screenPxRange = max(0.5 * dot(unitRange, screenTexSize), 1.0);
|
|
||||||
|
|
||||||
float sd = median(textureColor.r, textureColor.g, textureColor.b) - 0.5;
|
|
||||||
float screenPxDistance = screenPxRange * (sd + g_PushConstants.Outline / (pxRange * 1.5));
|
|
||||||
|
|
||||||
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TITLE_BEVEL)
|
|
||||||
{
|
|
||||||
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.01)).xy;
|
|
||||||
float3 rimColor = float3(1, 0.8, 0.29);
|
|
||||||
float3 shadowColor = float3(0.84, 0.57, 0);
|
|
||||||
|
|
||||||
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
|
||||||
float3 gradient = lerp(color.rgb, cosTheta >= 0.0 ? rimColor : shadowColor, abs(cosTheta));
|
|
||||||
color.rgb = lerp(gradient, color.rgb, pow(saturate(sd + 0.77), 32.0));
|
|
||||||
}
|
|
||||||
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL)
|
|
||||||
{
|
|
||||||
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.25)).xy;
|
|
||||||
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
|
||||||
float gradient = 1.0 + cosTheta * 0.5;
|
|
||||||
color.rgb = saturate(color.rgb * gradient);
|
|
||||||
}
|
|
||||||
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TEXT_SKEW)
|
|
||||||
{
|
|
||||||
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.5)).xy;
|
|
||||||
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
|
||||||
float gradient = saturate(1.0 + cosTheta);
|
|
||||||
color.rgb = lerp(color.rgb * gradient, color.rgb, pow(saturate(sd + 0.77), 32.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
color.a *= saturate(screenPxDistance + 0.5);
|
|
||||||
color.a *= textureColor.a;
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 main(in Interpolators interpolators) : SV_Target
|
float4 main(in Interpolators interpolators) : SV_Target
|
||||||
{
|
{
|
||||||
float4 color = interpolators.Color;
|
float4 color = interpolators.Color;
|
||||||
@@ -131,50 +86,52 @@ float4 main(in Interpolators interpolators) : SV_Target
|
|||||||
if (g_PushConstants.Texture2DDescriptorIndex != 0)
|
if (g_PushConstants.Texture2DDescriptorIndex != 0)
|
||||||
{
|
{
|
||||||
Texture2D<float4> texture = g_Texture2DDescriptorHeap[g_PushConstants.Texture2DDescriptorIndex & 0x7FFFFFFF];
|
Texture2D<float4> texture = g_Texture2DDescriptorHeap[g_PushConstants.Texture2DDescriptorIndex & 0x7FFFFFFF];
|
||||||
|
float4 textureColor = texture.Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
|
||||||
|
|
||||||
if ((g_PushConstants.Texture2DDescriptorIndex & 0x80000000) != 0)
|
if ((g_PushConstants.Texture2DDescriptorIndex & 0x80000000) != 0)
|
||||||
{
|
{
|
||||||
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT)
|
uint width, height;
|
||||||
|
texture.GetDimensions(width, height);
|
||||||
|
|
||||||
|
float pxRange = 8.0;
|
||||||
|
float2 unitRange = pxRange / float2(width, height);
|
||||||
|
float2 screenTexSize = 1.0 / fwidth(interpolators.UV);
|
||||||
|
float screenPxRange = max(0.5 * dot(unitRange, screenTexSize), 1.0);
|
||||||
|
|
||||||
|
float sd = median(textureColor.r, textureColor.g, textureColor.b) - 0.5;
|
||||||
|
float screenPxDistance = screenPxRange * (sd + g_PushConstants.Outline / (pxRange * 2.0));
|
||||||
|
|
||||||
|
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TITLE_BEVEL)
|
||||||
{
|
{
|
||||||
float scale;
|
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.01)).xy;
|
||||||
float invScale;
|
float3 rimColor = float3(1, 0.8, 0.29);
|
||||||
|
float3 shadowColor = float3(0.84, 0.57, 0);
|
||||||
|
|
||||||
if ((g_PushConstants.DisplaySize.x * g_PushConstants.InverseDisplaySize.y) >= (4.0 / 3.0))
|
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
||||||
{
|
float3 gradient = lerp(color.rgb, cosTheta >= 0.0 ? rimColor : shadowColor, abs(cosTheta));
|
||||||
scale = g_PushConstants.InverseDisplaySize.y * 720.0;
|
color.rgb = lerp(gradient, color.rgb, pow(saturate(sd + 0.8), 32.0));
|
||||||
invScale = g_PushConstants.DisplaySize.y / 720.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scale = g_PushConstants.InverseDisplaySize.x * 960.0;
|
|
||||||
invScale = g_PushConstants.DisplaySize.x / 960.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float2 lowQualityPosition = (interpolators.Position.xy - 0.5) * scale;
|
|
||||||
float2 fracPart = frac(lowQualityPosition);
|
|
||||||
|
|
||||||
float2 uvStep = fwidth(interpolators.UV) * invScale;
|
|
||||||
float2 lowQualityUV = interpolators.UV - fracPart * uvStep;
|
|
||||||
float2 screenTexSize = 1.0 / uvStep;
|
|
||||||
|
|
||||||
float4 topLeft = SampleSdfFont(color, texture, lowQualityUV + float2(0, 0), screenTexSize);
|
|
||||||
float4 topRight = SampleSdfFont(color, texture, lowQualityUV + float2(uvStep.x, 0), screenTexSize);
|
|
||||||
float4 bottomLeft = SampleSdfFont(color, texture, lowQualityUV + float2(0, uvStep.y), screenTexSize);
|
|
||||||
float4 bottomRight = SampleSdfFont(color, texture, lowQualityUV + uvStep.xy, screenTexSize);
|
|
||||||
|
|
||||||
float4 top = lerp(topLeft, topRight, fracPart.x);
|
|
||||||
float4 bottom = lerp(bottomLeft, bottomRight, fracPart.x);
|
|
||||||
|
|
||||||
color = lerp(top, bottom, fracPart.y);
|
|
||||||
}
|
}
|
||||||
else
|
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL)
|
||||||
{
|
{
|
||||||
color = SampleSdfFont(color, texture, interpolators.UV, 1.0 / fwidth(interpolators.UV));
|
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.25)).xy;
|
||||||
|
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
||||||
|
float gradient = 1.0 + cosTheta * 0.5;
|
||||||
|
color.rgb = saturate(color.rgb * gradient);
|
||||||
}
|
}
|
||||||
|
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TEXT_SKEW)
|
||||||
|
{
|
||||||
|
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.5)).xy;
|
||||||
|
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
||||||
|
float gradient = saturate(1.0 + cosTheta);
|
||||||
|
color.rgb = lerp(color.rgb * gradient, color.rgb, pow(saturate(sd + 0.77), 32.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
color.a *= saturate(screenPxDistance + 0.5);
|
||||||
|
color.a *= textureColor.a;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
color *= texture.Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
|
color *= textureColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-211
@@ -285,8 +285,6 @@ static bool g_vulkan = false;
|
|||||||
static constexpr bool g_vulkan = true;
|
static constexpr bool g_vulkan = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool g_mesaTriangleStripWorkaround = false;
|
|
||||||
|
|
||||||
static constexpr bool g_hardwareResolve = true;
|
static constexpr bool g_hardwareResolve = true;
|
||||||
static constexpr bool g_hardwareDepthResolve = true;
|
static constexpr bool g_hardwareDepthResolve = true;
|
||||||
|
|
||||||
@@ -1340,7 +1338,6 @@ struct ImGuiPushConstants
|
|||||||
ImU32 gradientBottomLeft{};
|
ImU32 gradientBottomLeft{};
|
||||||
uint32_t shaderModifier{};
|
uint32_t shaderModifier{};
|
||||||
uint32_t texture2DDescriptorIndex{};
|
uint32_t texture2DDescriptorIndex{};
|
||||||
ImVec2 displaySize{};
|
|
||||||
ImVec2 inverseDisplaySize{};
|
ImVec2 inverseDisplaySize{};
|
||||||
ImVec2 origin{ 0.0f, 0.0f };
|
ImVec2 origin{ 0.0f, 0.0f };
|
||||||
ImVec2 scale{ 1.0f, 1.0f };
|
ImVec2 scale{ 1.0f, 1.0f };
|
||||||
@@ -1702,14 +1699,6 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
|
|||||||
|
|
||||||
g_vulkan = (interfaceFunction == CreateVulkanInterfaceWrapper);
|
g_vulkan = (interfaceFunction == CreateVulkanInterfaceWrapper);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (interfaceFunction == CreateVulkanInterfaceWrapper)
|
|
||||||
{
|
|
||||||
// Enable triangle strip workaround if we are on the Mesa RADV driver, as it currently has a bug where
|
|
||||||
// restart indices cause triangles to be culled incorrectly. Converting them to degenerate triangles fixes it.
|
|
||||||
g_mesaTriangleStripWorkaround = deviceDescription.name.find(" (RADV ") != std::string::npos;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2329,7 +2318,6 @@ static void DrawProfiler()
|
|||||||
ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported");
|
ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported");
|
||||||
ImGui::Text("Triangle Fan: %s", g_capabilities.triangleFan ? "Supported" : "Unsupported");
|
ImGui::Text("Triangle Fan: %s", g_capabilities.triangleFan ? "Supported" : "Unsupported");
|
||||||
ImGui::Text("Dynamic Depth Bias: %s", g_capabilities.dynamicDepthBias ? "Supported" : "Unsupported");
|
ImGui::Text("Dynamic Depth Bias: %s", g_capabilities.dynamicDepthBias ? "Supported" : "Unsupported");
|
||||||
ImGui::Text("Triangle Strip Workaround: %s", g_mesaTriangleStripWorkaround ? "Enabled" : "Disabled");
|
|
||||||
ImGui::NewLine();
|
ImGui::NewLine();
|
||||||
|
|
||||||
ImGui::Text("API: %s", g_vulkan ? "Vulkan" : "D3D12");
|
ImGui::Text("API: %s", g_vulkan ? "Vulkan" : "D3D12");
|
||||||
@@ -2415,25 +2403,19 @@ static void DrawImGui()
|
|||||||
// we can adjust the mouse events before ImGui processes them.
|
// we can adjust the mouse events before ImGui processes them.
|
||||||
uint32_t width = g_swapChain->getWidth();
|
uint32_t width = g_swapChain->getWidth();
|
||||||
uint32_t height = g_swapChain->getHeight();
|
uint32_t height = g_swapChain->getHeight();
|
||||||
float mousePosScaleX = float(width) / float(GameWindow::s_width);
|
|
||||||
float mousePosScaleY = float(height) / float(GameWindow::s_height);
|
|
||||||
float mousePosOffsetX = (width - Video::s_viewportWidth) / 2.0f;
|
|
||||||
float mousePosOffsetY = (height - Video::s_viewportHeight) / 2.0f;
|
|
||||||
for (int i = 0; i < io.Ctx->InputEventsQueue.Size; i++)
|
|
||||||
{
|
|
||||||
auto& e = io.Ctx->InputEventsQueue[i];
|
|
||||||
if (e.Type == ImGuiInputEventType_MousePos)
|
|
||||||
{
|
|
||||||
if (e.MousePos.PosX != -FLT_MAX)
|
|
||||||
{
|
|
||||||
e.MousePos.PosX *= mousePosScaleX;
|
|
||||||
e.MousePos.PosX -= mousePosOffsetX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.MousePos.PosY != -FLT_MAX)
|
if (width != Video::s_viewportWidth || height != Video::s_viewportHeight)
|
||||||
|
{
|
||||||
|
float mousePosOffsetX = (width - Video::s_viewportWidth) / 2.0f;
|
||||||
|
float mousePosOffsetY = (height - Video::s_viewportHeight) / 2.0f;
|
||||||
|
|
||||||
|
for (int i = 0; i < io.Ctx->InputEventsQueue.Size; i++)
|
||||||
|
{
|
||||||
|
auto& e = io.Ctx->InputEventsQueue[i];
|
||||||
|
if (e.Type == ImGuiInputEventType_MousePos)
|
||||||
{
|
{
|
||||||
e.MousePos.PosY *= mousePosScaleY;
|
if (e.MousePos.PosX != -FLT_MAX) e.MousePos.PosX -= mousePosOffsetX;
|
||||||
e.MousePos.PosY -= mousePosOffsetY;
|
if (e.MousePos.PosY != -FLT_MAX) e.MousePos.PosY -= mousePosOffsetY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2503,7 +2485,6 @@ static void ProcDrawImGui(const RenderCommand& cmd)
|
|||||||
commandList->setViewports(RenderViewport(drawData.DisplayPos.x, drawData.DisplayPos.y, drawData.DisplaySize.x, drawData.DisplaySize.y));
|
commandList->setViewports(RenderViewport(drawData.DisplayPos.x, drawData.DisplayPos.y, drawData.DisplaySize.x, drawData.DisplaySize.y));
|
||||||
|
|
||||||
ImGuiPushConstants pushConstants{};
|
ImGuiPushConstants pushConstants{};
|
||||||
pushConstants.displaySize = drawData.DisplaySize;
|
|
||||||
pushConstants.inverseDisplaySize = { 1.0f / drawData.DisplaySize.x, 1.0f / drawData.DisplaySize.y };
|
pushConstants.inverseDisplaySize = { 1.0f / drawData.DisplaySize.x, 1.0f / drawData.DisplaySize.y };
|
||||||
commandList->setGraphicsPushConstants(0, &pushConstants);
|
commandList->setGraphicsPushConstants(0, &pushConstants);
|
||||||
|
|
||||||
@@ -7421,187 +7402,6 @@ bool FxShadowMapMidAsmHook(PPCRegister& r4, PPCRegister& r5, PPCRegister& r6, PP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is a driver bug on Mesa where restart indices cause incorrect culling and prevent some triangles from being rendered.
|
|
||||||
// Restart indices can be converted to degenerate triangles as a workaround until this issue gets fixed.
|
|
||||||
static void ConvertToDegenerateTriangles(uint16_t* indices, uint32_t indexCount, uint16_t*& newIndices, uint32_t& newIndexCount)
|
|
||||||
{
|
|
||||||
newIndices = reinterpret_cast<uint16_t*>(g_userHeap.Alloc(indexCount * sizeof(uint16_t) * 3));
|
|
||||||
newIndexCount = 0;
|
|
||||||
|
|
||||||
bool stripStart = true;
|
|
||||||
uint32_t stripSize = 0;
|
|
||||||
uint16_t lastIndex = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < indexCount; i++)
|
|
||||||
{
|
|
||||||
uint16_t index = indices[i];
|
|
||||||
if (index == 0xFFFF)
|
|
||||||
{
|
|
||||||
if ((stripSize % 2) != 0)
|
|
||||||
newIndices[newIndexCount++] = lastIndex;
|
|
||||||
|
|
||||||
stripStart = true;
|
|
||||||
stripSize = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (stripStart && newIndexCount != 0)
|
|
||||||
{
|
|
||||||
newIndices[newIndexCount++] = lastIndex;
|
|
||||||
newIndices[newIndexCount++] = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
newIndices[newIndexCount++] = index;
|
|
||||||
stripStart = false;
|
|
||||||
++stripSize;
|
|
||||||
lastIndex = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MeshResource
|
|
||||||
{
|
|
||||||
SWA_INSERT_PADDING(0x4);
|
|
||||||
be<uint32_t> indexCount;
|
|
||||||
be<uint32_t> indices;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::vector<uint16_t*> g_newIndicesToFree;
|
|
||||||
|
|
||||||
// Hedgehog::Mirage::CMeshData::Make
|
|
||||||
PPC_FUNC_IMPL(__imp__sub_82E44AF8);
|
|
||||||
PPC_FUNC(sub_82E44AF8)
|
|
||||||
{
|
|
||||||
uint16_t* newIndicesToFree = nullptr;
|
|
||||||
|
|
||||||
auto databaseData = reinterpret_cast<Hedgehog::Database::CDatabaseData*>(base + ctx.r3.u32);
|
|
||||||
if (g_mesaTriangleStripWorkaround && !databaseData->IsMadeOne())
|
|
||||||
{
|
|
||||||
auto meshResource = reinterpret_cast<MeshResource*>(base + ctx.r4.u32);
|
|
||||||
|
|
||||||
if (meshResource->indexCount != 0)
|
|
||||||
{
|
|
||||||
uint16_t* newIndices;
|
|
||||||
uint32_t newIndexCount;
|
|
||||||
|
|
||||||
ConvertToDegenerateTriangles(
|
|
||||||
reinterpret_cast<uint16_t*>(base + meshResource->indices),
|
|
||||||
meshResource->indexCount,
|
|
||||||
newIndices,
|
|
||||||
newIndexCount);
|
|
||||||
|
|
||||||
meshResource->indexCount = newIndexCount;
|
|
||||||
meshResource->indices = static_cast<uint32_t>(reinterpret_cast<uint8_t*>(newIndices) - base);
|
|
||||||
|
|
||||||
if (PPC_LOAD_U32(0x83396E98) != NULL)
|
|
||||||
{
|
|
||||||
// If index buffers are getting merged, new indices need to survive until the merge happens.
|
|
||||||
g_newIndicesToFree.push_back(newIndices);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Otherwise, we can free it immediately.
|
|
||||||
newIndicesToFree = newIndices;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__imp__sub_82E44AF8(ctx, base);
|
|
||||||
|
|
||||||
if (newIndicesToFree != nullptr)
|
|
||||||
g_userHeap.Free(newIndicesToFree);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hedgehog::Mirage::CShareVertexBuffer::Reset
|
|
||||||
PPC_FUNC_IMPL(__imp__sub_82E250D0);
|
|
||||||
PPC_FUNC(sub_82E250D0)
|
|
||||||
{
|
|
||||||
__imp__sub_82E250D0(ctx, base);
|
|
||||||
|
|
||||||
for (auto newIndicesToFree : g_newIndicesToFree)
|
|
||||||
g_userHeap.Free(newIndicesToFree);
|
|
||||||
|
|
||||||
g_newIndicesToFree.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LightAndIndexBufferResourceV1
|
|
||||||
{
|
|
||||||
SWA_INSERT_PADDING(0x4);
|
|
||||||
be<uint32_t> indexCount;
|
|
||||||
be<uint32_t> indices;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hedgehog::Mirage::CLightAndIndexBufferData::MakeV1
|
|
||||||
PPC_FUNC_IMPL(__imp__sub_82E3AFC8);
|
|
||||||
PPC_FUNC(sub_82E3AFC8)
|
|
||||||
{
|
|
||||||
uint16_t* newIndices = nullptr;
|
|
||||||
|
|
||||||
auto databaseData = reinterpret_cast<Hedgehog::Database::CDatabaseData*>(base + ctx.r3.u32);
|
|
||||||
if (g_mesaTriangleStripWorkaround && !databaseData->IsMadeOne())
|
|
||||||
{
|
|
||||||
auto lightAndIndexBufferResource = reinterpret_cast<LightAndIndexBufferResourceV1*>(base + ctx.r4.u32);
|
|
||||||
|
|
||||||
if (lightAndIndexBufferResource->indexCount != 0)
|
|
||||||
{
|
|
||||||
uint32_t newIndexCount;
|
|
||||||
|
|
||||||
ConvertToDegenerateTriangles(
|
|
||||||
reinterpret_cast<uint16_t*>(base + lightAndIndexBufferResource->indices),
|
|
||||||
lightAndIndexBufferResource->indexCount,
|
|
||||||
newIndices,
|
|
||||||
newIndexCount);
|
|
||||||
|
|
||||||
lightAndIndexBufferResource->indexCount = newIndexCount;
|
|
||||||
lightAndIndexBufferResource->indices = static_cast<uint32_t>(reinterpret_cast<uint8_t*>(newIndices) - base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__imp__sub_82E3AFC8(ctx, base);
|
|
||||||
|
|
||||||
if (newIndices != nullptr)
|
|
||||||
g_userHeap.Free(newIndices);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LightAndIndexBufferResourceV5
|
|
||||||
{
|
|
||||||
SWA_INSERT_PADDING(0x8);
|
|
||||||
be<uint32_t> indexCount;
|
|
||||||
be<uint32_t> indices;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hedgehog::Mirage::CLightAndIndexBufferData::MakeV5
|
|
||||||
PPC_FUNC_IMPL(__imp__sub_82E3B1C0);
|
|
||||||
PPC_FUNC(sub_82E3B1C0)
|
|
||||||
{
|
|
||||||
uint16_t* newIndices = nullptr;
|
|
||||||
|
|
||||||
auto databaseData = reinterpret_cast<Hedgehog::Database::CDatabaseData*>(base + ctx.r3.u32);
|
|
||||||
if (g_mesaTriangleStripWorkaround && !databaseData->IsMadeOne())
|
|
||||||
{
|
|
||||||
auto lightAndIndexBufferResource = reinterpret_cast<LightAndIndexBufferResourceV5*>(base + ctx.r4.u32);
|
|
||||||
|
|
||||||
if (lightAndIndexBufferResource->indexCount != 0)
|
|
||||||
{
|
|
||||||
uint32_t newIndexCount;
|
|
||||||
|
|
||||||
ConvertToDegenerateTriangles(
|
|
||||||
reinterpret_cast<uint16_t*>(base + lightAndIndexBufferResource->indices),
|
|
||||||
lightAndIndexBufferResource->indexCount,
|
|
||||||
newIndices,
|
|
||||||
newIndexCount);
|
|
||||||
|
|
||||||
lightAndIndexBufferResource->indexCount = newIndexCount;
|
|
||||||
lightAndIndexBufferResource->indices = static_cast<uint32_t>(reinterpret_cast<uint8_t*>(newIndices) - base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__imp__sub_82E3B1C0(ctx, base);
|
|
||||||
|
|
||||||
if (newIndices != nullptr)
|
|
||||||
g_userHeap.Free(newIndices);
|
|
||||||
}
|
|
||||||
|
|
||||||
GUEST_FUNCTION_HOOK(sub_82BD99B0, CreateDevice);
|
GUEST_FUNCTION_HOOK(sub_82BD99B0, CreateDevice);
|
||||||
|
|
||||||
GUEST_FUNCTION_HOOK(sub_82BE6230, DestructResource);
|
GUEST_FUNCTION_HOOK(sub_82BE6230, DestructResource);
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ int HID_OnSDLEvent(void*, SDL_Event* event)
|
|||||||
|
|
||||||
g_controllers[freeIndex] = controller;
|
g_controllers[freeIndex] = controller;
|
||||||
|
|
||||||
SetControllerTimeOfDayLED(controller, App::s_isWerehog);
|
SetControllerTimeOfDayLED(controller, App::s_pEvilSonicContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -598,5 +598,5 @@ XexPatcher::Result Installer::checkGameUpdateCompatibility(const std::filesystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> patchedBytes;
|
std::vector<uint8_t> patchedBytes;
|
||||||
return XexPatcher::apply(xexBytes.data(), xexBytes.size(), patchBytes.data(), patchBytes.size(), patchedBytes, true);
|
return XexPatcher::apply(xexBytes, patchBytes, patchedBytes, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "virtual_file_system.h"
|
#include "virtual_file_system.h"
|
||||||
#include <xex_patcher.h>
|
#include "xex_patcher.h"
|
||||||
|
|
||||||
enum class DLC {
|
enum class DLC {
|
||||||
Unknown,
|
Unknown,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "virtual_file_system.h"
|
#include "virtual_file_system.h"
|
||||||
|
|
||||||
#include <memory_mapped_file.h>
|
#include "memory_mapped_file.h"
|
||||||
|
|
||||||
struct ISOFileSystem : VirtualFileSystem
|
struct ISOFileSystem : VirtualFileSystem
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
#include "memory_mapped_file.h"
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
# include <cstring>
|
||||||
|
# include <cstdio>
|
||||||
|
# include <fcntl.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MemoryMappedFile::MemoryMappedFile()
|
||||||
|
{
|
||||||
|
// Default constructor.
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryMappedFile::MemoryMappedFile(const std::filesystem::path &path)
|
||||||
|
{
|
||||||
|
open(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryMappedFile::~MemoryMappedFile()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryMappedFile::MemoryMappedFile(MemoryMappedFile &&other)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
fileHandle = other.fileHandle;
|
||||||
|
fileMappingHandle = other.fileMappingHandle;
|
||||||
|
fileView = other.fileView;
|
||||||
|
fileSize = other.fileSize;
|
||||||
|
|
||||||
|
other.fileHandle = nullptr;
|
||||||
|
other.fileMappingHandle = nullptr;
|
||||||
|
other.fileView = nullptr;
|
||||||
|
other.fileSize.QuadPart = 0;
|
||||||
|
#else
|
||||||
|
fileHandle = other.fileHandle;
|
||||||
|
fileView = other.fileView;
|
||||||
|
fileSize = other.fileSize;
|
||||||
|
|
||||||
|
other.fileHandle = -1;
|
||||||
|
other.fileView = MAP_FAILED;
|
||||||
|
other.fileSize = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryMappedFile::open(const std::filesystem::path &path)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
fileHandle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "CreateFileW failed with error %lu.\n", GetLastError());
|
||||||
|
fileHandle = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetFileSizeEx(fileHandle, &fileSize))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "GetFileSizeEx failed with error %lu.\n", GetLastError());
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
fileHandle = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileMappingHandle = CreateFileMappingW(fileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||||
|
if (fileMappingHandle == nullptr)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "CreateFileMappingW failed with error %lu.\n", GetLastError());
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
fileHandle = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileView = MapViewOfFile(fileMappingHandle, FILE_MAP_READ, 0, 0, 0);
|
||||||
|
if (fileView == nullptr)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "MapViewOfFile failed with error %lu.\n", GetLastError());
|
||||||
|
CloseHandle(fileMappingHandle);
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
fileMappingHandle = nullptr;
|
||||||
|
fileHandle = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
fileHandle = ::open(path.c_str(), O_RDONLY);
|
||||||
|
if (fileHandle == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "open for %s failed with error %s.\n", path.c_str(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSize = lseek(fileHandle, 0, SEEK_END);
|
||||||
|
if (fileSize == (off_t)(-1))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "lseek failed with error %s.\n", strerror(errno));
|
||||||
|
::close(fileHandle);
|
||||||
|
fileHandle = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileView = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fileHandle, 0);
|
||||||
|
if (fileView == MAP_FAILED)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "mmap failed with error %s.\n", strerror(errno));
|
||||||
|
::close(fileHandle);
|
||||||
|
fileHandle = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryMappedFile::close()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (fileView != nullptr)
|
||||||
|
{
|
||||||
|
UnmapViewOfFile(fileView);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileMappingHandle != nullptr)
|
||||||
|
{
|
||||||
|
CloseHandle(fileMappingHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileHandle != nullptr)
|
||||||
|
{
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (fileView != MAP_FAILED)
|
||||||
|
{
|
||||||
|
munmap(fileView, fileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileHandle != -1)
|
||||||
|
{
|
||||||
|
::close(fileHandle);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryMappedFile::isOpen() const
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return (fileView != nullptr);
|
||||||
|
#else
|
||||||
|
return (fileView != MAP_FAILED);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *MemoryMappedFile::data() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<uint8_t *>(fileView);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryMappedFile::size() const
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return fileSize.QuadPart;
|
||||||
|
#else
|
||||||
|
return static_cast<size_t>(fileSize);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
# include <Windows.h>
|
||||||
|
#else
|
||||||
|
# include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct MemoryMappedFile {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
HANDLE fileHandle = nullptr;
|
||||||
|
HANDLE fileMappingHandle = nullptr;
|
||||||
|
LPVOID fileView = nullptr;
|
||||||
|
LARGE_INTEGER fileSize = {};
|
||||||
|
#else
|
||||||
|
int fileHandle = -1;
|
||||||
|
void *fileView = MAP_FAILED;
|
||||||
|
off_t fileSize = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MemoryMappedFile();
|
||||||
|
MemoryMappedFile(const std::filesystem::path &path);
|
||||||
|
MemoryMappedFile(MemoryMappedFile &&other);
|
||||||
|
~MemoryMappedFile();
|
||||||
|
bool open(const std::filesystem::path &path);
|
||||||
|
void close();
|
||||||
|
bool isOpen() const;
|
||||||
|
uint8_t *data() const;
|
||||||
|
size_t size() const;
|
||||||
|
};
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "virtual_file_system.h"
|
#include "virtual_file_system.h"
|
||||||
|
|
||||||
#include <memory_mapped_file.h>
|
#include "memory_mapped_file.h"
|
||||||
|
|
||||||
enum class XContentVolumeType
|
enum class XContentVolumeType
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,693 @@
|
|||||||
|
// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/cpu/xex_module.cc
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2023 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xex_patcher.h"
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <aes.hpp>
|
||||||
|
#include <lzx.h>
|
||||||
|
#include <mspack.h>
|
||||||
|
#include <TinySHA1.hpp>
|
||||||
|
|
||||||
|
#include "memory_mapped_file.h"
|
||||||
|
|
||||||
|
enum Xex2ModuleFlags
|
||||||
|
{
|
||||||
|
XEX_MODULE_MODULE_PATCH = 0x10,
|
||||||
|
XEX_MODULE_PATCH_FULL = 0x20,
|
||||||
|
XEX_MODULE_PATCH_DELTA = 0x40,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Xex2HeaderKeys
|
||||||
|
{
|
||||||
|
XEX_HEADER_FILE_FORMAT_INFO = 0x3FF,
|
||||||
|
XEX_HEADER_DELTA_PATCH_DESCRIPTOR = 0x5FF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Xex2EncryptionType
|
||||||
|
{
|
||||||
|
XEX_ENCRYPTION_NONE = 0,
|
||||||
|
XEX_ENCRYPTION_NORMAL = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Xex2CompressionType
|
||||||
|
{
|
||||||
|
XEX_COMPRESSION_NONE = 0,
|
||||||
|
XEX_COMPRESSION_BASIC = 1,
|
||||||
|
XEX_COMPRESSION_NORMAL = 2,
|
||||||
|
XEX_COMPRESSION_DELTA = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Xex2SectionType
|
||||||
|
{
|
||||||
|
XEX_SECTION_CODE = 1,
|
||||||
|
XEX_SECTION_DATA = 2,
|
||||||
|
XEX_SECTION_READONLY_DATA = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2OptHeader
|
||||||
|
{
|
||||||
|
be<uint32_t> key;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
be<uint32_t> value;
|
||||||
|
be<uint32_t> offset;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2Header
|
||||||
|
{
|
||||||
|
be<uint32_t> magic;
|
||||||
|
be<uint32_t> moduleFlags;
|
||||||
|
be<uint32_t> headerSize;
|
||||||
|
be<uint32_t> reserved;
|
||||||
|
be<uint32_t> securityOffset;
|
||||||
|
be<uint32_t> headerCount;
|
||||||
|
Xex2OptHeader headers[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2PageDescriptor
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
// Must be endian-swapped before reading the bitfield.
|
||||||
|
uint32_t beValue;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t info : 4;
|
||||||
|
uint32_t pageCount : 28;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
char dataDigest[0x14];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2SecurityInfo
|
||||||
|
{
|
||||||
|
be<uint32_t> headerSize;
|
||||||
|
be<uint32_t> imageSize;
|
||||||
|
char rsaSignature[0x100];
|
||||||
|
be<uint32_t> unknown;
|
||||||
|
be<uint32_t> imageFlags;
|
||||||
|
be<uint32_t> loadAddress;
|
||||||
|
char sectionDigest[0x14];
|
||||||
|
be<uint32_t> importTableCount;
|
||||||
|
char importTableDigest[0x14];
|
||||||
|
char xgd2MediaId[0x10];
|
||||||
|
char aesKey[0x10];
|
||||||
|
be<uint32_t> exportTable;
|
||||||
|
char headerDigest[0x14];
|
||||||
|
be<uint32_t> region;
|
||||||
|
be<uint32_t> allowedMediaTypes;
|
||||||
|
be<uint32_t> pageDescriptorCount;
|
||||||
|
Xex2PageDescriptor pageDescriptors[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2DeltaPatch
|
||||||
|
{
|
||||||
|
be<uint32_t> oldAddress;
|
||||||
|
be<uint32_t> newAddress;
|
||||||
|
be<uint16_t> uncompressedLength;
|
||||||
|
be<uint16_t> compressedLength;
|
||||||
|
char patchData[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2OptDeltaPatchDescriptor
|
||||||
|
{
|
||||||
|
be<uint32_t> size;
|
||||||
|
be<uint32_t> targetVersionValue;
|
||||||
|
be<uint32_t> sourceVersionValue;
|
||||||
|
uint8_t digestSource[0x14];
|
||||||
|
uint8_t imageKeySource[0x10];
|
||||||
|
be<uint32_t> sizeOfTargetHeaders;
|
||||||
|
be<uint32_t> deltaHeadersSourceOffset;
|
||||||
|
be<uint32_t> deltaHeadersSourceSize;
|
||||||
|
be<uint32_t> deltaHeadersTargetOffset;
|
||||||
|
be<uint32_t> deltaImageSourceOffset;
|
||||||
|
be<uint32_t> deltaImageSourceSize;
|
||||||
|
be<uint32_t> deltaImageTargetOffset;
|
||||||
|
Xex2DeltaPatch info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2FileBasicCompressionBlock
|
||||||
|
{
|
||||||
|
be<uint32_t> dataSize;
|
||||||
|
be<uint32_t> zeroSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2FileBasicCompressionInfo
|
||||||
|
{
|
||||||
|
Xex2FileBasicCompressionBlock firstBlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2CompressedBlockInfo
|
||||||
|
{
|
||||||
|
be<uint32_t> blockSize;
|
||||||
|
uint8_t blockHash[20];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2FileNormalCompressionInfo
|
||||||
|
{
|
||||||
|
be<uint32_t> windowSize;
|
||||||
|
Xex2CompressedBlockInfo firstBlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xex2OptFileFormatInfo
|
||||||
|
{
|
||||||
|
be<uint32_t> infoSize;
|
||||||
|
be<uint16_t> encryptionType;
|
||||||
|
be<uint16_t> compressionType;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
Xex2FileBasicCompressionInfo basic;
|
||||||
|
Xex2FileNormalCompressionInfo normal;
|
||||||
|
} compressionInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const void *getOptHeaderPtr(std::span<const uint8_t> moduleBytes, uint32_t headerKey)
|
||||||
|
{
|
||||||
|
if ((headerKey & 0xFF) == 0)
|
||||||
|
{
|
||||||
|
assert(false && "Wrong type of method for this key. Expected return value is a number.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Xex2Header *xex2Header = (const Xex2Header *)(moduleBytes.data());
|
||||||
|
for (uint32_t i = 0; i < xex2Header->headerCount; i++)
|
||||||
|
{
|
||||||
|
const Xex2OptHeader &optHeader = xex2Header->headers[i];
|
||||||
|
if (optHeader.key == headerKey)
|
||||||
|
{
|
||||||
|
if ((headerKey & 0xFF) == 1)
|
||||||
|
{
|
||||||
|
return &optHeader.value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return &moduleBytes.data()[optHeader.offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mspack_memory_file
|
||||||
|
{
|
||||||
|
mspack_system sys;
|
||||||
|
void *buffer;
|
||||||
|
size_t bufferSize;
|
||||||
|
size_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static mspack_memory_file *mspack_memory_open(mspack_system *sys, void *buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
assert(bufferSize < INT_MAX);
|
||||||
|
|
||||||
|
if (bufferSize >= INT_MAX)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mspack_memory_file *memoryFile = (mspack_memory_file *)(std::calloc(1, sizeof(mspack_memory_file)));
|
||||||
|
if (memoryFile == nullptr)
|
||||||
|
{
|
||||||
|
return memoryFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
memoryFile->buffer = buffer;
|
||||||
|
memoryFile->bufferSize = bufferSize;
|
||||||
|
memoryFile->offset = 0;
|
||||||
|
return memoryFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mspack_memory_close(mspack_memory_file *file)
|
||||||
|
{
|
||||||
|
std::free(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mspack_memory_read(mspack_file *file, void *buffer, int chars)
|
||||||
|
{
|
||||||
|
mspack_memory_file *memoryFile = (mspack_memory_file *)(file);
|
||||||
|
const size_t remaining = memoryFile->bufferSize - memoryFile->offset;
|
||||||
|
const size_t total = std::min(size_t(chars), remaining);
|
||||||
|
std::memcpy(buffer, (uint8_t *)(memoryFile->buffer) + memoryFile->offset, total);
|
||||||
|
memoryFile->offset += total;
|
||||||
|
return int(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mspack_memory_write(mspack_file *file, void *buffer, int chars)
|
||||||
|
{
|
||||||
|
mspack_memory_file *memoryFile = (mspack_memory_file *)(file);
|
||||||
|
const size_t remaining = memoryFile->bufferSize - memoryFile->offset;
|
||||||
|
const size_t total = std::min(size_t(chars), remaining);
|
||||||
|
std::memcpy((uint8_t *)(memoryFile->buffer) + memoryFile->offset, buffer, total);
|
||||||
|
memoryFile->offset += total;
|
||||||
|
return int(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *mspack_memory_alloc(mspack_system *sys, size_t chars)
|
||||||
|
{
|
||||||
|
return std::calloc(chars, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mspack_memory_free(void *ptr)
|
||||||
|
{
|
||||||
|
std::free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mspack_memory_copy(void *src, void *dest, size_t chars)
|
||||||
|
{
|
||||||
|
std::memcpy(dest, src, chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mspack_system *mspack_memory_sys_create()
|
||||||
|
{
|
||||||
|
auto sys = (mspack_system *)(std::calloc(1, sizeof(mspack_system)));
|
||||||
|
if (!sys)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys->read = mspack_memory_read;
|
||||||
|
sys->write = mspack_memory_write;
|
||||||
|
sys->alloc = mspack_memory_alloc;
|
||||||
|
sys->free = mspack_memory_free;
|
||||||
|
sys->copy = mspack_memory_copy;
|
||||||
|
return sys;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mspack_memory_sys_destroy(struct mspack_system *sys)
|
||||||
|
{
|
||||||
|
free(sys);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
inline bool bitScanForward(uint32_t v, uint32_t *outFirstSetIndex)
|
||||||
|
{
|
||||||
|
return _BitScanForward((unsigned long *)(outFirstSetIndex), v) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex)
|
||||||
|
{
|
||||||
|
return _BitScanForward64((unsigned long *)(outFirstSetIndex), v) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
inline bool bitScanForward(uint32_t v, uint32_t *outFirstSetIndex)
|
||||||
|
{
|
||||||
|
int i = ffs(v);
|
||||||
|
*outFirstSetIndex = i - 1;
|
||||||
|
return i != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex)
|
||||||
|
{
|
||||||
|
int i = __builtin_ffsll(v);
|
||||||
|
*outFirstSetIndex = i - 1;
|
||||||
|
return i != 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int lzxDecompress(const void *lzxData, size_t lzxLength, void *dst, size_t dstLength, uint32_t windowSize, void *windowData, size_t windowDataLength)
|
||||||
|
{
|
||||||
|
int resultCode = 1;
|
||||||
|
uint32_t windowBits;
|
||||||
|
if (!bitScanForward(windowSize, &windowBits)) {
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
mspack_system *sys = mspack_memory_sys_create();
|
||||||
|
mspack_memory_file *lzxSrc = mspack_memory_open(sys, (void *)(lzxData), lzxLength);
|
||||||
|
mspack_memory_file *lzxDst = mspack_memory_open(sys, dst, dstLength);
|
||||||
|
lzxd_stream *lzxd = lzxd_init(sys, (mspack_file *)(lzxSrc), (mspack_file *)(lzxDst), windowBits, 0, 0x8000, dstLength, 0);
|
||||||
|
if (lzxd != nullptr) {
|
||||||
|
if (windowData != nullptr) {
|
||||||
|
size_t paddingLength = windowSize - windowDataLength;
|
||||||
|
std::memset(&lzxd->window[0], 0, paddingLength);
|
||||||
|
std::memcpy(&lzxd->window[paddingLength], windowData, windowDataLength);
|
||||||
|
lzxd->ref_data_size = windowSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultCode = lzxd_decompress(lzxd, dstLength);
|
||||||
|
lzxd_free(lzxd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lzxSrc) {
|
||||||
|
mspack_memory_close(lzxSrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lzxDst) {
|
||||||
|
mspack_memory_close(lzxDst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sys) {
|
||||||
|
mspack_memory_sys_destroy(sys);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lzxDeltaApplyPatch(const Xex2DeltaPatch *deltaPatch, uint32_t patchLength, uint32_t windowSize, uint8_t *dstData)
|
||||||
|
{
|
||||||
|
const void *patchEnd = (const uint8_t *)(deltaPatch) + patchLength;
|
||||||
|
const Xex2DeltaPatch *curPatch = deltaPatch;
|
||||||
|
while (patchEnd > curPatch)
|
||||||
|
{
|
||||||
|
int patchSize = -4;
|
||||||
|
if (curPatch->compressedLength == 0 && curPatch->uncompressedLength == 0 && curPatch->newAddress == 0 && curPatch->oldAddress == 0)
|
||||||
|
{
|
||||||
|
// End of patch.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (curPatch->compressedLength)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
// Set the data to zeroes.
|
||||||
|
std::memset(&dstData[curPatch->newAddress], 0, curPatch->uncompressedLength);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// Move the data.
|
||||||
|
std::memcpy(&dstData[curPatch->newAddress], &dstData[curPatch->oldAddress], curPatch->uncompressedLength);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Decompress the data into the destination.
|
||||||
|
patchSize = curPatch->compressedLength - 4;
|
||||||
|
int result = lzxDecompress(curPatch->patchData, curPatch->compressedLength, &dstData[curPatch->newAddress], curPatch->uncompressedLength, windowSize, &dstData[curPatch->oldAddress], curPatch->uncompressedLength);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
curPatch++;
|
||||||
|
curPatch = (const Xex2DeltaPatch *)((const uint8_t *)(curPatch) + patchSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XexPatcher::Result XexPatcher::apply(std::span<const uint8_t> xexBytes, std::span<const uint8_t> patchBytes, std::vector<uint8_t> &outBytes, bool skipData)
|
||||||
|
{
|
||||||
|
// Validate headers.
|
||||||
|
static const char Xex2Magic[] = "XEX2";
|
||||||
|
const Xex2Header *xexHeader = (const Xex2Header *)(xexBytes.data());
|
||||||
|
if (memcmp(xexBytes.data(), Xex2Magic, 4) != 0)
|
||||||
|
{
|
||||||
|
return Result::XexFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Xex2Header *patchHeader = (const Xex2Header *)(patchBytes.data());
|
||||||
|
if (memcmp(patchBytes.data(), Xex2Magic, 4) != 0)
|
||||||
|
{
|
||||||
|
return Result::PatchFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((patchHeader->moduleFlags & (XEX_MODULE_MODULE_PATCH | XEX_MODULE_PATCH_DELTA | XEX_MODULE_PATCH_FULL)) == 0)
|
||||||
|
{
|
||||||
|
return Result::PatchFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate patch.
|
||||||
|
const Xex2OptDeltaPatchDescriptor *patchDescriptor = (const Xex2OptDeltaPatchDescriptor *)(getOptHeaderPtr(patchBytes, XEX_HEADER_DELTA_PATCH_DESCRIPTOR));
|
||||||
|
if (patchDescriptor == nullptr)
|
||||||
|
{
|
||||||
|
return Result::PatchFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Xex2OptFileFormatInfo *patchFileFormatInfo = (const Xex2OptFileFormatInfo *)(getOptHeaderPtr(patchBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
||||||
|
if (patchFileFormatInfo == nullptr)
|
||||||
|
{
|
||||||
|
return Result::PatchFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patchFileFormatInfo->compressionType != XEX_COMPRESSION_DELTA)
|
||||||
|
{
|
||||||
|
return Result::PatchFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patchDescriptor->deltaHeadersSourceOffset > xexHeader->headerSize)
|
||||||
|
{
|
||||||
|
return Result::PatchIncompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patchDescriptor->deltaHeadersSourceSize > (xexHeader->headerSize - patchDescriptor->deltaHeadersSourceOffset))
|
||||||
|
{
|
||||||
|
return Result::PatchIncompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patchDescriptor->deltaHeadersTargetOffset > patchDescriptor->sizeOfTargetHeaders)
|
||||||
|
{
|
||||||
|
return Result::PatchIncompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t deltaTargetSize = patchDescriptor->sizeOfTargetHeaders - patchDescriptor->deltaHeadersTargetOffset;
|
||||||
|
if (patchDescriptor->deltaHeadersSourceSize > deltaTargetSize)
|
||||||
|
{
|
||||||
|
return Result::PatchIncompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply patch.
|
||||||
|
uint32_t headerTargetSize = patchDescriptor->sizeOfTargetHeaders;
|
||||||
|
if (headerTargetSize == 0)
|
||||||
|
{
|
||||||
|
headerTargetSize = patchDescriptor->deltaHeadersTargetOffset + patchDescriptor->deltaHeadersSourceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the bytes for the new XEX header. Copy over the existing data.
|
||||||
|
uint32_t newXexHeaderSize = std::max(headerTargetSize, xexHeader->headerSize.get());
|
||||||
|
outBytes.resize(newXexHeaderSize);
|
||||||
|
memset(outBytes.data(), 0, newXexHeaderSize);
|
||||||
|
memcpy(outBytes.data(), xexBytes.data(), headerTargetSize);
|
||||||
|
|
||||||
|
Xex2Header *newXexHeader = (Xex2Header *)(outBytes.data());
|
||||||
|
if (patchDescriptor->deltaHeadersSourceOffset > 0)
|
||||||
|
{
|
||||||
|
memcpy(&outBytes[patchDescriptor->deltaHeadersTargetOffset], &outBytes[patchDescriptor->deltaHeadersSourceOffset], patchDescriptor->deltaHeadersSourceSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int resultCode = lzxDeltaApplyPatch(&patchDescriptor->info, patchDescriptor->size, patchFileFormatInfo->compressionInfo.normal.windowSize, outBytes.data());
|
||||||
|
if (resultCode != 0)
|
||||||
|
{
|
||||||
|
return Result::PatchFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the header the specified size by the patch.
|
||||||
|
outBytes.resize(headerTargetSize);
|
||||||
|
newXexHeader = (Xex2Header *)(outBytes.data());
|
||||||
|
|
||||||
|
// Copy the rest of the data.
|
||||||
|
const Xex2SecurityInfo *newSecurityInfo = (const Xex2SecurityInfo *)(&outBytes[newXexHeader->securityOffset]);
|
||||||
|
outBytes.resize(outBytes.size() + newSecurityInfo->imageSize);
|
||||||
|
memset(&outBytes[headerTargetSize], 0, outBytes.size() - headerTargetSize);
|
||||||
|
memcpy(&outBytes[headerTargetSize], &xexBytes[xexHeader->headerSize], xexBytes.size() - xexHeader->headerSize);
|
||||||
|
newXexHeader = (Xex2Header *)(outBytes.data());
|
||||||
|
newSecurityInfo = (const Xex2SecurityInfo *)(&outBytes[newXexHeader->securityOffset]);
|
||||||
|
|
||||||
|
// Decrypt the keys and validate that the patch is compatible with the base file.
|
||||||
|
static const uint32_t KeySize = 16;
|
||||||
|
static const uint8_t Xex2RetailKey[16] = { 0x20, 0xB1, 0x85, 0xA5, 0x9D, 0x28, 0xFD, 0xC3, 0x40, 0x58, 0x3F, 0xBB, 0x08, 0x96, 0xBF, 0x91 };
|
||||||
|
static const uint8_t AESBlankIV[AES_BLOCKLEN] = {};
|
||||||
|
const Xex2SecurityInfo *originalSecurityInfo = (const Xex2SecurityInfo *)(&xexBytes[xexHeader->securityOffset]);
|
||||||
|
const Xex2SecurityInfo *patchSecurityInfo = (const Xex2SecurityInfo *)(&patchBytes[patchHeader->securityOffset]);
|
||||||
|
uint8_t decryptedOriginalKey[KeySize];
|
||||||
|
uint8_t decryptedNewKey[KeySize];
|
||||||
|
uint8_t decryptedPatchKey[KeySize];
|
||||||
|
uint8_t decrpytedImageKeySource[KeySize];
|
||||||
|
memcpy(decryptedOriginalKey, originalSecurityInfo->aesKey, KeySize);
|
||||||
|
memcpy(decryptedNewKey, newSecurityInfo->aesKey, KeySize);
|
||||||
|
memcpy(decryptedPatchKey, patchSecurityInfo->aesKey, KeySize);
|
||||||
|
memcpy(decrpytedImageKeySource, patchDescriptor->imageKeySource, KeySize);
|
||||||
|
|
||||||
|
AES_ctx aesContext;
|
||||||
|
AES_init_ctx_iv(&aesContext, Xex2RetailKey, AESBlankIV);
|
||||||
|
AES_CBC_decrypt_buffer(&aesContext, decryptedOriginalKey, KeySize);
|
||||||
|
|
||||||
|
AES_ctx_set_iv(&aesContext, AESBlankIV);
|
||||||
|
AES_CBC_decrypt_buffer(&aesContext, decryptedNewKey, KeySize);
|
||||||
|
|
||||||
|
AES_init_ctx_iv(&aesContext, decryptedNewKey, AESBlankIV);
|
||||||
|
AES_CBC_decrypt_buffer(&aesContext, decryptedPatchKey, KeySize);
|
||||||
|
|
||||||
|
AES_ctx_set_iv(&aesContext, AESBlankIV);
|
||||||
|
AES_CBC_decrypt_buffer(&aesContext, decrpytedImageKeySource, KeySize);
|
||||||
|
|
||||||
|
// Validate the patch's key matches the one from the original XEX.
|
||||||
|
if (memcmp(decrpytedImageKeySource, decryptedOriginalKey, KeySize) != 0)
|
||||||
|
{
|
||||||
|
return Result::PatchIncompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't process the rest of the patch.
|
||||||
|
if (skipData)
|
||||||
|
{
|
||||||
|
return Result::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt base XEX if necessary.
|
||||||
|
const Xex2OptFileFormatInfo *fileFormatInfo = (const Xex2OptFileFormatInfo *)(getOptHeaderPtr(xexBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
||||||
|
if (fileFormatInfo == nullptr)
|
||||||
|
{
|
||||||
|
return Result::XexFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileFormatInfo->encryptionType == XEX_ENCRYPTION_NORMAL)
|
||||||
|
{
|
||||||
|
AES_init_ctx_iv(&aesContext, decryptedOriginalKey, AESBlankIV);
|
||||||
|
AES_CBC_decrypt_buffer(&aesContext, &outBytes[headerTargetSize], xexBytes.size() - xexHeader->headerSize);
|
||||||
|
}
|
||||||
|
else if (fileFormatInfo->encryptionType != XEX_ENCRYPTION_NONE)
|
||||||
|
{
|
||||||
|
return Result::XexFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decompress base XEX if necessary.
|
||||||
|
if (fileFormatInfo->compressionType == XEX_COMPRESSION_BASIC)
|
||||||
|
{
|
||||||
|
const Xex2FileBasicCompressionBlock *blocks = &fileFormatInfo->compressionInfo.basic.firstBlock;
|
||||||
|
int32_t numBlocks = (fileFormatInfo->infoSize / sizeof(Xex2FileBasicCompressionBlock)) - 1;
|
||||||
|
int32_t baseCompressedSize = 0;
|
||||||
|
int32_t baseImageSize = 0;
|
||||||
|
for (int32_t i = 0; i < numBlocks; i++) {
|
||||||
|
baseCompressedSize += blocks[i].dataSize;
|
||||||
|
baseImageSize += blocks[i].dataSize + blocks[i].zeroSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outBytes.size() < (headerTargetSize + baseImageSize))
|
||||||
|
{
|
||||||
|
return Result::XexFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse iteration allows to perform this decompression in place.
|
||||||
|
uint8_t *srcDataCursor = outBytes.data() + headerTargetSize + baseCompressedSize;
|
||||||
|
uint8_t *outDataCursor = outBytes.data() + headerTargetSize + baseImageSize;
|
||||||
|
for (int32_t i = numBlocks - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
outDataCursor -= blocks[i].zeroSize;
|
||||||
|
memset(outDataCursor, 0, blocks[i].zeroSize);
|
||||||
|
outDataCursor -= blocks[i].dataSize;
|
||||||
|
srcDataCursor -= blocks[i].dataSize;
|
||||||
|
memmove(outDataCursor, srcDataCursor, blocks[i].dataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL || fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA)
|
||||||
|
{
|
||||||
|
return Result::XexFileUnsupported;
|
||||||
|
}
|
||||||
|
else if (fileFormatInfo->compressionType != XEX_COMPRESSION_NONE)
|
||||||
|
{
|
||||||
|
return Result::XexFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Xex2OptFileFormatInfo *newFileFormatInfo = (Xex2OptFileFormatInfo *)(getOptHeaderPtr(outBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
||||||
|
if (newFileFormatInfo == nullptr)
|
||||||
|
{
|
||||||
|
return Result::PatchFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the header to indicate no encryption or compression is used.
|
||||||
|
newFileFormatInfo->encryptionType = XEX_ENCRYPTION_NONE;
|
||||||
|
newFileFormatInfo->compressionType = XEX_COMPRESSION_NONE;
|
||||||
|
|
||||||
|
// Copy and decrypt patch data if necessary.
|
||||||
|
std::vector<uint8_t> patchData;
|
||||||
|
patchData.resize(patchBytes.size() - patchHeader->headerSize);
|
||||||
|
memcpy(patchData.data(), &patchBytes[patchHeader->headerSize], patchData.size());
|
||||||
|
|
||||||
|
if (patchFileFormatInfo->encryptionType == XEX_ENCRYPTION_NORMAL)
|
||||||
|
{
|
||||||
|
AES_init_ctx_iv(&aesContext, decryptedPatchKey, AESBlankIV);
|
||||||
|
AES_CBC_decrypt_buffer(&aesContext, patchData.data(), patchData.size());
|
||||||
|
}
|
||||||
|
else if (patchFileFormatInfo->encryptionType != XEX_ENCRYPTION_NONE)
|
||||||
|
{
|
||||||
|
return Result::PatchFileInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Xex2CompressedBlockInfo *currentBlock = &patchFileFormatInfo->compressionInfo.normal.firstBlock;
|
||||||
|
uint8_t *outExe = &outBytes[newXexHeader->headerSize];
|
||||||
|
if (patchDescriptor->deltaImageSourceOffset > 0)
|
||||||
|
{
|
||||||
|
memcpy(&outExe[patchDescriptor->deltaImageTargetOffset], &outExe[patchDescriptor->deltaImageSourceOffset], patchDescriptor->deltaImageSourceSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint32_t DigestSize = 20;
|
||||||
|
uint8_t sha1Digest[DigestSize];
|
||||||
|
sha1::SHA1 sha1Context;
|
||||||
|
uint8_t *patchDataCursor = patchData.data();
|
||||||
|
while (currentBlock->blockSize > 0)
|
||||||
|
{
|
||||||
|
const Xex2CompressedBlockInfo *nextBlock = (const Xex2CompressedBlockInfo *)(patchDataCursor);
|
||||||
|
|
||||||
|
// Hash and validate the block.
|
||||||
|
sha1Context.reset();
|
||||||
|
sha1Context.processBytes(patchDataCursor, currentBlock->blockSize);
|
||||||
|
sha1Context.finalize(sha1Digest);
|
||||||
|
if (memcmp(sha1Digest, currentBlock->blockHash, DigestSize) != 0)
|
||||||
|
{
|
||||||
|
return Result::PatchFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
patchDataCursor += 24;
|
||||||
|
|
||||||
|
// Apply the block's patch data.
|
||||||
|
uint32_t blockDataSize = currentBlock->blockSize - 24;
|
||||||
|
if (lzxDeltaApplyPatch((const Xex2DeltaPatch *)(patchDataCursor), blockDataSize, patchFileFormatInfo->compressionInfo.normal.windowSize, outExe) != 0)
|
||||||
|
{
|
||||||
|
return Result::PatchFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
patchDataCursor += blockDataSize;
|
||||||
|
currentBlock = nextBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
XexPatcher::Result XexPatcher::apply(const std::filesystem::path &baseXexPath, const std::filesystem::path &patchXexPath, const std::filesystem::path &newXexPath)
|
||||||
|
{
|
||||||
|
MemoryMappedFile baseXexFile(baseXexPath);
|
||||||
|
MemoryMappedFile patchFile(patchXexPath);
|
||||||
|
if (!baseXexFile.isOpen() || !patchFile.isOpen())
|
||||||
|
{
|
||||||
|
return Result::FileOpenFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> newXexBytes;
|
||||||
|
Result result = apply({ baseXexFile.data(), baseXexFile.size() }, { patchFile.data(), patchFile.size() }, newXexBytes, false);
|
||||||
|
if (result != Result::Success)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream newXexFile(newXexPath, std::ios::binary);
|
||||||
|
if (!newXexFile.is_open())
|
||||||
|
{
|
||||||
|
return Result::FileOpenFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
newXexFile.write((const char *)(newXexBytes.data()), newXexBytes.size());
|
||||||
|
newXexFile.close();
|
||||||
|
|
||||||
|
if (newXexFile.bad())
|
||||||
|
{
|
||||||
|
std::filesystem::remove(newXexPath);
|
||||||
|
return Result::FileWriteFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result::Success;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/cpu/xex_module.cc
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2023 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <span>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct XexPatcher
|
||||||
|
{
|
||||||
|
enum class Result {
|
||||||
|
Success,
|
||||||
|
FileOpenFailed,
|
||||||
|
FileWriteFailed,
|
||||||
|
XexFileUnsupported,
|
||||||
|
XexFileInvalid,
|
||||||
|
PatchFileInvalid,
|
||||||
|
PatchIncompatible,
|
||||||
|
PatchFailed,
|
||||||
|
PatchUnsupported
|
||||||
|
};
|
||||||
|
|
||||||
|
static Result apply(std::span<const uint8_t> xexBytes, std::span<const uint8_t> patchBytes, std::vector<uint8_t> &outBytes, bool skipData);
|
||||||
|
static Result apply(const std::filesystem::path &baseXexPath, const std::filesystem::path &patchXexPath, const std::filesystem::path &newXexPath);
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
+281
-315
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,6 @@ enum class ELanguage : uint32_t
|
|||||||
|
|
||||||
inline std::string g_localeMissing = "<missing string>";
|
inline std::string g_localeMissing = "<missing string>";
|
||||||
|
|
||||||
extern std::unordered_map<std::string_view, std::unordered_map<ELanguage, std::string>> g_locale;
|
extern std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_locale;
|
||||||
|
|
||||||
std::string& Localise(const std::string_view& key);
|
std::string& Localise(const char* key);
|
||||||
|
|||||||
+19
-19
@@ -106,33 +106,33 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* header = reinterpret_cast<const Xex2Header*>(loadResult.data());
|
auto* xex = reinterpret_cast<XEX_HEADER*>(loadResult.data());
|
||||||
auto* security = reinterpret_cast<const Xex2SecurityInfo*>(loadResult.data() + header->securityOffset);
|
auto security = reinterpret_cast<XEX2_SECURITY_INFO*>((char*)xex + xex->AddressOfSecurityInfo);
|
||||||
const auto* fileFormatInfo = reinterpret_cast<const Xex2OptFileFormatInfo*>(getOptHeaderPtr(loadResult.data(), XEX_HEADER_FILE_FORMAT_INFO));
|
|
||||||
auto entry = *reinterpret_cast<const uint32_t*>(getOptHeaderPtr(loadResult.data(), XEX_HEADER_ENTRY_POINT));
|
auto format = Xex2FindOptionalHeader<XEX_FILE_FORMAT_INFO>(xex, XEX_HEADER_FILE_FORMAT_INFO);
|
||||||
|
auto entry = *Xex2FindOptionalHeader<uint32_t>(xex, XEX_HEADER_ENTRY_POINT);
|
||||||
ByteSwapInplace(entry);
|
ByteSwapInplace(entry);
|
||||||
|
|
||||||
auto srcData = loadResult.data() + header->headerSize;
|
auto srcData = (char *)xex + xex->SizeOfHeader;
|
||||||
auto destData = reinterpret_cast<uint8_t*>(g_memory.Translate(security->loadAddress));
|
auto destData = (char *)g_memory.Translate(security->ImageBase);
|
||||||
|
if (format->CompressionType == 0)
|
||||||
if (fileFormatInfo->compressionType == XEX_COMPRESSION_NONE)
|
|
||||||
{
|
{
|
||||||
memcpy(destData, srcData, security->imageSize);
|
memcpy(destData, srcData, security->SizeOfImage);
|
||||||
}
|
}
|
||||||
else if (fileFormatInfo->compressionType == XEX_COMPRESSION_BASIC)
|
else if (format->CompressionType == 1)
|
||||||
{
|
{
|
||||||
auto* blocks = reinterpret_cast<const Xex2FileBasicCompressionBlock*>(fileFormatInfo + 1);
|
auto numBlocks = (format->SizeOfHeader / sizeof(XEX_BASIC_FILE_COMPRESSION_INFO)) - 1;
|
||||||
const size_t numBlocks = (fileFormatInfo->infoSize / sizeof(Xex2FileBasicCompressionInfo)) - 1;
|
auto blocks = reinterpret_cast<const XEX_BASIC_FILE_COMPRESSION_INFO*>(format + 1);
|
||||||
|
|
||||||
for (size_t i = 0; i < numBlocks; i++)
|
for (size_t i = 0; i < numBlocks; i++)
|
||||||
{
|
{
|
||||||
memcpy(destData, srcData, blocks[i].dataSize);
|
memcpy(destData, srcData, blocks[i].SizeOfData);
|
||||||
|
|
||||||
srcData += blocks[i].dataSize;
|
srcData += blocks[i].SizeOfData;
|
||||||
destData += blocks[i].dataSize;
|
destData += blocks[i].SizeOfData;
|
||||||
|
memset(destData, 0, blocks[i].SizeOfPadding);
|
||||||
|
|
||||||
memset(destData, 0, blocks[i].zeroSize);
|
destData += blocks[i].SizeOfPadding;
|
||||||
destData += blocks[i].zeroSize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -140,9 +140,9 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
|
|||||||
assert(false && "Unknown compression type.");
|
assert(false && "Unknown compression type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = reinterpret_cast<const Xex2ResourceInfo*>(getOptHeaderPtr(loadResult.data(), XEX_HEADER_RESOURCE_INFO));
|
auto res = Xex2FindOptionalHeader<XEX_RESOURCE_INFO>(xex, XEX_HEADER_RESOURCE_INFO);
|
||||||
|
|
||||||
g_xdbfWrapper = XDBFWrapper((uint8_t*)g_memory.Translate(res->offset.get()), res->sizeOfData);
|
g_xdbfWrapper = XDBFWrapper((uint8_t*)g_memory.Translate(res->Offset.get()), res->SizeOfData);
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <os/registry.h>
|
#include <os/registry.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
inline const wchar_t* g_registryRoot = L"Software\\UnleashedRecomp";
|
inline const wchar_t* g_registryRoot = L"Software\\UnleashedRecomp";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <kernel/function.h>
|
#include <kernel/function.h>
|
||||||
#include <api/SWA.h>
|
#include <api/SWA.h>
|
||||||
|
#include <patches/free_camera_patches.h>
|
||||||
#include <ui/achievement_menu.h>
|
#include <ui/achievement_menu.h>
|
||||||
#include <ui/button_guide.h>
|
#include <ui/button_guide.h>
|
||||||
#include <ui/options_menu.h>
|
#include <ui/options_menu.h>
|
||||||
@@ -119,6 +120,9 @@ bool CHudPauseMiscInjectOptionsMidAsmHook(PPCRegister& pThis)
|
|||||||
PPC_FUNC_IMPL(__imp__sub_824B0930);
|
PPC_FUNC_IMPL(__imp__sub_824B0930);
|
||||||
PPC_FUNC(sub_824B0930)
|
PPC_FUNC(sub_824B0930)
|
||||||
{
|
{
|
||||||
|
if (FreeCameraPatches::s_isActive)
|
||||||
|
return;
|
||||||
|
|
||||||
if (App::s_isLoading)
|
if (App::s_isLoading)
|
||||||
{
|
{
|
||||||
__imp__sub_824B0930(ctx, base);
|
__imp__sub_824B0930(ctx, base);
|
||||||
@@ -172,7 +176,7 @@ PPC_FUNC(sub_824B0930)
|
|||||||
|
|
||||||
if (*SWA::SGlobals::ms_IsRenderHud && pHudPause->m_IsShown && !pHudPause->m_Submenu && pHudPause->m_Transition == SWA::eTransitionType_Undefined)
|
if (*SWA::SGlobals::ms_IsRenderHud && pHudPause->m_IsShown && !pHudPause->m_Submenu && pHudPause->m_Transition == SWA::eTransitionType_Undefined)
|
||||||
{
|
{
|
||||||
ButtonGuide::Open(Button("Achievements_Name", FLT_MAX, EButtonIcon::Back, EButtonAlignment::Left, EFontQuality::Low));
|
ButtonGuide::Open(Button("Achievements_Name", EButtonIcon::Back, EButtonAlignment::Left, EFontQuality::Low));
|
||||||
g_isClosed = false;
|
g_isClosed = false;
|
||||||
}
|
}
|
||||||
else if (!g_isClosed)
|
else if (!g_isClosed)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
#include "camera_patches.h"
|
||||||
#include <api/SWA.h>
|
#include <api/SWA.h>
|
||||||
|
#include <gpu/video.h>
|
||||||
|
#include <patches/aspect_ratio_patches.h>
|
||||||
|
#include <patches/free_camera_patches.h>
|
||||||
#include <ui/game_window.h>
|
#include <ui/game_window.h>
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
#include <gpu/video.h>
|
|
||||||
#include "camera_patches.h"
|
|
||||||
#include "aspect_ratio_patches.h"
|
|
||||||
|
|
||||||
void CameraAspectRatioMidAsmHook(PPCRegister& r30, PPCRegister& r31)
|
void CameraAspectRatioMidAsmHook(PPCRegister& r30, PPCRegister& r31)
|
||||||
{
|
{
|
||||||
@@ -35,7 +36,9 @@ void CameraFieldOfViewMidAsmHook(PPCRegister& r31, PPCRegister& f31)
|
|||||||
{
|
{
|
||||||
auto camera = (SWA::CCamera*)g_memory.Translate(r31.u32);
|
auto camera = (SWA::CCamera*)g_memory.Translate(r31.u32);
|
||||||
|
|
||||||
f31.f64 = AdjustFieldOfView(f31.f64, camera->m_HorzAspectRatio);
|
f31.f64 = FreeCameraPatches::s_isActive
|
||||||
|
? FreeCameraPatches::s_fieldOfView
|
||||||
|
: AdjustFieldOfView(f31.f64, camera->m_HorzAspectRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
PPC_FUNC_IMPL(__imp__sub_824697B0);
|
PPC_FUNC_IMPL(__imp__sub_824697B0);
|
||||||
|
|||||||
@@ -0,0 +1,250 @@
|
|||||||
|
#include "free_camera_patches.h"
|
||||||
|
#include <api/SWA.h>
|
||||||
|
#include <os/logger.h>
|
||||||
|
#include <ui/game_window.h>
|
||||||
|
#include <user/config.h>
|
||||||
|
#include <app.h>
|
||||||
|
|
||||||
|
#define DEGREES_TO_RADIANS(x) (float)(x / 180.0f * M_PI)
|
||||||
|
#define RADIANS_TO_DEGREES(x) (float)(x / M_PI * 180.0f)
|
||||||
|
|
||||||
|
constexpr float DEFAULT_SPEED = 1.0f;
|
||||||
|
constexpr float DEFAULT_FIELD_OF_VIEW = 45.0f;
|
||||||
|
constexpr float MOVE_SPEED_SLOW = 0.075f;
|
||||||
|
constexpr float MOVE_SPEED_FAST = 8.0f;
|
||||||
|
constexpr float MOVE_SPEED_MODIFIER_RATIO = 0.02f;
|
||||||
|
constexpr float FOV_MODIFIER_RATIO = 1.0f;
|
||||||
|
|
||||||
|
static float g_baseSpeed = DEFAULT_SPEED;
|
||||||
|
static float g_baseFieldOfView = DEFAULT_FIELD_OF_VIEW;
|
||||||
|
|
||||||
|
static bool g_isDisablingFreeCamera;
|
||||||
|
static bool g_isCameraLocked;
|
||||||
|
static float g_speed;
|
||||||
|
static float g_fieldOfView;
|
||||||
|
|
||||||
|
static void ResetParameters()
|
||||||
|
{
|
||||||
|
g_isCameraLocked = false;
|
||||||
|
g_speed = g_baseSpeed = DEFAULT_SPEED;
|
||||||
|
|
||||||
|
*SWA::SGlobals::ms_IsRenderDepthOfField = true;
|
||||||
|
FreeCameraPatches::s_fieldOfView = g_fieldOfView = g_baseFieldOfView = DEFAULT_FIELD_OF_VIEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FreeCameraActiveMidAsmHook()
|
||||||
|
{
|
||||||
|
return Config::EnableFreeCamera && FreeCameraPatches::s_isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FreeCameraSpeedInputMidAsmHook(PPCRegister& r31, PPCRegister& r29, PPCRegister& f0)
|
||||||
|
{
|
||||||
|
if (!Config::EnableFreeCamera)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto pCamera = (SWA::CFreeCamera*)g_memory.Translate(r31.u32);
|
||||||
|
auto pPadState = (SWA::SPadState*)g_memory.Translate(r29.u32);
|
||||||
|
auto factor = App::s_deltaTime / (1.0f / 60.0f);
|
||||||
|
|
||||||
|
if (g_isCameraLocked)
|
||||||
|
{
|
||||||
|
g_speed = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static auto isLeftTriggerSpeedModifier = false;
|
||||||
|
static auto isRightTriggerSpeedModifier = false;
|
||||||
|
|
||||||
|
if (pPadState->IsDown(SWA::eKeyState_LeftTrigger))
|
||||||
|
{
|
||||||
|
g_speed = MOVE_SPEED_SLOW;
|
||||||
|
isLeftTriggerSpeedModifier = true;
|
||||||
|
}
|
||||||
|
else if (isLeftTriggerSpeedModifier)
|
||||||
|
{
|
||||||
|
g_speed = g_baseSpeed;
|
||||||
|
isLeftTriggerSpeedModifier = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pPadState->IsDown(SWA::eKeyState_RightTrigger))
|
||||||
|
{
|
||||||
|
g_speed = MOVE_SPEED_FAST;
|
||||||
|
isRightTriggerSpeedModifier = true;
|
||||||
|
}
|
||||||
|
else if (isRightTriggerSpeedModifier)
|
||||||
|
{
|
||||||
|
g_speed = g_baseSpeed;
|
||||||
|
isRightTriggerSpeedModifier = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLeftTriggerSpeedModifier && isRightTriggerSpeedModifier)
|
||||||
|
g_speed = MOVE_SPEED_FAST / 3;
|
||||||
|
|
||||||
|
if (pPadState->IsDown(SWA::eKeyState_A))
|
||||||
|
g_speed = g_baseSpeed = DEFAULT_SPEED;
|
||||||
|
|
||||||
|
if (pPadState->IsDown(SWA::eKeyState_B))
|
||||||
|
{
|
||||||
|
g_baseSpeed -= MOVE_SPEED_MODIFIER_RATIO * factor;
|
||||||
|
g_speed = g_baseSpeed;
|
||||||
|
|
||||||
|
LOGFN("[Free Camera] Speed: {}", g_speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pPadState->IsDown(SWA::eKeyState_X))
|
||||||
|
{
|
||||||
|
g_baseSpeed += MOVE_SPEED_MODIFIER_RATIO * factor;
|
||||||
|
g_speed = g_baseSpeed;
|
||||||
|
|
||||||
|
LOGFN("[Free Camera] Speed: {}", g_speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_speed = std::clamp(g_speed, 0.01f, 20.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
f0.f64 = g_speed;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SWA::CFreeCamera::Update
|
||||||
|
PPC_FUNC_IMPL(__imp__sub_82472A18);
|
||||||
|
PPC_FUNC(sub_82472A18)
|
||||||
|
{
|
||||||
|
if (Config::EnableFreeCamera)
|
||||||
|
{
|
||||||
|
auto pCamera = (SWA::CFreeCamera*)g_memory.Translate(ctx.r3.u32);
|
||||||
|
auto aspectRatio = (float)GameWindow::s_width / (float)GameWindow::s_height;
|
||||||
|
|
||||||
|
if (auto pInputState = SWA::CInputState::GetInstance())
|
||||||
|
{
|
||||||
|
auto& rPadState = pInputState->GetPadState();
|
||||||
|
|
||||||
|
// Deactivate.
|
||||||
|
if (rPadState.IsTapped(SWA::eKeyState_Select))
|
||||||
|
{
|
||||||
|
guest_stack_var<SWA::Message::MsgPopCameraController> msgPopCameraController(pCamera, 0.0f);
|
||||||
|
guest_stack_var<SWA::Message::MsgCameraPauseMove> msgCameraPauseMove(false);
|
||||||
|
|
||||||
|
// Process SWA::Message::MsgPopCameraController.
|
||||||
|
GuestToHostFunction<int>(sub_8246A840, pCamera->m_pCamera.get(), msgPopCameraController.get());
|
||||||
|
|
||||||
|
// Process SWA::Message::MsgFinishFreeCamera.
|
||||||
|
GuestToHostFunction<int>(sub_8253ADB8, App::s_pGameModeStage);
|
||||||
|
|
||||||
|
// Process SWA::Message::MsgCameraPauseMove.
|
||||||
|
GuestToHostFunction<int>(sub_824679C0, pCamera->m_pCamera.get(), msgCameraPauseMove.get());
|
||||||
|
|
||||||
|
FreeCameraPatches::s_isActive = false;
|
||||||
|
*SWA::SGlobals::ms_IsRenderHud = true;
|
||||||
|
|
||||||
|
LOGN("[Free Camera] Disabled");
|
||||||
|
|
||||||
|
g_isDisablingFreeCamera = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teleport player to camera.
|
||||||
|
if (rPadState.IsTapped(SWA::eKeyState_LeftStick))
|
||||||
|
{
|
||||||
|
guest_stack_var<SWA::Message::MsgSetPosition> msgSetPosition(pCamera->m_Position);
|
||||||
|
guest_stack_var<SWA::Message::MsgSetVelocity> msgSetVelocity(Hedgehog::Math::CVector(0.0f, 0.0f, 0.0f));
|
||||||
|
|
||||||
|
if (auto pPlayerSpeedContext = SWA::Player::CPlayerSpeedContext::GetInstance())
|
||||||
|
{
|
||||||
|
// Process SWA::Message::MsgSetPosition.
|
||||||
|
GuestToHostFunction<int>(sub_82303100, pPlayerSpeedContext->m_pPlayer.get(), msgSetPosition.get());
|
||||||
|
|
||||||
|
// Process SWA::Message::MsgSetVelocity.
|
||||||
|
GuestToHostFunction<int>(sub_82311820, pPlayerSpeedContext->m_pPlayer.get(), msgSetVelocity.get());
|
||||||
|
}
|
||||||
|
else if (App::s_pEvilSonicContext)
|
||||||
|
{
|
||||||
|
// Process SWA::Message::MsgSetPosition.
|
||||||
|
GuestToHostFunction<int>(sub_82303100, App::s_pEvilSonicContext->m_pPlayer.get(), msgSetPosition.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock camera.
|
||||||
|
if (rPadState.IsTapped(SWA::eKeyState_DpadLeft))
|
||||||
|
{
|
||||||
|
g_isCameraLocked = !g_isCameraLocked;
|
||||||
|
|
||||||
|
if (g_isCameraLocked)
|
||||||
|
{
|
||||||
|
LOGN("[Free Camera] Locked");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_speed = g_baseSpeed;
|
||||||
|
|
||||||
|
LOGN("[Free Camera] Unlocked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle depth of field.
|
||||||
|
if (rPadState.IsTapped(SWA::eKeyState_DpadRight))
|
||||||
|
{
|
||||||
|
*SWA::SGlobals::ms_IsRenderDepthOfField = !*SWA::SGlobals::ms_IsRenderDepthOfField;
|
||||||
|
|
||||||
|
if (*SWA::SGlobals::ms_IsRenderDepthOfField)
|
||||||
|
{
|
||||||
|
LOGN("[Free Camera] Depth of Field ON");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGN("[Free Camera] Depth of Field OFF");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto isResetFOV = rPadState.IsDown(SWA::eKeyState_Y);
|
||||||
|
auto isIncreaseFOV = rPadState.IsDown(SWA::eKeyState_DpadUp);
|
||||||
|
auto isDecreaseFOV = rPadState.IsDown(SWA::eKeyState_DpadDown);
|
||||||
|
|
||||||
|
auto fovScaleFactor = 0.0f;
|
||||||
|
|
||||||
|
if (isIncreaseFOV)
|
||||||
|
{
|
||||||
|
fovScaleFactor = FOV_MODIFIER_RATIO;
|
||||||
|
}
|
||||||
|
else if (isDecreaseFOV)
|
||||||
|
{
|
||||||
|
fovScaleFactor = -FOV_MODIFIER_RATIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_fieldOfView = fmodf(isResetFOV ? DEFAULT_FIELD_OF_VIEW : g_fieldOfView + fovScaleFactor * App::s_deltaTime * 60.0f, 180.0f);
|
||||||
|
|
||||||
|
FreeCameraPatches::s_fieldOfView = 2.0f * atan(tan(DEGREES_TO_RADIANS(g_fieldOfView / 2.0f) * (16.0f / 9.0f / std::min(aspectRatio, 16.0f / 9.0f))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__imp__sub_82472A18(ctx, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeCameraPatches::Update()
|
||||||
|
{
|
||||||
|
if (!Config::EnableFreeCamera || !App::s_pGameModeStage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (auto pInputState = SWA::CInputState::GetInstance())
|
||||||
|
{
|
||||||
|
auto& rPadState = pInputState->GetPadState();
|
||||||
|
|
||||||
|
if (rPadState.IsTapped(SWA::eKeyState_Select) && !FreeCameraPatches::s_isActive && !g_isDisablingFreeCamera)
|
||||||
|
{
|
||||||
|
ResetParameters();
|
||||||
|
|
||||||
|
// Process SWA::Message::MsgStartFreeCamera.
|
||||||
|
GuestToHostFunction<int>(sub_8253ACB8, App::s_pGameModeStage);
|
||||||
|
|
||||||
|
FreeCameraPatches::s_isActive = true;
|
||||||
|
*SWA::SGlobals::ms_IsRenderHud = false;
|
||||||
|
|
||||||
|
LOGN("[Free Camera] Enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rPadState.IsReleased(SWA::eKeyState_Select) && !FreeCameraPatches::s_isActive)
|
||||||
|
g_isDisablingFreeCamera = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class FreeCameraPatches
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static inline bool s_isActive;
|
||||||
|
|
||||||
|
static inline float s_fieldOfView;
|
||||||
|
|
||||||
|
static void Update();
|
||||||
|
};
|
||||||
@@ -57,7 +57,7 @@ PPC_FUNC(sub_82B98D30)
|
|||||||
g_pScene = nullptr;
|
g_pScene = nullptr;
|
||||||
InspirePatches::s_sceneName.clear();
|
InspirePatches::s_sceneName.clear();
|
||||||
|
|
||||||
SDL_User_EvilSonic(App::s_isWerehog);
|
SDL_User_EvilSonic(App::s_pEvilSonicContext);
|
||||||
|
|
||||||
g_loadedMouthExplosionAnimation = false;
|
g_loadedMouthExplosionAnimation = false;
|
||||||
g_hideMorphModels = false;
|
g_hideMorphModels = false;
|
||||||
|
|||||||
@@ -70,9 +70,10 @@ void ObjBigBarrelSetPositionMidAsmHook(PPCRegister& r3, PPCRegister& r4)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SWA::CExBullet::AddCallback
|
|
||||||
// Tornado Defense bullet particles are colored by the button prompt, which differs on PlayStation 3.
|
// Tornado Defense bullet particles are colored by the button prompt, which differs on PlayStation 3.
|
||||||
// Luckily, the PS3 particles are left in the files, and they get spawned by name when a bullet gets created.
|
// Luckily, the PS3 particles are left in the files, and they get spawned by name when a bullet gets created.
|
||||||
|
|
||||||
|
// SWA::CExBullet::AddCallback
|
||||||
PPC_FUNC_IMPL(__imp__sub_82B14CC0);
|
PPC_FUNC_IMPL(__imp__sub_82B14CC0);
|
||||||
PPC_FUNC(sub_82B14CC0)
|
PPC_FUNC(sub_82B14CC0)
|
||||||
{
|
{
|
||||||
@@ -98,38 +99,3 @@ PPC_FUNC(sub_82B14CC0)
|
|||||||
|
|
||||||
__imp__sub_82B14CC0(ctx, base);
|
__imp__sub_82B14CC0(ctx, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CObjGrindDashPanel is particularly egregious when it comes to overlapping sounds at HFR
|
|
||||||
// due to the character proxy sending the hit message multiple times in a frame. This is a
|
|
||||||
// quick workaround to limit the message process function to occur at a 30 FPS time step.
|
|
||||||
static constexpr size_t OBJ_GRIND_DASH_PANEL_SIZE = 0x160;
|
|
||||||
|
|
||||||
void ObjGrindDashPanelAllocMidAsmHook(PPCRegister& r3)
|
|
||||||
{
|
|
||||||
r3.u32 += sizeof(double);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SWA::CObjGrindDashPanel::CObjGrindDashPanel
|
|
||||||
PPC_FUNC_IMPL(__imp__sub_82614228);
|
|
||||||
PPC_FUNC(sub_82614228)
|
|
||||||
{
|
|
||||||
*reinterpret_cast<double*>(base + ctx.r3.u32 + OBJ_GRIND_DASH_PANEL_SIZE) = 0.0;
|
|
||||||
__imp__sub_82614228(ctx, base);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SWA::CObjGrindDashPanel::MsgHitEventCollision::Impl
|
|
||||||
PPC_FUNC_IMPL(__imp__sub_826145D8);
|
|
||||||
PPC_FUNC(sub_826145D8)
|
|
||||||
{
|
|
||||||
constexpr double REFERENCE_DELTA_TIME = 1.0 / 30.0;
|
|
||||||
constexpr double DELTA_TIME_TOLERANCE = 0.0001;
|
|
||||||
|
|
||||||
auto lastHitTime = reinterpret_cast<double*>(base + ctx.r3.u32 + OBJ_GRIND_DASH_PANEL_SIZE);
|
|
||||||
auto deltaTime = App::s_time - *lastHitTime;
|
|
||||||
|
|
||||||
if ((deltaTime + DELTA_TIME_TOLERANCE) > REFERENCE_DELTA_TIME)
|
|
||||||
{
|
|
||||||
__imp__sub_826145D8(ctx, base);
|
|
||||||
*lastHitTime = App::s_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -104,9 +104,9 @@ void SetXButtonHomingMidAsmHook(PPCRegister& r30)
|
|||||||
PPC_FUNC_IMPL(__imp__sub_823B49D8);
|
PPC_FUNC_IMPL(__imp__sub_823B49D8);
|
||||||
PPC_FUNC(sub_823B49D8)
|
PPC_FUNC(sub_823B49D8)
|
||||||
{
|
{
|
||||||
__imp__sub_823B49D8(ctx, base);
|
App::s_pEvilSonicContext = (SWA::Player::CEvilSonicContext*)g_memory.Translate(ctx.r3.u32);
|
||||||
|
|
||||||
App::s_isWerehog = true;
|
__imp__sub_823B49D8(ctx, base);
|
||||||
|
|
||||||
SDL_User_EvilSonic(true);
|
SDL_User_EvilSonic(true);
|
||||||
}
|
}
|
||||||
@@ -115,9 +115,9 @@ PPC_FUNC(sub_823B49D8)
|
|||||||
PPC_FUNC_IMPL(__imp__sub_823B4590);
|
PPC_FUNC_IMPL(__imp__sub_823B4590);
|
||||||
PPC_FUNC(sub_823B4590)
|
PPC_FUNC(sub_823B4590)
|
||||||
{
|
{
|
||||||
__imp__sub_823B4590(ctx, base);
|
App::s_pEvilSonicContext = nullptr;
|
||||||
|
|
||||||
App::s_isWerehog = false;
|
__imp__sub_823B4590(ctx, base);
|
||||||
|
|
||||||
SDL_User_EvilSonic(false);
|
SDL_User_EvilSonic(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ PPC_FUNC(sub_824DCF38)
|
|||||||
if (Config::TimeOfDayTransition == ETimeOfDayTransition::PlayStation)
|
if (Config::TimeOfDayTransition == ETimeOfDayTransition::PlayStation)
|
||||||
{
|
{
|
||||||
ctx.r4.u32 = SWA::eLoadingDisplayType_ChangeTimeOfDay;
|
ctx.r4.u32 = SWA::eLoadingDisplayType_ChangeTimeOfDay;
|
||||||
pLoading->m_IsNightToDay = App::s_isWerehog;
|
pLoading->m_IsNightToDay = App::s_pEvilSonicContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config::UseArrowsForTimeOfDayTransition)
|
if (Config::UseArrowsForTimeOfDayTransition)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
inline std::array<const char*, 17> g_credits =
|
inline std::array<const char*, 14> g_credits =
|
||||||
{
|
{
|
||||||
"Skyth",
|
"Skyth",
|
||||||
"Hyper",
|
"Hyper",
|
||||||
@@ -15,8 +15,5 @@ inline std::array<const char*, 17> g_credits =
|
|||||||
"LadyLunanova",
|
"LadyLunanova",
|
||||||
"LJSTAR",
|
"LJSTAR",
|
||||||
"Goalringmod27",
|
"Goalringmod27",
|
||||||
"M&M",
|
"M&M"
|
||||||
"DaGuAr",
|
|
||||||
"brianuuuSonic",
|
|
||||||
"Kitzuku"
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
VERSION_MILESTONE="Release Candidate 2"
|
VERSION_MILESTONE="Beta 3"
|
||||||
VERSION_MAJOR=1
|
VERSION_MAJOR=1
|
||||||
VERSION_MINOR=0
|
VERSION_MINOR=0
|
||||||
VERSION_REVISION=0
|
VERSION_REVISION=0
|
||||||
|
|||||||
@@ -763,7 +763,7 @@ void AchievementMenu::Open()
|
|||||||
return std::get<1>(a) > std::get<1>(b);
|
return std::get<1>(a) > std::get<1>(b);
|
||||||
});
|
});
|
||||||
|
|
||||||
ButtonGuide::Open(Button("Common_Back", FLT_MAX, EButtonIcon::B, EFontQuality::Low));
|
ButtonGuide::Open(Button("Common_Back", EButtonIcon::B));
|
||||||
|
|
||||||
ResetSelection();
|
ResetSelection();
|
||||||
Game_PlaySound("sys_actstg_pausewinopen");
|
Game_PlaySound("sys_actstg_pausewinopen");
|
||||||
|
|||||||
@@ -183,9 +183,6 @@ void AchievementOverlay::Draw()
|
|||||||
IM_COL32(255, 255, 255, 255) // col
|
IM_COL32(255, 255, 255, 255) // col
|
||||||
);
|
);
|
||||||
|
|
||||||
// Use low quality text.
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
|
||||||
|
|
||||||
// Draw header text.
|
// Draw header text.
|
||||||
DrawTextWithShadow
|
DrawTextWithShadow
|
||||||
(
|
(
|
||||||
@@ -211,9 +208,6 @@ void AchievementOverlay::Draw()
|
|||||||
1.0f, // radius
|
1.0f, // radius
|
||||||
IM_COL32(0, 0, 0, 255) // shadowColour
|
IM_COL32(0, 0, 0, 255) // shadowColour
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reset low quality text shader modifier.
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
constexpr float DEFAULT_SIDE_MARGINS = 379;
|
constexpr float DEFAULT_SIDE_MARGINS = 379;
|
||||||
|
|
||||||
ImFont* g_fntNewRodin;
|
ImFont* g_fntNewRodin;
|
||||||
|
ImFont* g_fntNewRodinLQ;
|
||||||
|
|
||||||
std::unique_ptr<GuestTexture> g_upControllerIcons;
|
std::unique_ptr<GuestTexture> g_upControllerIcons;
|
||||||
std::unique_ptr<GuestTexture> g_upKBMIcons;
|
std::unique_ptr<GuestTexture> g_upKBMIcons;
|
||||||
@@ -143,74 +144,79 @@ std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon
|
|||||||
return std::make_tuple(btn, texture);
|
return std::make_tuple(btn, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImFont* GetFont(EFontQuality fontQuality)
|
||||||
|
{
|
||||||
|
return fontQuality == EFontQuality::Low
|
||||||
|
? g_fntNewRodinLQ
|
||||||
|
: g_fntNewRodin;
|
||||||
|
}
|
||||||
|
|
||||||
static void DrawGuide(float* offset, ImVec2 regionMin, ImVec2 regionMax, EButtonIcon icon,
|
static void DrawGuide(float* offset, ImVec2 regionMin, ImVec2 regionMax, EButtonIcon icon,
|
||||||
EButtonAlignment alignment, ImVec2 iconMin, ImVec2 iconMax, EFontQuality fontQuality,
|
EButtonAlignment alignment, ImVec2 iconMin, ImVec2 iconMax, EFontQuality fontQuality,
|
||||||
float textWidth, float maxTextWidth, float textScale, float fontSize, const char* text)
|
ImVec2 textSize, float fontSize, const char* text)
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetBackgroundDrawList();
|
auto drawList = ImGui::GetBackgroundDrawList();
|
||||||
|
auto _icon = icon;
|
||||||
auto iconWidth = Scale(g_iconWidths[icon]);
|
auto iconWidth = Scale(g_iconWidths[icon]);
|
||||||
auto textMarginY = regionMin.y + Scale(9.0f);
|
auto dualIconMarginX = Scale(25);
|
||||||
|
|
||||||
ImVec2 textPos;
|
if (icon == EButtonIcon::LBRB)
|
||||||
|
|
||||||
if (icon == EButtonIcon::LBRB || icon == EButtonIcon::LTRT)
|
|
||||||
{
|
{
|
||||||
auto iconMarginX = Scale(16);
|
_icon = EButtonIcon::LB;
|
||||||
|
}
|
||||||
iconMin.x = alignment == EButtonAlignment::Left
|
else if (icon == EButtonIcon::LTRT)
|
||||||
? regionMin.x + *offset - maxTextWidth + (iconWidth / 2)
|
{
|
||||||
: regionMax.x - *offset - maxTextWidth - (iconWidth / 2) - iconMarginX;
|
_icon = EButtonIcon::LT;
|
||||||
|
|
||||||
iconMax.x = iconMin.x + iconWidth;
|
|
||||||
|
|
||||||
// Left button.
|
|
||||||
auto btnIcon = GetButtonIcon(icon == EButtonIcon::LBRB ? EButtonIcon::LB : EButtonIcon::LT);
|
|
||||||
drawList->AddImage(std::get<1>(btnIcon), iconMin, iconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
|
|
||||||
|
|
||||||
auto dualIconMin = alignment == EButtonAlignment::Left
|
|
||||||
? ImVec2(iconMax.x + maxTextWidth + iconMarginX, iconMin.y)
|
|
||||||
: ImVec2(regionMax.x - *offset + maxTextWidth - iconWidth, iconMin.y);
|
|
||||||
|
|
||||||
auto dualIconMax = ImVec2(dualIconMin.x + iconWidth, iconMax.y);
|
|
||||||
|
|
||||||
// Right button.
|
|
||||||
btnIcon = GetButtonIcon(icon == EButtonIcon::LBRB ? EButtonIcon::RB : EButtonIcon::RT);
|
|
||||||
drawList->AddImage(std::get<1>(btnIcon), dualIconMin, dualIconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
|
|
||||||
|
|
||||||
textPos = { (iconMax.x + ((dualIconMin.x - iconMax.x) - maxTextWidth + std::max(0.0f, maxTextWidth - textWidth)) / 2) + Scale(2), textMarginY};
|
|
||||||
|
|
||||||
*offset += iconWidth;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto btnIcon = GetButtonIcon(icon);
|
dualIconMarginX = 0;
|
||||||
|
|
||||||
drawList->AddImage(std::get<1>(btnIcon), iconMin, iconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
|
|
||||||
|
|
||||||
auto textMarginX = alignment == EButtonAlignment::Left
|
|
||||||
? regionMin.x + *offset
|
|
||||||
: regionMax.x - *offset;
|
|
||||||
|
|
||||||
textPos = { textMarginX, textMarginY };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetScale({ textScale, 1.0f });
|
if (icon == EButtonIcon::LBRB || icon == EButtonIcon::LTRT)
|
||||||
SetOrigin(textPos);
|
|
||||||
|
|
||||||
if (fontQuality == EFontQuality::Low)
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
|
||||||
|
|
||||||
DrawTextWithOutline(g_fntNewRodin, fontSize, textPos, IM_COL32_WHITE, text, 4, IM_COL32_BLACK);
|
|
||||||
|
|
||||||
if (fontQuality == EFontQuality::Low)
|
|
||||||
{
|
{
|
||||||
// Add extra luminance to low quality text.
|
iconMin = alignment == EButtonAlignment::Left
|
||||||
drawList->AddText(g_fntNewRodin, fontSize, textPos, IM_COL32(255, 255, 255, 127), text);
|
? ImVec2(/* X */ regionMin.x + *offset - dualIconMarginX * 3, /* Y */ iconMin.y)
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
: ImVec2(/* X */ regionMax.x - *offset - textSize.x - iconWidth, /* Y */ iconMin.y);
|
||||||
|
|
||||||
|
iconMax = alignment == EButtonAlignment::Left
|
||||||
|
? ImVec2(iconMin.x + iconWidth, iconMax.y)
|
||||||
|
: ImVec2(iconMin.x, iconMax.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetScale({ 1.0f, 1.0f });
|
auto btnIcon = GetButtonIcon(_icon);
|
||||||
SetOrigin({ 0.0f, 0.0f });
|
drawList->AddImage(std::get<1>(btnIcon), iconMin, iconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
|
||||||
|
|
||||||
|
auto font = GetFont(fontQuality);
|
||||||
|
|
||||||
|
auto textMarginX = alignment == EButtonAlignment::Left
|
||||||
|
? regionMin.x + *offset + dualIconMarginX
|
||||||
|
: regionMax.x - *offset - dualIconMarginX * 2;
|
||||||
|
|
||||||
|
auto textMarginY = regionMin.y + Scale(8);
|
||||||
|
|
||||||
|
ImVec2 textPosition = { textMarginX, textMarginY };
|
||||||
|
|
||||||
|
DrawTextWithOutline(font, fontSize, textPosition, IM_COL32_WHITE, text, 4, IM_COL32_BLACK);
|
||||||
|
|
||||||
|
// Add extra luminance to low quality text.
|
||||||
|
if (fontQuality == EFontQuality::Low)
|
||||||
|
drawList->AddText(font, fontSize, textPosition, IM_COL32(255, 255, 255, 127), text);
|
||||||
|
|
||||||
|
if (icon == EButtonIcon::LBRB || icon == EButtonIcon::LTRT)
|
||||||
|
{
|
||||||
|
auto btnIcon = GetButtonIcon(icon == EButtonIcon::LBRB ? EButtonIcon::RB : EButtonIcon::RT);
|
||||||
|
|
||||||
|
auto dualIconMin = alignment == EButtonAlignment::Left
|
||||||
|
? ImVec2(/* X */ regionMin.x + *offset + textSize.x + dualIconMarginX * 2, /* Y */ iconMin.y)
|
||||||
|
: ImVec2(/* X */ regionMax.x - *offset + textSize.x - dualIconMarginX, /* Y */ iconMin.y);
|
||||||
|
|
||||||
|
auto dualIconMax = ImVec2(dualIconMin.x + iconWidth, iconMax.y);
|
||||||
|
|
||||||
|
drawList->AddImage(std::get<1>(btnIcon), dualIconMin, dualIconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
|
||||||
|
|
||||||
|
*offset += dualIconMarginX + iconWidth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ButtonGuide::Init()
|
void ButtonGuide::Init()
|
||||||
@@ -218,6 +224,8 @@ void ButtonGuide::Init()
|
|||||||
auto& io = ImGui::GetIO();
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
g_fntNewRodin = ImFontAtlasSnapshot::GetFont("FOT-NewRodinPro-M.otf");
|
g_fntNewRodin = ImFontAtlasSnapshot::GetFont("FOT-NewRodinPro-M.otf");
|
||||||
|
g_fntNewRodinLQ = ImFontAtlasSnapshot::GetFont("FOT-NewRodinPro-M.otf");
|
||||||
|
|
||||||
g_upControllerIcons = LOAD_ZSTD_TEXTURE(g_controller);
|
g_upControllerIcons = LOAD_ZSTD_TEXTURE(g_controller);
|
||||||
g_upKBMIcons = LOAD_ZSTD_TEXTURE(g_kbm);
|
g_upKBMIcons = LOAD_ZSTD_TEXTURE(g_kbm);
|
||||||
}
|
}
|
||||||
@@ -233,9 +241,10 @@ void ButtonGuide::Draw()
|
|||||||
ImVec2 regionMin = { g_aspectRatioOffsetX + Scale(g_sideMargins), g_aspectRatioOffsetY * 2.0f + Scale(720.0f - 102.0f) };
|
ImVec2 regionMin = { g_aspectRatioOffsetX + Scale(g_sideMargins), g_aspectRatioOffsetY * 2.0f + Scale(720.0f - 102.0f) };
|
||||||
ImVec2 regionMax = { g_aspectRatioOffsetX + Scale(1280.0f - g_sideMargins), g_aspectRatioOffsetY * 2.0f + Scale(720.0f) };
|
ImVec2 regionMax = { g_aspectRatioOffsetX + Scale(1280.0f - g_sideMargins), g_aspectRatioOffsetY * 2.0f + Scale(720.0f) };
|
||||||
|
|
||||||
auto textMarginX = Scale(21.25f);
|
auto textMarginX = Scale(57);
|
||||||
|
auto textMarginY = Scale(8);
|
||||||
auto iconMarginX = Scale(4);
|
auto iconMarginX = Scale(4);
|
||||||
auto fontSize = Scale(21.8f);
|
auto fontSize = Scale(22.5f);
|
||||||
|
|
||||||
auto offsetLeft = 0.0f;
|
auto offsetLeft = 0.0f;
|
||||||
auto offsetRight = 0.0f;
|
auto offsetRight = 0.0f;
|
||||||
@@ -251,20 +260,18 @@ void ButtonGuide::Draw()
|
|||||||
if (btn.Visibility && !*btn.Visibility)
|
if (btn.Visibility && !*btn.Visibility)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto str = Localise(btn.Name).c_str();
|
auto str = Localise(btn.Name.c_str()).c_str();
|
||||||
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
|
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
|
||||||
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
|
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
|
||||||
auto textWidth = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str).x;
|
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str);
|
||||||
auto maxWidth = btn.MaxWidth == FLT_MAX ? textWidth : Scale(btn.MaxWidth);
|
|
||||||
auto textScale = std::min(1.0f, maxWidth / textWidth);
|
|
||||||
|
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
offsetLeft += maxWidth + iconWidth + textMarginX;
|
offsetLeft += textSize.x + iconWidth + textMarginX;
|
||||||
|
|
||||||
ImVec2 iconMin = { regionMin.x + offsetLeft - iconWidth - iconMarginX, regionMin.y };
|
ImVec2 iconMin = { regionMin.x + offsetLeft - iconWidth - iconMarginX, regionMin.y };
|
||||||
ImVec2 iconMax = { regionMin.x + offsetLeft - iconMarginX, regionMin.y + iconHeight };
|
ImVec2 iconMax = { regionMin.x + offsetLeft - iconMarginX, regionMin.y + iconHeight };
|
||||||
|
|
||||||
DrawGuide(&offsetLeft, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textWidth, maxWidth, textScale, fontSize, str);
|
DrawGuide(&offsetLeft, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw right aligned icons.
|
// Draw right aligned icons.
|
||||||
@@ -278,20 +285,18 @@ void ButtonGuide::Draw()
|
|||||||
if (btn.Visibility && !*btn.Visibility)
|
if (btn.Visibility && !*btn.Visibility)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto str = Localise(btn.Name).c_str();
|
auto str = Localise(btn.Name.c_str()).c_str();
|
||||||
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
|
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
|
||||||
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
|
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
|
||||||
auto textWidth = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str).x;
|
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str);
|
||||||
auto maxWidth = btn.MaxWidth == FLT_MAX ? textWidth : Scale(btn.MaxWidth);
|
|
||||||
auto textScale = std::min(1.0f, maxWidth / textWidth);
|
|
||||||
|
|
||||||
if (i < g_buttons.size() - 1)
|
if (i < g_buttons.size() - 1)
|
||||||
offsetRight += maxWidth + iconWidth + textMarginX;
|
offsetRight += textSize.x + iconWidth + textMarginX;
|
||||||
|
|
||||||
ImVec2 iconMin = { regionMax.x - offsetRight - iconWidth - iconMarginX, regionMin.y };
|
ImVec2 iconMin = { regionMax.x - offsetRight - iconWidth - iconMarginX, regionMin.y };
|
||||||
ImVec2 iconMax = { regionMax.x - offsetRight - iconMarginX, regionMin.y + iconHeight };
|
ImVec2 iconMax = { regionMax.x - offsetRight - iconMarginX, regionMin.y + iconHeight };
|
||||||
|
|
||||||
DrawGuide(&offsetRight, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textWidth, maxWidth, textScale, fontSize, str);
|
DrawGuide(&offsetRight, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,23 +40,19 @@ class Button
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::string Name{};
|
std::string Name{};
|
||||||
float MaxWidth{ FLT_MAX };
|
|
||||||
EButtonIcon Icon{};
|
EButtonIcon Icon{};
|
||||||
EButtonAlignment Alignment{ EButtonAlignment::Right };
|
EButtonAlignment Alignment{ EButtonAlignment::Right };
|
||||||
EFontQuality FontQuality{ EFontQuality::High };
|
EFontQuality FontQuality{ EFontQuality::High };
|
||||||
bool* Visibility{ nullptr };
|
bool* Visibility{ nullptr };
|
||||||
|
|
||||||
Button(std::string name, float maxWidth, EButtonIcon icon, EButtonAlignment alignment, EFontQuality fontQuality = EFontQuality::High, bool* visibility = nullptr)
|
Button(std::string name, EButtonIcon icon, EButtonAlignment alignment, EFontQuality fontQuality = EFontQuality::High, bool* visibility = nullptr)
|
||||||
: Name(name), MaxWidth(maxWidth), Icon(icon), Alignment(alignment), FontQuality(fontQuality), Visibility(visibility) {}
|
: Name(name), Icon(icon), Alignment(alignment), FontQuality(fontQuality), Visibility(visibility) {}
|
||||||
|
|
||||||
Button(std::string name, float maxWidth, EButtonIcon icon, EButtonAlignment alignment, bool* visibility)
|
Button(std::string name, EButtonIcon icon, EButtonAlignment alignment, bool* visibility) : Name(name), Icon(icon), Alignment(alignment), Visibility(visibility) {}
|
||||||
: Name(name), MaxWidth(maxWidth), Icon(icon), Alignment(alignment), Visibility(visibility) {}
|
|
||||||
|
|
||||||
Button(std::string name, float maxWidth, EButtonIcon icon, bool* visibility)
|
Button(std::string name, EButtonIcon icon, bool* visibility) : Name(name), Icon(icon), Visibility(visibility) {}
|
||||||
: Name(name), MaxWidth(maxWidth), Icon(icon), Visibility(visibility) {}
|
|
||||||
|
|
||||||
Button(std::string name, float maxWidth, EButtonIcon icon, EFontQuality fontQuality = EFontQuality::High)
|
Button(std::string name, EButtonIcon icon) : Name(name), Icon(icon) {}
|
||||||
: Name(name), MaxWidth(maxWidth), Icon(icon), FontQuality(fontQuality) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ButtonGuide
|
class ButtonGuide
|
||||||
|
|||||||
@@ -378,11 +378,6 @@ SDL_Rect GameWindow::GetDimensions()
|
|||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameWindow::GetSizeInPixels(int *w, int *h)
|
|
||||||
{
|
|
||||||
SDL_GetWindowSizeInPixels(s_pWindow, w, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::SetDimensions(int w, int h, int x, int y)
|
void GameWindow::SetDimensions(int w, int h, int x, int y)
|
||||||
{
|
{
|
||||||
s_width = w;
|
s_width = w;
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ public:
|
|||||||
static bool IsMaximised();
|
static bool IsMaximised();
|
||||||
static EWindowState SetMaximised(bool isEnabled);
|
static EWindowState SetMaximised(bool isEnabled);
|
||||||
static SDL_Rect GetDimensions();
|
static SDL_Rect GetDimensions();
|
||||||
static void GetSizeInPixels(int *w, int *h);
|
|
||||||
static void SetDimensions(int w, int h, int x = SDL_WINDOWPOS_CENTERED, int y = SDL_WINDOWPOS_CENTERED);
|
static void SetDimensions(int w, int h, int x = SDL_WINDOWPOS_CENTERED, int y = SDL_WINDOWPOS_CENTERED);
|
||||||
static void ResetDimensions();
|
static void ResetDimensions();
|
||||||
static uint32_t GetWindowFlags();
|
static uint32_t GetWindowFlags();
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ void ResetGradient()
|
|||||||
|
|
||||||
void SetShaderModifier(uint32_t shaderModifier)
|
void SetShaderModifier(uint32_t shaderModifier)
|
||||||
{
|
{
|
||||||
if (shaderModifier == IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT && Config::DisableLowResolutionFontOnCustomUI)
|
|
||||||
shaderModifier = IMGUI_SHADER_MODIFIER_NONE;
|
|
||||||
|
|
||||||
auto callbackData = AddImGuiCallback(ImGuiCallback::SetShaderModifier);
|
auto callbackData = AddImGuiCallback(ImGuiCallback::SetShaderModifier);
|
||||||
callbackData->setShaderModifier.shaderModifier = shaderModifier;
|
callbackData->setShaderModifier.shaderModifier = shaderModifier;
|
||||||
}
|
}
|
||||||
@@ -464,39 +461,17 @@ std::vector<std::string> Split(const char* strStart, const ImFont* font, float f
|
|||||||
const bool wordWrapEnabled = (maxWidth > 0.0f);
|
const bool wordWrapEnabled = (maxWidth > 0.0f);
|
||||||
const char *wordWrapEOL = nullptr;
|
const char *wordWrapEOL = nullptr;
|
||||||
|
|
||||||
auto IsKanji = [](const char* str, const char* strEnd)
|
|
||||||
{
|
|
||||||
const char* tempStr = str;
|
|
||||||
unsigned int c = (unsigned int)*tempStr;
|
|
||||||
if (c < 0x80)
|
|
||||||
tempStr += 1;
|
|
||||||
else
|
|
||||||
tempStr += ImTextCharFromUtf8(&c, tempStr, strEnd);
|
|
||||||
|
|
||||||
// Basic CJK and CJK Extension A
|
|
||||||
return (c >= 0x4E00 && c <= 0x9FBF) || (c >= 0x3400 && c <= 0x4DBF);
|
|
||||||
};
|
|
||||||
|
|
||||||
while (*str != 0)
|
while (*str != 0)
|
||||||
{
|
{
|
||||||
if (wordWrapEnabled)
|
if (wordWrapEnabled)
|
||||||
{
|
{
|
||||||
if (wordWrapEOL == nullptr)
|
if (wordWrapEOL == nullptr)
|
||||||
{
|
{
|
||||||
wordWrapEOL = CalcWordWrapPositionA(font, scale, str, strEnd, maxWidth - lineWidth);
|
wordWrapEOL = font->CalcWordWrapPositionA(scale, str, strEnd, maxWidth - lineWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str >= wordWrapEOL)
|
if (str >= wordWrapEOL)
|
||||||
{
|
{
|
||||||
if (IsKanji(str, strEnd))
|
|
||||||
{
|
|
||||||
// If the current character is Kanji, move back to prevent splitting Kanji
|
|
||||||
while (str > lineStart && IsKanji(str - 3, strEnd))
|
|
||||||
{
|
|
||||||
str -= 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (textWidth < lineWidth)
|
if (textWidth < lineWidth)
|
||||||
textWidth = lineWidth;
|
textWidth = lineWidth;
|
||||||
|
|
||||||
@@ -670,7 +645,7 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidt
|
|||||||
return MeasureCentredParagraph(font, fontSize, lineMargin, lines);
|
return MeasureCentredParagraph(font, fontSize, lineMargin, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> annotationDrawMethod, bool isCentred, bool leadingSpace)
|
void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> annotationDrawMethod, bool isCentred)
|
||||||
{
|
{
|
||||||
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
|
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
|
||||||
|
|
||||||
@@ -678,13 +653,7 @@ void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, c
|
|||||||
auto lines = Split(input.first.c_str(), font, fontSize, maxWidth);
|
auto lines = Split(input.first.c_str(), font, fontSize, maxWidth);
|
||||||
|
|
||||||
for (auto& line : lines)
|
for (auto& line : lines)
|
||||||
{
|
|
||||||
line = ReAddRubyAnnotations(line, input.second);
|
line = ReAddRubyAnnotations(line, input.second);
|
||||||
if (!line.empty() && line.substr(0, 3) != "「" && leadingSpace)
|
|
||||||
{
|
|
||||||
line.insert(0, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines);
|
auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines);
|
||||||
auto offsetY = 0.0f;
|
auto offsetY = 0.0f;
|
||||||
@@ -854,105 +823,3 @@ void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha)
|
|||||||
drawList->AddImage(g_texLight.get(), min, max, GET_UV_COORDS(lightOffUVs), lightCol);
|
drawList->AddImage(g_texLight.get(), min, max, GET_UV_COORDS(lightOffUVs), lightCol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Taken from ImGui because we need to modify to break for '\u200B\ too
|
|
||||||
// Simple word-wrapping for English, not full-featured. Please submit failing cases!
|
|
||||||
// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end.
|
|
||||||
// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
|
|
||||||
const char* CalcWordWrapPositionA(const ImFont* font, float scale, const char* text, const char* text_end, float wrap_width)
|
|
||||||
{
|
|
||||||
// For references, possible wrap point marked with ^
|
|
||||||
// "aaa bbb, ccc,ddd. eee fff. ggg!"
|
|
||||||
// ^ ^ ^ ^ ^__ ^ ^
|
|
||||||
|
|
||||||
// List of hardcoded separators: .,;!?'"
|
|
||||||
|
|
||||||
// Skip extra blanks after a line returns (that includes not counting them in width computation)
|
|
||||||
// e.g. "Hello world" --> "Hello" "World"
|
|
||||||
|
|
||||||
// Cut words that cannot possibly fit within one line.
|
|
||||||
// e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
|
|
||||||
float line_width = 0.0f;
|
|
||||||
float word_width = 0.0f;
|
|
||||||
float blank_width = 0.0f;
|
|
||||||
wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
|
|
||||||
|
|
||||||
const char* word_end = text;
|
|
||||||
const char* prev_word_end = NULL;
|
|
||||||
bool inside_word = true;
|
|
||||||
|
|
||||||
const char* s = text;
|
|
||||||
IM_ASSERT(text_end != NULL);
|
|
||||||
while (s < text_end)
|
|
||||||
{
|
|
||||||
unsigned int c = (unsigned int)*s;
|
|
||||||
const char* next_s;
|
|
||||||
if (c < 0x80)
|
|
||||||
next_s = s + 1;
|
|
||||||
else
|
|
||||||
next_s = s + ImTextCharFromUtf8(&c, s, text_end);
|
|
||||||
|
|
||||||
if (c < 32)
|
|
||||||
{
|
|
||||||
if (c == '\n')
|
|
||||||
{
|
|
||||||
line_width = word_width = blank_width = 0.0f;
|
|
||||||
inside_word = true;
|
|
||||||
s = next_s;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '\r')
|
|
||||||
{
|
|
||||||
s = next_s;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const float char_width = ((int)c < font->IndexAdvanceX.Size ? font->IndexAdvanceX.Data[c] : font->FallbackAdvanceX);
|
|
||||||
if (ImCharIsBlankW(c) || c == 0x200B)
|
|
||||||
{
|
|
||||||
if (inside_word)
|
|
||||||
{
|
|
||||||
line_width += blank_width;
|
|
||||||
blank_width = 0.0f;
|
|
||||||
word_end = s;
|
|
||||||
}
|
|
||||||
blank_width += char_width;
|
|
||||||
inside_word = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
word_width += char_width;
|
|
||||||
if (inside_word)
|
|
||||||
{
|
|
||||||
word_end = next_s;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
prev_word_end = word_end;
|
|
||||||
line_width += word_width + blank_width;
|
|
||||||
word_width = blank_width = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow wrapping after punctuation.
|
|
||||||
inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"');
|
|
||||||
}
|
|
||||||
|
|
||||||
// We ignore blank width at the end of the line (they can be skipped)
|
|
||||||
if (line_width + word_width > wrap_width)
|
|
||||||
{
|
|
||||||
// Words that cannot possibly fit within an entire line will be cut anywhere.
|
|
||||||
if (word_width < wrap_width)
|
|
||||||
s = prev_word_end ? prev_word_end : word_end;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = next_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
|
|
||||||
// +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol).
|
|
||||||
if (s == text && text < text_end)
|
|
||||||
return s + 1;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ std::vector<std::string> RemoveAnnotationFromParagraph(const std::vector<std::st
|
|||||||
std::string RemoveAnnotationFromParagraphLine(const std::vector<TextSegment>& annotatedLine);
|
std::string RemoveAnnotationFromParagraphLine(const std::vector<TextSegment>& annotatedLine);
|
||||||
ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, const std::vector<std::string>& lines);
|
ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, const std::vector<std::string>& lines);
|
||||||
ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidth, float lineMargin, const char* text);
|
ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidth, float lineMargin, const char* text);
|
||||||
void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> annotationDrawMethod, bool isCentred = false, bool leadingSpace = false);
|
void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> annotationDrawMethod, bool isCentred = false);
|
||||||
float Lerp(float a, float b, float t);
|
float Lerp(float a, float b, float t);
|
||||||
float Cubic(float a, float b, float t);
|
float Cubic(float a, float b, float t);
|
||||||
float Hermite(float a, float b, float t);
|
float Hermite(float a, float b, float t);
|
||||||
@@ -81,4 +81,3 @@ ImU32 ColourLerp(ImU32 c0, ImU32 c1, float t);
|
|||||||
void DrawVersionString(const ImFont* font, const ImU32 col = IM_COL32(255, 255, 255, 70));
|
void DrawVersionString(const ImFont* font, const ImU32 col = IM_COL32(255, 255, 255, 70));
|
||||||
void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop = false);
|
void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop = false);
|
||||||
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha = 1.0f);
|
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha = 1.0f);
|
||||||
const char* CalcWordWrapPositionA(const ImFont* font, float scale, const char* text, const char* text_end, float wrap_width);
|
|
||||||
|
|||||||
@@ -736,14 +736,6 @@ static void DrawDescriptionContainer()
|
|||||||
}
|
}
|
||||||
else if (g_currentPage == WizardPage::InstallFailed)
|
else if (g_currentPage == WizardPage::InstallFailed)
|
||||||
{
|
{
|
||||||
// Japanese needs text to be brought in by a normal width space
|
|
||||||
// as it allows for text to begin further than others for
|
|
||||||
// special characters.
|
|
||||||
if (Config::Language == ELanguage::Japanese)
|
|
||||||
{
|
|
||||||
strncat(descriptionText, " ", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
strncat(descriptionText, g_installerErrorMessage.c_str(), sizeof(descriptionText) - 1);
|
strncat(descriptionText, g_installerErrorMessage.c_str(), sizeof(descriptionText) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,8 +769,6 @@ static void DrawDescriptionContainer()
|
|||||||
|
|
||||||
textX += annotationFontSize;
|
textX += annotationFontSize;
|
||||||
textY += annotationFontSize;
|
textY += annotationFontSize;
|
||||||
|
|
||||||
lineWidth += annotationFontSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drawList->PushClipRect(clipRectMin, clipRectMax, false);
|
drawList->PushClipRect(clipRectMin, clipRectMax, false);
|
||||||
@@ -798,9 +788,7 @@ static void DrawDescriptionContainer()
|
|||||||
[=](const char* str, float size, ImVec2 pos)
|
[=](const char* str, float size, ImVec2 pos)
|
||||||
{
|
{
|
||||||
DrawTextBasic(g_seuratFont, size, pos, IM_COL32(255, 255, 255, 255 * textAlpha), str);
|
DrawTextBasic(g_seuratFont, size, pos, IM_COL32(255, 255, 255, 255 * textAlpha), str);
|
||||||
},
|
}
|
||||||
false,
|
|
||||||
Config::Language == ELanguage::Japanese
|
|
||||||
);
|
);
|
||||||
|
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
@@ -884,7 +872,7 @@ static void DrawDescriptionContainer()
|
|||||||
|
|
||||||
if (g_currentPage == WizardPage::InstallSucceeded && textAlpha >= 1.0)
|
if (g_currentPage == WizardPage::InstallSucceeded && textAlpha >= 1.0)
|
||||||
{
|
{
|
||||||
ButtonGuide::Open(Button("Common_Select", 115.0f, selectIcon));
|
ButtonGuide::Open(Button("Common_Select", selectIcon));
|
||||||
}
|
}
|
||||||
else if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
|
else if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
|
||||||
{
|
{
|
||||||
@@ -896,15 +884,15 @@ static void DrawDescriptionContainer()
|
|||||||
|
|
||||||
std::array<Button, 2> buttons =
|
std::array<Button, 2> buttons =
|
||||||
{
|
{
|
||||||
Button("Common_Select", 115.0f, selectIcon),
|
Button("Common_Select", selectIcon),
|
||||||
Button(backKey, FLT_MAX, backIcon)
|
Button(backKey, backIcon)
|
||||||
};
|
};
|
||||||
|
|
||||||
ButtonGuide::Open(buttons);
|
ButtonGuide::Open(buttons);
|
||||||
}
|
}
|
||||||
else if (g_currentPage == WizardPage::Installing)
|
else if (g_currentPage == WizardPage::Installing)
|
||||||
{
|
{
|
||||||
ButtonGuide::Open(Button("Common_Cancel", FLT_MAX, backIcon));
|
ButtonGuide::Open(Button("Common_Cancel", backIcon));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1411,7 +1399,7 @@ static void DrawNavigationButton()
|
|||||||
|
|
||||||
float squashRatio;
|
float squashRatio;
|
||||||
constexpr float NAV_BUTTON_MAX_TEXT_WIDTH = 90.0f;
|
constexpr float NAV_BUTTON_MAX_TEXT_WIDTH = 90.0f;
|
||||||
std::string_view nextButtonKey = "Installer_Button_Next";
|
const char *nextButtonKey = "Installer_Button_Next";
|
||||||
if (skipButton)
|
if (skipButton)
|
||||||
{
|
{
|
||||||
nextButtonKey = "Installer_Button_Skip";
|
nextButtonKey = "Installer_Button_Skip";
|
||||||
|
|||||||
@@ -223,10 +223,6 @@ void DrawButton(int rowIndex, float yOffset, float width, float height, std::str
|
|||||||
auto fontSize = Scale(28);
|
auto fontSize = Scale(28);
|
||||||
auto textSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, text.c_str());
|
auto textSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, text.c_str());
|
||||||
|
|
||||||
// Show low quality text in-game.
|
|
||||||
if (App::s_isInit)
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
|
||||||
|
|
||||||
DrawTextWithShadow
|
DrawTextWithShadow
|
||||||
(
|
(
|
||||||
g_fntSeurat,
|
g_fntSeurat,
|
||||||
@@ -235,10 +231,6 @@ void DrawButton(int rowIndex, float yOffset, float width, float height, std::str
|
|||||||
isSelected ? IM_COL32(255, 128, 0, 255) : IM_COL32(255, 255, 255, 255),
|
isSelected ? IM_COL32(255, 128, 0, 255) : IM_COL32(255, 255, 255, 255),
|
||||||
text.c_str()
|
text.c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reset the shader modifier.
|
|
||||||
if (App::s_isInit)
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawNextButtonGuide(bool isController, bool isKeyboard)
|
void DrawNextButtonGuide(bool isController, bool isKeyboard)
|
||||||
@@ -249,16 +241,11 @@ void DrawNextButtonGuide(bool isController, bool isKeyboard)
|
|||||||
? EButtonIcon::Enter
|
? EButtonIcon::Enter
|
||||||
: EButtonIcon::LMB;
|
: EButtonIcon::LMB;
|
||||||
|
|
||||||
auto fontQuality = EFontQuality::High;
|
// Always show controller prompt in-game.
|
||||||
|
|
||||||
// Always show controller prompt and low quality text in-game.
|
|
||||||
if (App::s_isInit)
|
if (App::s_isInit)
|
||||||
{
|
|
||||||
icon = EButtonIcon::A;
|
icon = EButtonIcon::A;
|
||||||
fontQuality = EFontQuality::Low;
|
|
||||||
}
|
|
||||||
|
|
||||||
ButtonGuide::Open(Button("Common_Next", FLT_MAX, icon, fontQuality));
|
ButtonGuide::Open(Button("Common_Next", icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ResetSelection()
|
static void ResetSelection()
|
||||||
@@ -351,10 +338,6 @@ void MessageWindow::Draw()
|
|||||||
|
|
||||||
if (DrawContainer(g_appearTime, centre, { textSize.x / 2 + textMarginX, textSize.y / 2 + textMarginY }, !g_isControlsVisible))
|
if (DrawContainer(g_appearTime, centre, { textSize.x / 2 + textMarginX, textSize.y / 2 + textMarginY }, !g_isControlsVisible))
|
||||||
{
|
{
|
||||||
// Use low quality text when the game is booted to not clash with existing UI.
|
|
||||||
if (App::s_isInit)
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
|
||||||
|
|
||||||
DrawRubyAnnotatedText
|
DrawRubyAnnotatedText
|
||||||
(
|
(
|
||||||
g_fntSeurat,
|
g_fntSeurat,
|
||||||
@@ -370,16 +353,12 @@ void MessageWindow::Draw()
|
|||||||
},
|
},
|
||||||
[=](const char* str, float size, ImVec2 pos)
|
[=](const char* str, float size, ImVec2 pos)
|
||||||
{
|
{
|
||||||
DrawTextWithShadow(g_fntSeurat, size, pos, IM_COL32(255, 255, 255, 255), str, 1.5f, 1.5f);
|
DrawTextWithShadow(g_fntSeurat, size, pos, IM_COL32(255, 255, 255, 255), str, 1.0f);
|
||||||
},
|
},
|
||||||
|
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reset the shader modifier.
|
|
||||||
if (App::s_isInit)
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
|
||||||
|
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
|
|
||||||
if (g_buttons.size())
|
if (g_buttons.size())
|
||||||
@@ -444,17 +423,10 @@ void MessageWindow::Draw()
|
|||||||
backIcon = EButtonIcon::Escape;
|
backIcon = EButtonIcon::Escape;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fontQuality = EFontQuality::High;
|
|
||||||
if (App::s_isInit)
|
|
||||||
{
|
|
||||||
// Show low quality text in-game.
|
|
||||||
fontQuality = EFontQuality::Low;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<Button, 2> buttons =
|
std::array<Button, 2> buttons =
|
||||||
{
|
{
|
||||||
Button("Common_Select", 115.0f, selectIcon, fontQuality),
|
Button("Common_Select", selectIcon),
|
||||||
Button("Common_Back", FLT_MAX, backIcon, fontQuality),
|
Button("Common_Back", backIcon),
|
||||||
};
|
};
|
||||||
|
|
||||||
ButtonGuide::Open(buttons);
|
ButtonGuide::Open(buttons);
|
||||||
@@ -498,8 +470,8 @@ void MessageWindow::Draw()
|
|||||||
|
|
||||||
std::array<Button, 2> buttons =
|
std::array<Button, 2> buttons =
|
||||||
{
|
{
|
||||||
Button("Common_Select", 115.0f, EButtonIcon::LMB),
|
Button("Common_Select", EButtonIcon::LMB),
|
||||||
Button("Common_Back", FLT_MAX, EButtonIcon::Escape),
|
Button("Common_Back", EButtonIcon::Escape),
|
||||||
};
|
};
|
||||||
|
|
||||||
ButtonGuide::Open(buttons);
|
ButtonGuide::Open(buttons);
|
||||||
|
|||||||
@@ -449,8 +449,11 @@ static bool DrawCategories()
|
|||||||
|
|
||||||
auto inputState = SWA::CInputState::GetInstance();
|
auto inputState = SWA::CInputState::GetInstance();
|
||||||
|
|
||||||
bool moveLeft = !g_lockedOnOption && inputState->GetPadState().IsTapped(SWA::eKeyState_LeftBumper);
|
bool moveLeft = !g_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_LeftBumper) ||
|
||||||
bool moveRight = !g_lockedOnOption && inputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper);
|
inputState->GetPadState().IsTapped(SWA::eKeyState_LeftTrigger));
|
||||||
|
|
||||||
|
bool moveRight = !g_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper) ||
|
||||||
|
inputState->GetPadState().IsTapped(SWA::eKeyState_RightTrigger));
|
||||||
|
|
||||||
if (moveLeft)
|
if (moveLeft)
|
||||||
{
|
{
|
||||||
@@ -1121,25 +1124,17 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
|||||||
{
|
{
|
||||||
if (config == &Config::WindowSize)
|
if (config == &Config::WindowSize)
|
||||||
{
|
{
|
||||||
if (Config::Fullscreen)
|
auto displayModes = GameWindow::GetDisplayModes();
|
||||||
|
|
||||||
|
if (config->Value >= 0 && config->Value < displayModes.size())
|
||||||
{
|
{
|
||||||
int displayW, displayH;
|
auto& displayMode = displayModes[config->Value];
|
||||||
GameWindow::GetSizeInPixels(&displayW, &displayH);
|
|
||||||
valueText = fmt::format("{}x{}", displayW, displayH);
|
valueText = fmt::format("{}x{}", displayMode.w, displayMode.h);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto displayModes = GameWindow::GetDisplayModes();
|
valueText = fmt::format("{}x{}", GameWindow::s_width, GameWindow::s_height);
|
||||||
if (config->Value >= 0 && config->Value < displayModes.size())
|
|
||||||
{
|
|
||||||
auto& displayMode = displayModes[config->Value];
|
|
||||||
|
|
||||||
valueText = fmt::format("{}x{}", displayMode.w, displayMode.h);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
valueText = fmt::format("{}x{}", GameWindow::s_width, GameWindow::s_height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (config == &Config::Monitor)
|
else if (config == &Config::Monitor)
|
||||||
@@ -1466,7 +1461,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
|||||||
|
|
||||||
if (g_inaccessibleReason)
|
if (g_inaccessibleReason)
|
||||||
{
|
{
|
||||||
desc += "\n\n" + *g_inaccessibleReason;
|
desc = *g_inaccessibleReason;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1484,9 +1479,10 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& valueDescription = g_selectedItem->GetValueDescription(Config::Language);
|
const auto& valueDescription = g_selectedItem->GetValueDescription(Config::Language);
|
||||||
|
|
||||||
if (!valueDescription.empty())
|
if (!valueDescription.empty())
|
||||||
|
{
|
||||||
desc += "\n\n" + valueDescription;
|
desc += "\n\n" + valueDescription;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clipRectMin = { clipRectMin.x, thumbnailMax.y };
|
clipRectMin = { clipRectMin.x, thumbnailMax.y };
|
||||||
@@ -1501,7 +1497,6 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
|||||||
|
|
||||||
auto textX = clipRectMin.x - Scale(0.5f);
|
auto textX = clipRectMin.x - Scale(0.5f);
|
||||||
auto textY = thumbnailMax.y + offsetY;
|
auto textY = thumbnailMax.y + offsetY;
|
||||||
float lineWidth = clipRectMax.x - clipRectMin.x;
|
|
||||||
|
|
||||||
if (Config::Language == ELanguage::Japanese)
|
if (Config::Language == ELanguage::Japanese)
|
||||||
{
|
{
|
||||||
@@ -1516,13 +1511,9 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
|||||||
clipRectMax.x += annotationFontSize;
|
clipRectMax.x += annotationFontSize;
|
||||||
|
|
||||||
textY += annotationFontSize;
|
textY += annotationFontSize;
|
||||||
|
|
||||||
// Dirty hack to disallow clipping on Japanese text
|
|
||||||
// whilst allowing annotations to go over the border
|
|
||||||
lineWidth -= annotationFontSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, lineWidth, 5.0f, desc.c_str());
|
auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, clipRectMax.x - clipRectMin.x, 5.0f, desc.c_str());
|
||||||
|
|
||||||
drawList->PushClipRect(clipRectMin, clipRectMax, false);
|
drawList->PushClipRect(clipRectMin, clipRectMax, false);
|
||||||
|
|
||||||
@@ -1598,7 +1589,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
|||||||
(
|
(
|
||||||
g_seuratFont,
|
g_seuratFont,
|
||||||
fontSize,
|
fontSize,
|
||||||
lineWidth,
|
clipRectMax.x - clipRectMin.x,
|
||||||
{ textX, textY - scrollOffset },
|
{ textX, textY - scrollOffset },
|
||||||
5.0f,
|
5.0f,
|
||||||
desc.c_str(),
|
desc.c_str(),
|
||||||
@@ -1799,10 +1790,10 @@ void OptionsMenu::Open(bool isPause, SWA::EMenuType pauseMenuType)
|
|||||||
|
|
||||||
std::array<Button, 4> buttons =
|
std::array<Button, 4> buttons =
|
||||||
{
|
{
|
||||||
Button("Common_Switch", 115.0f, EButtonIcon::LBRB, EButtonAlignment::Left, &g_isControlsVisible),
|
Button("Common_Switch", EButtonIcon::LBRB, EButtonAlignment::Left, &g_isControlsVisible),
|
||||||
Button("Common_Reset", 110.0f, EButtonIcon::X, &g_canReset),
|
Button("Common_Reset", EButtonIcon::X, &g_canReset),
|
||||||
Button("Common_Select", 115.0f, EButtonIcon::A, &g_isControlsVisible),
|
Button("Common_Select", EButtonIcon::A, &g_isControlsVisible),
|
||||||
Button("Common_Back", 65.0f, EButtonIcon::B, &g_isControlsVisible)
|
Button("Common_Back", EButtonIcon::B, &g_isControlsVisible)
|
||||||
};
|
};
|
||||||
|
|
||||||
ButtonGuide::Open(buttons);
|
ButtonGuide::Open(buttons);
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
#include <decompressor.h>
|
#include <decompressor.h>
|
||||||
#include <hid/hid.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/achievement_notifications.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/allow_background_input_xb.dds.h>
|
#include <res/images/options_menu/thumbnails/allow_background_input.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/allow_background_input_ps.dds.h>
|
|
||||||
#include <res/images/options_menu/thumbnails/antialiasing_none.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_2x.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/antialiasing_4x.dds.h>
|
#include <res/images/options_menu/thumbnails/antialiasing_4x.dds.h>
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
#include <res/images/options_menu/thumbnails/brightness.dds.h>
|
#include <res/images/options_menu/thumbnails/brightness.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/channel_stereo.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/channel_surround.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/control_tutorial_ps.dds.h>
|
|
||||||
#include <res/images/options_menu/thumbnails/control_tutorial_xb.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/controller_icons.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/default.dds.h>
|
#include <res/images/options_menu/thumbnails/default.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/effects_volume.dds.h>
|
#include <res/images/options_menu/thumbnails/effects_volume.dds.h>
|
||||||
@@ -35,21 +35,23 @@
|
|||||||
#include <res/images/options_menu/thumbnails/movie_scale_fill.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_attenuation.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/music_volume.dds.h>
|
#include <res/images/options_menu/thumbnails/music_volume.dds.h>
|
||||||
|
#include <res/images/options_menu/thumbnails/resolution_scale.dds.h>
|
||||||
|
#include <res/images/options_menu/thumbnails/shadow_resolution_original.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x512.dds.h>
|
#include <res/images/options_menu/thumbnails/shadow_resolution_x512.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x1024.dds.h>
|
#include <res/images/options_menu/thumbnails/shadow_resolution_x1024.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x2048.dds.h>
|
#include <res/images/options_menu/thumbnails/shadow_resolution_x2048.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x4096.dds.h>
|
#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/shadow_resolution_x8192.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/time_transition_ps.dds.h>
|
#include <res/images/options_menu/thumbnails/subtitles.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/time_transition_xb.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_false.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/transparency_antialiasing_true.dds.h>
|
#include <res/images/options_menu/thumbnails/transparency_antialiasing_true.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/ui_alignment_centre.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/ui_alignment_edge.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/vertical_camera.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/voice_language.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/vibration_ps.dds.h>
|
#include <res/images/options_menu/thumbnails/vibration.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/vibration_xb.dds.h>
|
|
||||||
#include <res/images/options_menu/thumbnails/vsync_on.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/vsync_off.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/window_size.dds.h>
|
#include <res/images/options_menu/thumbnails/window_size.dds.h>
|
||||||
@@ -57,15 +59,7 @@
|
|||||||
|
|
||||||
#define VALUE_THUMBNAIL_MAP(type) std::unordered_map<type, std::unique_ptr<GuestTexture>>
|
#define VALUE_THUMBNAIL_MAP(type) std::unordered_map<type, std::unique_ptr<GuestTexture>>
|
||||||
|
|
||||||
static std::unique_ptr<GuestTexture> g_defaultThumbnail;
|
static std::unordered_map<std::string_view, std::unique_ptr<GuestTexture>> g_namedThumbnails;
|
||||||
|
|
||||||
static std::unique_ptr<GuestTexture> g_controlTutorialXBThumbnail;
|
|
||||||
static std::unique_ptr<GuestTexture> g_controlTutorialPSThumbnail;
|
|
||||||
static std::unique_ptr<GuestTexture> g_vibrationXBThumbnail;
|
|
||||||
static std::unique_ptr<GuestTexture> g_vibrationPSThumbnail;
|
|
||||||
static std::unique_ptr<GuestTexture> g_backgroundInputXBThumbnail;
|
|
||||||
static std::unique_ptr<GuestTexture> g_backgroundInputPSThumbnail;
|
|
||||||
|
|
||||||
static std::unordered_map<const IConfigDef*, std::unique_ptr<GuestTexture>> g_configThumbnails;
|
static std::unordered_map<const IConfigDef*, std::unique_ptr<GuestTexture>> g_configThumbnails;
|
||||||
|
|
||||||
static VALUE_THUMBNAIL_MAP(ETimeOfDayTransition) g_timeOfDayTransitionThumbnails;
|
static VALUE_THUMBNAIL_MAP(ETimeOfDayTransition) g_timeOfDayTransitionThumbnails;
|
||||||
@@ -82,17 +76,14 @@ static VALUE_THUMBNAIL_MAP(EUIAlignmentMode) g_uiAlignmentThumbnails;
|
|||||||
|
|
||||||
void LoadThumbnails()
|
void LoadThumbnails()
|
||||||
{
|
{
|
||||||
g_defaultThumbnail = LOAD_ZSTD_TEXTURE(g_default);
|
g_namedThumbnails["Default"] = LOAD_ZSTD_TEXTURE(g_default);
|
||||||
|
g_namedThumbnails["WindowSize"] = LOAD_ZSTD_TEXTURE(g_window_size);
|
||||||
g_controlTutorialXBThumbnail = LOAD_ZSTD_TEXTURE(g_control_tutorial_xb);
|
g_namedThumbnails["ControlTutorialXB"] = LOAD_ZSTD_TEXTURE(g_control_tutorial_xb);
|
||||||
g_controlTutorialPSThumbnail = LOAD_ZSTD_TEXTURE(g_control_tutorial_ps);
|
g_namedThumbnails["ControlTutorialPS"] = LOAD_ZSTD_TEXTURE(g_control_tutorial_ps);
|
||||||
g_vibrationXBThumbnail = LOAD_ZSTD_TEXTURE(g_vibration_xb);
|
|
||||||
g_vibrationPSThumbnail = LOAD_ZSTD_TEXTURE(g_vibration_ps);
|
|
||||||
g_backgroundInputXBThumbnail = LOAD_ZSTD_TEXTURE(g_allow_background_input_xb);
|
|
||||||
g_backgroundInputPSThumbnail = LOAD_ZSTD_TEXTURE(g_allow_background_input_ps);
|
|
||||||
|
|
||||||
g_configThumbnails[&Config::Language] = LOAD_ZSTD_TEXTURE(g_language);
|
g_configThumbnails[&Config::Language] = LOAD_ZSTD_TEXTURE(g_language);
|
||||||
g_configThumbnails[&Config::VoiceLanguage] = LOAD_ZSTD_TEXTURE(g_voice_language);
|
g_configThumbnails[&Config::VoiceLanguage] = LOAD_ZSTD_TEXTURE(g_voice_language);
|
||||||
|
g_configThumbnails[&Config::Subtitles] = LOAD_ZSTD_TEXTURE(g_subtitles);
|
||||||
g_configThumbnails[&Config::Hints] = LOAD_ZSTD_TEXTURE(g_hints);
|
g_configThumbnails[&Config::Hints] = LOAD_ZSTD_TEXTURE(g_hints);
|
||||||
g_configThumbnails[&Config::AchievementNotifications] = LOAD_ZSTD_TEXTURE(g_achievement_notifications);
|
g_configThumbnails[&Config::AchievementNotifications] = LOAD_ZSTD_TEXTURE(g_achievement_notifications);
|
||||||
|
|
||||||
@@ -101,6 +92,8 @@ void LoadThumbnails()
|
|||||||
|
|
||||||
g_configThumbnails[&Config::HorizontalCamera] = LOAD_ZSTD_TEXTURE(g_horizontal_camera);
|
g_configThumbnails[&Config::HorizontalCamera] = LOAD_ZSTD_TEXTURE(g_horizontal_camera);
|
||||||
g_configThumbnails[&Config::VerticalCamera] = LOAD_ZSTD_TEXTURE(g_vertical_camera);
|
g_configThumbnails[&Config::VerticalCamera] = LOAD_ZSTD_TEXTURE(g_vertical_camera);
|
||||||
|
g_configThumbnails[&Config::Vibration] = LOAD_ZSTD_TEXTURE(g_vibration);
|
||||||
|
g_configThumbnails[&Config::AllowBackgroundInput] = LOAD_ZSTD_TEXTURE(g_allow_background_input);
|
||||||
g_configThumbnails[&Config::ControllerIcons] = LOAD_ZSTD_TEXTURE(g_controller_icons);
|
g_configThumbnails[&Config::ControllerIcons] = LOAD_ZSTD_TEXTURE(g_controller_icons);
|
||||||
g_configThumbnails[&Config::MasterVolume] = LOAD_ZSTD_TEXTURE(g_master_volume);
|
g_configThumbnails[&Config::MasterVolume] = LOAD_ZSTD_TEXTURE(g_master_volume);
|
||||||
g_configThumbnails[&Config::MusicVolume] = LOAD_ZSTD_TEXTURE(g_music_volume);
|
g_configThumbnails[&Config::MusicVolume] = LOAD_ZSTD_TEXTURE(g_music_volume);
|
||||||
@@ -114,8 +107,8 @@ void LoadThumbnails()
|
|||||||
g_configThumbnails[&Config::WindowSize] = LOAD_ZSTD_TEXTURE(g_window_size);
|
g_configThumbnails[&Config::WindowSize] = LOAD_ZSTD_TEXTURE(g_window_size);
|
||||||
g_configThumbnails[&Config::Monitor] = LOAD_ZSTD_TEXTURE(g_monitor);
|
g_configThumbnails[&Config::Monitor] = LOAD_ZSTD_TEXTURE(g_monitor);
|
||||||
g_configThumbnails[&Config::AspectRatio] = LOAD_ZSTD_TEXTURE(g_aspect_ratio);
|
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::Fullscreen] = LOAD_ZSTD_TEXTURE(g_fullscreen);
|
||||||
g_configThumbnails[&Config::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
|
|
||||||
|
|
||||||
g_vsyncThumbnails[false] = LOAD_ZSTD_TEXTURE(g_vsync_off);
|
g_vsyncThumbnails[false] = LOAD_ZSTD_TEXTURE(g_vsync_off);
|
||||||
g_vsyncThumbnails[true] = LOAD_ZSTD_TEXTURE(g_vsync_on);
|
g_vsyncThumbnails[true] = LOAD_ZSTD_TEXTURE(g_vsync_on);
|
||||||
@@ -131,6 +124,7 @@ void LoadThumbnails()
|
|||||||
g_transparencyAntiAliasingThumbnails[false] = LOAD_ZSTD_TEXTURE(g_transparency_antialiasing_false);
|
g_transparencyAntiAliasingThumbnails[false] = LOAD_ZSTD_TEXTURE(g_transparency_antialiasing_false);
|
||||||
g_transparencyAntiAliasingThumbnails[true] = LOAD_ZSTD_TEXTURE(g_transparency_antialiasing_true);
|
g_transparencyAntiAliasingThumbnails[true] = LOAD_ZSTD_TEXTURE(g_transparency_antialiasing_true);
|
||||||
|
|
||||||
|
g_shadowResolutionThumbnails[EShadowResolution::Original] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_original);
|
||||||
g_shadowResolutionThumbnails[EShadowResolution::x512] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x512);
|
g_shadowResolutionThumbnails[EShadowResolution::x512] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x512);
|
||||||
g_shadowResolutionThumbnails[EShadowResolution::x1024] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x1024);
|
g_shadowResolutionThumbnails[EShadowResolution::x1024] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x1024);
|
||||||
g_shadowResolutionThumbnails[EShadowResolution::x2048] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x2048);
|
g_shadowResolutionThumbnails[EShadowResolution::x2048] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x2048);
|
||||||
@@ -149,6 +143,8 @@ void LoadThumbnails()
|
|||||||
|
|
||||||
g_uiAlignmentThumbnails[EUIAlignmentMode::Centre] = LOAD_ZSTD_TEXTURE(g_ui_alignment_centre);
|
g_uiAlignmentThumbnails[EUIAlignmentMode::Centre] = LOAD_ZSTD_TEXTURE(g_ui_alignment_centre);
|
||||||
g_uiAlignmentThumbnails[EUIAlignmentMode::Edge] = LOAD_ZSTD_TEXTURE(g_ui_alignment_edge);
|
g_uiAlignmentThumbnails[EUIAlignmentMode::Edge] = LOAD_ZSTD_TEXTURE(g_ui_alignment_edge);
|
||||||
|
|
||||||
|
g_configThumbnails[&Config::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -160,50 +156,40 @@ bool TryGetValueThumbnail(const IConfigDef* cfg, VALUE_THUMBNAIL_MAP(T)* thumbna
|
|||||||
if (!cfg->GetValue())
|
if (!cfg->GetValue())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
T value = *(T*)cfg->GetValue();
|
auto result = thumbnails->at(*(T*)cfg->GetValue()).get();
|
||||||
|
|
||||||
if constexpr (std::is_same_v<T, EShadowResolution>)
|
if (!result)
|
||||||
{
|
return false;
|
||||||
if (value == EShadowResolution::Original)
|
|
||||||
value = EShadowResolution::x1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto findResult = thumbnails->find(value);
|
*texture = result;
|
||||||
|
|
||||||
if (findResult != thumbnails->end())
|
return true;
|
||||||
{
|
}
|
||||||
*texture = findResult->second.get();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
GuestTexture* GetThumbnail(const std::string_view name)
|
||||||
|
{
|
||||||
|
if (!g_namedThumbnails.count(name))
|
||||||
|
return g_namedThumbnails["Default"].get();
|
||||||
|
|
||||||
|
return g_namedThumbnails[name].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
GuestTexture* GetThumbnail(const IConfigDef* cfg)
|
GuestTexture* GetThumbnail(const IConfigDef* cfg)
|
||||||
{
|
{
|
||||||
auto findResult = g_configThumbnails.find(cfg);
|
if (!g_configThumbnails.count(cfg))
|
||||||
if (findResult == g_configThumbnails.end())
|
|
||||||
{
|
{
|
||||||
auto texture = g_defaultThumbnail.get();
|
auto texture = g_namedThumbnails["Default"].get();
|
||||||
|
|
||||||
bool isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation;
|
|
||||||
|
|
||||||
if (Config::ControllerIcons == EControllerIcons::Auto)
|
|
||||||
isPlayStation = hid::g_inputDeviceController == hid::EInputDevice::PlayStation;
|
|
||||||
|
|
||||||
if (cfg == &Config::ControlTutorial)
|
if (cfg == &Config::ControlTutorial)
|
||||||
{
|
{
|
||||||
texture = isPlayStation ? g_controlTutorialPSThumbnail.get() : g_controlTutorialXBThumbnail.get();
|
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();
|
||||||
}
|
}
|
||||||
else if (cfg == &Config::Vibration)
|
if (cfg == &Config::TimeOfDayTransition)
|
||||||
{
|
|
||||||
texture = isPlayStation ? g_vibrationPSThumbnail.get() : g_vibrationXBThumbnail.get();
|
|
||||||
}
|
|
||||||
else if (cfg == &Config::AllowBackgroundInput)
|
|
||||||
{
|
|
||||||
texture = isPlayStation ? g_backgroundInputPSThumbnail.get() : g_backgroundInputXBThumbnail.get();
|
|
||||||
}
|
|
||||||
else if (cfg == &Config::TimeOfDayTransition)
|
|
||||||
{
|
{
|
||||||
TryGetValueThumbnail<ETimeOfDayTransition>(cfg, &g_timeOfDayTransitionThumbnails, &texture);
|
TryGetValueThumbnail<ETimeOfDayTransition>(cfg, &g_timeOfDayTransitionThumbnails, &texture);
|
||||||
}
|
}
|
||||||
@@ -251,5 +237,5 @@ GuestTexture* GetThumbnail(const IConfigDef* cfg)
|
|||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
return findResult->second.get();
|
return g_configThumbnails[cfg].get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,4 +5,5 @@
|
|||||||
|
|
||||||
void LoadThumbnails();
|
void LoadThumbnails();
|
||||||
|
|
||||||
|
GuestTexture* GetThumbnail(const std::string_view name);
|
||||||
GuestTexture* GetThumbnail(const IConfigDef* cfg);
|
GuestTexture* GetThumbnail(const IConfigDef* cfg);
|
||||||
|
|||||||
@@ -511,33 +511,43 @@ std::string_view ConfigDef<T, isHidden>::GetName() const
|
|||||||
template<typename T, bool isHidden>
|
template<typename T, bool isHidden>
|
||||||
std::string ConfigDef<T, isHidden>::GetNameLocalised(ELanguage language) const
|
std::string ConfigDef<T, isHidden>::GetNameLocalised(ELanguage language) const
|
||||||
{
|
{
|
||||||
if (Locale != nullptr)
|
if (!Locale)
|
||||||
{
|
return Name;
|
||||||
auto languageFindResult = Locale->find(language);
|
|
||||||
if (languageFindResult == Locale->end())
|
|
||||||
languageFindResult = Locale->find(ELanguage::English);
|
|
||||||
|
|
||||||
if (languageFindResult != Locale->end())
|
if (!Locale->count(language))
|
||||||
return std::get<0>(languageFindResult->second);
|
{
|
||||||
|
if (Locale->count(ELanguage::English))
|
||||||
|
{
|
||||||
|
return std::get<0>(Locale->at(ELanguage::English));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Name;
|
return std::get<0>(Locale->at(language));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool isHidden>
|
template<typename T, bool isHidden>
|
||||||
std::string ConfigDef<T, isHidden>::GetDescription(ELanguage language) const
|
std::string ConfigDef<T, isHidden>::GetDescription(ELanguage language) const
|
||||||
{
|
{
|
||||||
if (Locale != nullptr)
|
if (!Locale)
|
||||||
{
|
return "";
|
||||||
auto languageFindResult = Locale->find(language);
|
|
||||||
if (languageFindResult == Locale->end())
|
|
||||||
languageFindResult = Locale->find(ELanguage::English);
|
|
||||||
|
|
||||||
if (languageFindResult != Locale->end())
|
if (!Locale->count(language))
|
||||||
return std::get<1>(languageFindResult->second);
|
{
|
||||||
|
if (Locale->count(ELanguage::English))
|
||||||
|
{
|
||||||
|
return std::get<1>(Locale->at(ELanguage::English));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return std::get<1>(Locale->at(language));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool isHidden>
|
template<typename T, bool isHidden>
|
||||||
@@ -568,27 +578,27 @@ std::string ConfigDef<T, isHidden>::GetValueLocalised(ELanguage language) const
|
|||||||
: Localise("Common_Off");
|
: Localise("Common_Off");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locale != nullptr)
|
if (!locale)
|
||||||
|
return ToString(false);
|
||||||
|
|
||||||
|
if (!locale->count(language))
|
||||||
{
|
{
|
||||||
ELanguage languages[] = { language, ELanguage::English };
|
if (locale->count(ELanguage::English))
|
||||||
|
|
||||||
for (auto languageToFind : languages)
|
|
||||||
{
|
{
|
||||||
auto languageFindResult = locale->find(languageToFind);
|
language = ELanguage::English;
|
||||||
|
}
|
||||||
if (languageFindResult != locale->end())
|
else
|
||||||
{
|
{
|
||||||
auto valueFindResult = languageFindResult->second.find(Value);
|
return ToString(false);
|
||||||
if (valueFindResult != languageFindResult->second.end())
|
|
||||||
return std::get<0>(valueFindResult->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (languageToFind == ELanguage::English)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ToString(false);
|
auto strings = locale->at(language);
|
||||||
|
|
||||||
|
if (!strings.count(Value))
|
||||||
|
return ToString(false);
|
||||||
|
|
||||||
|
return std::get<0>(strings.at(Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool isHidden>
|
template<typename T, bool isHidden>
|
||||||
@@ -605,27 +615,27 @@ std::string ConfigDef<T, isHidden>::GetValueDescription(ELanguage language) cons
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locale != nullptr)
|
if (!locale)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if (!locale->count(language))
|
||||||
{
|
{
|
||||||
ELanguage languages[] = { language, ELanguage::English };
|
if (locale->count(ELanguage::English))
|
||||||
|
|
||||||
for (auto languageToFind : languages)
|
|
||||||
{
|
{
|
||||||
auto languageFindResult = locale->find(languageToFind);
|
language = ELanguage::English;
|
||||||
|
}
|
||||||
if (languageFindResult != locale->end())
|
else
|
||||||
{
|
{
|
||||||
auto valueFindResult = languageFindResult->second.find(Value);
|
return "";
|
||||||
if (valueFindResult != languageFindResult->second.end())
|
|
||||||
return std::get<1>(valueFindResult->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (languageToFind == ELanguage::English)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
auto strings = locale->at(language);
|
||||||
|
|
||||||
|
if (!strings.count(Value))
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return std::get<1>(strings.at(Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, bool isHidden>
|
template<typename T, bool isHidden>
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ CONFIG_DEFINE_HIDDEN("Codes", bool, DisableAutoSaveWarning, false);
|
|||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableDLCIcon, false);
|
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableDLCIcon, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableDWMRoundedCorners, false);
|
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableDWMRoundedCorners, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableEventCollisionDebugView, false);
|
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableEventCollisionDebugView, false);
|
||||||
|
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableFreeCamera, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableGIMipLevelDebugView, false);
|
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableGIMipLevelDebugView, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableObjectCollisionDebugView, false);
|
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableObjectCollisionDebugView, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableStageCollisionDebugView, false);
|
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableStageCollisionDebugView, false);
|
||||||
@@ -91,6 +92,5 @@ CONFIG_DEFINE_HIDDEN("Codes", bool, SaveScoreAtCheckpoints, false);
|
|||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, SkipIntroLogos, false);
|
CONFIG_DEFINE_HIDDEN("Codes", bool, SkipIntroLogos, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, UseArrowsForTimeOfDayTransition, false);
|
CONFIG_DEFINE_HIDDEN("Codes", bool, UseArrowsForTimeOfDayTransition, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, UseOfficialTitleOnTitleBar, false);
|
CONFIG_DEFINE_HIDDEN("Codes", bool, UseOfficialTitleOnTitleBar, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableLowResolutionFontOnCustomUI, false);
|
|
||||||
|
|
||||||
CONFIG_DEFINE("Update", time_t, LastChecked, 0);
|
CONFIG_DEFINE("Update", time_t, LastChecked, 0);
|
||||||
|
|||||||
@@ -28,10 +28,7 @@ endforeach()
|
|||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${UNLEASHED_RECOMP_PPC_RECOMPILED_SOURCES}
|
OUTPUT ${UNLEASHED_RECOMP_PPC_RECOMPILED_SOURCES}
|
||||||
COMMAND $<TARGET_FILE:XenonRecomp>
|
COMMAND $<TARGET_FILE:XenonRecomp>
|
||||||
DEPENDS
|
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex" "${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex"
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xexp"
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(XENOS_RECOMP_ROOT "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/XenosRecomp")
|
set(XENOS_RECOMP_ROOT "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/XenosRecomp")
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[main]
|
[main]
|
||||||
file_path = "../private/default.xex"
|
file_path = "../private/default.xex"
|
||||||
patch_file_path = "../private/default.xexp"
|
|
||||||
patched_file_path = "../private/default_patched.xex"
|
|
||||||
out_directory_path = "../ppc"
|
out_directory_path = "../ppc"
|
||||||
switch_table_file_path = "SWA_switch_tables.toml"
|
switch_table_file_path = "SWA_switch_tables.toml"
|
||||||
|
|
||||||
@@ -1090,6 +1088,19 @@ address = 0x82BB38E4
|
|||||||
registers = ["r31", "r29", "r28"]
|
registers = ["r31", "r29", "r28"]
|
||||||
|
|
||||||
[[midasm_hook]]
|
[[midasm_hook]]
|
||||||
name = "ObjGrindDashPanelAllocMidAsmHook"
|
name = "FreeCameraSpeedInputMidAsmHook"
|
||||||
address = 0x82614948
|
address = 0x82472A7C
|
||||||
registers = ["r3"]
|
registers = ["r31", "r29", "f0"]
|
||||||
|
jump_address_on_true = 0x82472AC4
|
||||||
|
|
||||||
|
# Disable start/end tool input.
|
||||||
|
[[midasm_hook]]
|
||||||
|
name = "FreeCameraActiveMidAsmHook"
|
||||||
|
address = 0x825D7690
|
||||||
|
jump_address_on_true = 0x825D7704
|
||||||
|
|
||||||
|
# Disable deactivation input.
|
||||||
|
[[midasm_hook]]
|
||||||
|
name = "FreeCameraActiveMidAsmHook"
|
||||||
|
address = 0x825D745C
|
||||||
|
jump_address_on_true = 0x825D768C
|
||||||
|
|||||||
+1
-1
Submodule UnleashedRecompResources updated: 89c82c0aa8...5ba3baac5a
@@ -38,16 +38,6 @@
|
|||||||
"path": "private/default.xex",
|
"path": "private/default.xex",
|
||||||
"dest": "UnleashedRecompLib/private"
|
"dest": "UnleashedRecompLib/private"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"path": "private/default.xexp",
|
|
||||||
"dest": "UnleashedRecompLib/private"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"path": "private/default_patched.xex",
|
|
||||||
"dest": "UnleashedRecompLib/private"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "private/shader.ar",
|
"path": "private/shader.ar",
|
||||||
|
|||||||
Vendored
+223
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based
|
||||||
|
* on the implementation in boost::uuid::details.
|
||||||
|
*
|
||||||
|
* SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* Taken from https://github.com/mohaps/TinySHA1
|
||||||
|
* Modified for use by Xenia
|
||||||
|
*/
|
||||||
|
#ifndef _TINY_SHA1_HPP_
|
||||||
|
#define _TINY_SHA1_HPP_
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace sha1 {
|
||||||
|
class SHA1 {
|
||||||
|
public:
|
||||||
|
typedef uint32_t digest32_t[5];
|
||||||
|
typedef uint8_t digest8_t[20];
|
||||||
|
inline static uint32_t LeftRotate(uint32_t value, size_t count) {
|
||||||
|
return (value << count) ^ (value >> (32 - count));
|
||||||
|
}
|
||||||
|
SHA1() { reset(); }
|
||||||
|
virtual ~SHA1() {}
|
||||||
|
SHA1(const SHA1& s) { *this = s; }
|
||||||
|
const SHA1& operator=(const SHA1& s) {
|
||||||
|
memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
|
||||||
|
memcpy(m_block, s.m_block, 64);
|
||||||
|
m_blockByteIndex = s.m_blockByteIndex;
|
||||||
|
m_byteCount = s.m_byteCount;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHA1& init(const uint32_t digest[5], const uint8_t block[64],
|
||||||
|
uint32_t count) {
|
||||||
|
std::memcpy(m_digest, digest, 20);
|
||||||
|
std::memcpy(m_block, block, count % 64);
|
||||||
|
m_byteCount = count;
|
||||||
|
m_blockByteIndex = count % 64;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t* getDigest() const { return m_digest; }
|
||||||
|
const uint8_t* getBlock() const { return m_block; }
|
||||||
|
size_t getBlockByteIndex() const { return m_blockByteIndex; }
|
||||||
|
size_t getByteCount() const { return m_byteCount; }
|
||||||
|
|
||||||
|
SHA1& reset() {
|
||||||
|
m_digest[0] = 0x67452301;
|
||||||
|
m_digest[1] = 0xEFCDAB89;
|
||||||
|
m_digest[2] = 0x98BADCFE;
|
||||||
|
m_digest[3] = 0x10325476;
|
||||||
|
m_digest[4] = 0xC3D2E1F0;
|
||||||
|
m_blockByteIndex = 0;
|
||||||
|
m_byteCount = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHA1& processByte(uint8_t octet) {
|
||||||
|
this->m_block[this->m_blockByteIndex++] = octet;
|
||||||
|
++this->m_byteCount;
|
||||||
|
if (m_blockByteIndex == 64) {
|
||||||
|
this->m_blockByteIndex = 0;
|
||||||
|
processBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHA1& processBlock(const void* const start, const void* const end) {
|
||||||
|
const uint8_t* begin = static_cast<const uint8_t*>(start);
|
||||||
|
const uint8_t* finish = static_cast<const uint8_t*>(end);
|
||||||
|
while (begin != finish) {
|
||||||
|
processByte(*begin);
|
||||||
|
begin++;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHA1& processBytes(const void* const data, size_t len) {
|
||||||
|
const uint8_t* block = static_cast<const uint8_t*>(data);
|
||||||
|
processBlock(block, block + len);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t* finalize(digest32_t digest) {
|
||||||
|
size_t bitCount = this->m_byteCount * 8;
|
||||||
|
processByte(0x80);
|
||||||
|
if (this->m_blockByteIndex > 56) {
|
||||||
|
while (m_blockByteIndex != 0) {
|
||||||
|
processByte(0);
|
||||||
|
}
|
||||||
|
while (m_blockByteIndex < 56) {
|
||||||
|
processByte(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (m_blockByteIndex < 56) {
|
||||||
|
processByte(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processByte(0);
|
||||||
|
processByte(0);
|
||||||
|
processByte(0);
|
||||||
|
processByte(0);
|
||||||
|
processByte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
|
||||||
|
processByte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
|
||||||
|
processByte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
|
||||||
|
processByte(static_cast<unsigned char>((bitCount)&0xFF));
|
||||||
|
|
||||||
|
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* finalize(digest8_t digest) {
|
||||||
|
digest32_t d32;
|
||||||
|
finalize(d32);
|
||||||
|
size_t di = 0;
|
||||||
|
digest[di++] = ((d32[0] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[0] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[0] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[0]) & 0xFF);
|
||||||
|
|
||||||
|
digest[di++] = ((d32[1] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[1] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[1] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[1]) & 0xFF);
|
||||||
|
|
||||||
|
digest[di++] = ((d32[2] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[2] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[2] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[2]) & 0xFF);
|
||||||
|
|
||||||
|
digest[di++] = ((d32[3] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[3] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[3] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[3]) & 0xFF);
|
||||||
|
|
||||||
|
digest[di++] = ((d32[4] >> 24) & 0xFF);
|
||||||
|
digest[di++] = ((d32[4] >> 16) & 0xFF);
|
||||||
|
digest[di++] = ((d32[4] >> 8) & 0xFF);
|
||||||
|
digest[di++] = ((d32[4]) & 0xFF);
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void processBlock() {
|
||||||
|
uint32_t w[80];
|
||||||
|
for (size_t i = 0; i < 16; i++) {
|
||||||
|
w[i] = (m_block[i * 4 + 0] << 24);
|
||||||
|
w[i] |= (m_block[i * 4 + 1] << 16);
|
||||||
|
w[i] |= (m_block[i * 4 + 2] << 8);
|
||||||
|
w[i] |= (m_block[i * 4 + 3]);
|
||||||
|
}
|
||||||
|
for (size_t i = 16; i < 80; i++) {
|
||||||
|
w[i] = LeftRotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t a = m_digest[0];
|
||||||
|
uint32_t b = m_digest[1];
|
||||||
|
uint32_t c = m_digest[2];
|
||||||
|
uint32_t d = m_digest[3];
|
||||||
|
uint32_t e = m_digest[4];
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < 80; ++i) {
|
||||||
|
uint32_t f = 0;
|
||||||
|
uint32_t k = 0;
|
||||||
|
|
||||||
|
if (i < 20) {
|
||||||
|
f = (b & c) | (~b & d);
|
||||||
|
k = 0x5A827999;
|
||||||
|
} else if (i < 40) {
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
k = 0x6ED9EBA1;
|
||||||
|
} else if (i < 60) {
|
||||||
|
f = (b & c) | (b & d) | (c & d);
|
||||||
|
k = 0x8F1BBCDC;
|
||||||
|
} else {
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
k = 0xCA62C1D6;
|
||||||
|
}
|
||||||
|
uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = LeftRotate(b, 30);
|
||||||
|
b = a;
|
||||||
|
a = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_digest[0] += a;
|
||||||
|
m_digest[1] += b;
|
||||||
|
m_digest[2] += c;
|
||||||
|
m_digest[3] += d;
|
||||||
|
m_digest[4] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
digest32_t m_digest;
|
||||||
|
uint8_t m_block[64];
|
||||||
|
size_t m_blockByteIndex;
|
||||||
|
size_t m_byteCount;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+1
Submodule thirdparty/libmspack added at 305907723a
+1
Submodule thirdparty/tiny-AES-c added at 23856752fb
+1
-1
Submodule tools/XenonRecomp updated: cd6fcb33bd...0fc545a6e2
Reference in New Issue
Block a user