Compare commits

..

2 Commits

Author SHA1 Message Date
Hyper 5f32e2495f Switched to CFreeCamera instead of CReplayFreeCamera 2025-02-18 01:59:26 +00:00
Hyper 0aa1a256dd Implemented free camera (WIP)
Patch "Enable Free Camera" id "EnableFreeCamera" in "Debug" by "Hyper" does
/*
Enables the replay mode camera with controls similar to Generations Free Camera.

Controls:
- Start - toggle pause (use after enabling free camera).
- Back (Select) - toggle free camera.
- Left Stick - move camera.
- Left Stick Button (L3) - teleport player to camera.
- Right Stick - rotate camera.
- Right Stick Button (R3) - teleport camera to player.
- Left Bumper (L1) - move camera down.
- Right Bumper (R1) - move camera up.
- Left Trigger (L2) - move camera at slow speed.
- Right Trigger (R2) - move camera at fast speed.
- Left Trigger (L2) + Right Trigger (R2) - move camera at moderate speed.
- A (Cross) - reset camera speed.
- B (Circle) - decrease base camera speed.
- X (Square) - increase base camera speed.
- Y (Triangle) - reset field of view.
- D-Pad Up - increase field of view.
- D-Pad Down - decrease field of view.
- D-Pad Left - toggle camera position lock.
- D-Pad Right - toggle depth of field.
*/
2025-02-17 02:55:36 +00:00
79 changed files with 2678 additions and 1554 deletions
+6
View File
@@ -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
+1 -1
View File
@@ -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".
+16 -6
View File
@@ -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 {};
}
+11 -1
View File
@@ -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);
}
+8
View File
@@ -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
View File
@@ -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);
}
+4 -2
View File
@@ -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 -11
View File
@@ -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();
} }
-1
View File
@@ -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();
} }
+1 -1
View File
@@ -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;
+38 -81
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
} }
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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
{ {
+693
View File
@@ -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;
}
+35
View File
@@ -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
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -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
View File
@@ -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)
+7 -4
View File
@@ -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();
};
+1 -1
View File
@@ -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;
+2 -36
View File
@@ -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;
}
}
+4 -4
View File
@@ -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);
} }
+1 -1
View File
@@ -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)
+2 -5
View File
@@ -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 -1
View File
@@ -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
+1 -1
View File
@@ -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
{ {
+72 -67
View File
@@ -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);
} }
} }
+5 -9
View File
@@ -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
-5
View File
@@ -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;
-1
View File
@@ -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();
+2 -135
View File
@@ -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;
}
+1 -2
View File
@@ -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);
+6 -18
View File
@@ -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";
+7 -35
View File
@@ -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);
+21 -30
View File
@@ -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);
+42 -56
View File
@@ -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);
+58 -48
View File
@@ -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>
+1 -1
View File
@@ -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);
+1 -4
View File
@@ -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")
+16 -5
View File
@@ -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
@@ -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",
+223
View File
@@ -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
Vendored Submodule
+1
Submodule thirdparty/libmspack added at 305907723a
Vendored Submodule
+1
Submodule thirdparty/tiny-AES-c added at 23856752fb