Compare commits

...

28 Commits

Author SHA1 Message Date
Skyth db76ffa5b3 Update version milestone to Release Candidate 1. 2025-02-21 18:23:07 +03:00
SuperSonic16 7e51a00e3a Updated flatpak file sources for the new file requirements (#441) 2025-02-21 18:13:28 +03:00
Michael b3d5cdbe3b Update remaining thumbnails (#442)
* Implement Vibration & Background Input thumbnails

* Disable Resolution Scale and Subtitle Thumbnails

* Remove unused thumbnails & redirect original shadow resolution thumbnail to 1024x.

* Fix else if chain.

* Update resources submodule.

---------

Co-authored-by: RadiantDerg <9061202+RadiantDerg@users.noreply.github.com>
Co-authored-by: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com>
2025-02-21 17:38:00 +03:00
Hyper 8ff365cbaa button_guide: fix LB/RB prompt clipping 4:3 aspect ratio (#439) 2025-02-20 22:48:06 +03:00
Hyper d812c12d06 options_menu: remove LT/RT input for switching tabs (#440) 2025-02-20 22:47:35 +03:00
Skyth (Asilkan) 27d4af12ad Fix lack of space before "Add Files". (#438) 2025-02-20 22:14:48 +03:00
ĐeäTh 82f81dc7f9 Options menu fixes for Japanese (#436)
* fix options menu descriptions

* add explanation for special gylph characters

* update resources submodule
2025-02-20 21:51:42 +03:00
Skyth (Asilkan) 5f5517977a Fix SDF font outline sizes. (#435) 2025-02-20 21:14:32 +03:00
ĐeäTh b101e016cf Japanese localization (#415)
* translate most option names and setting names

* add most header/button guide japanese localizations

* include furigana usage guidance for japanese localization

* remove os message window furigana note

* fix incorrect kana usage for 'lock'

* add more option localization

* translate achievement notification option

* remove english battle theme description from japanese

* fix compilation errors

* Japanese localization 1st pass

* Revert JP localization taken from in-game

* Use "Window Size"

* add support for zero width line break hints

* add dirty hack for kana being clipped at the right edge of the info panel

* Changed line to original meaning

* Added zero width spaces to option descriptions

* Japanese localization 2nd pass

* Remove furigana from Video_BackendError

* add more japanese specific hacks for installer_wizard description

* locale small fixes

* Update config_locale.cpp

* options menu scroll fixes, minor localization touchups

* adjust installer wizard text spacing

* fix installer wizard text positioning when a line starts with a normal kana in japanese

* Installer adjustment

* option fixes

* Added missing line break on introduction

* do touchups to message window annotation drop shadow

* adjust spacing in TitleMissingDLC text to fit furigana properly

* add brianuuuSonic to credits

* change capitalization of xbox in xbox color correction

* remove usage of temporaries

* tweak cutscene aspect ratio description

* add missing credit for german translation

* update resources submodule

---------

Co-authored-by: brianuuu <38166666+brianuuu@users.noreply.github.com>
2025-02-20 20:20:49 +03:00
Darío de7148772b Spanish translation. (#314) 2025-02-20 19:30:47 +03:00
ĐeäTh 4d4eba693f French Localization (#414)
* add french localization

* change installer introduction line breaks

* brightness and control tutorial localization touchups

* remove translation for Werehog from descriptions

* change quit message for consistency with in-game text

* add spaces between characters and question marks for consistency

* add spaces between characters and exclamation marks for consistency

* add spaces between characters and colon for consistency

* more spacing fixes

* ensure available space doesn't break at 10tb+ storage

* change localization for gibibyte acronym to proper unit

* update to new localization for InstallFailed

---------

Co-authored-by: LJSTAR <31629427+ljstarbird@users.noreply.github.com>
2025-02-20 19:05:53 +03:00
NextinHKRY 08c791f2cf Italian Localization (#380)
* italian: Redid localization files, again

* italian: Update Hints and Button tutorials

* italian: Update Control Tutorial text

* italian: Updated locale

* italian: Added language desc. and added deliberate mistake

Why did they add a space before the question mark...
2025-02-20 17:46:05 +03:00
Kitzuku 07ad85b7bb German localization (#423)
* Update locale.cpp for most German localization

* Adding the rest of German localisation

Additionally changed phrasing on a few lines to be more in line with official terminology used in other games and software respectively.

* Add German Localization to Config

Adds all strings to the German localization for the options menu.

* Change installer wizard space check page text spacing

* Update locale.cpp as per review

Removed line break for welcome message.
Shortened installer prompts.
Adjusted lines breaks across the board.
Improved consistency with game.

* address line breaks

* add missing controller icon strings

* correct line breaks for Installer_Page_InstallFailed

---------

Co-authored-by: DeaTh-G <hatvongeorge@gmail.com>
Co-authored-by: Michael <15317421+ActualMandM@users.noreply.github.com>
2025-02-20 17:43:54 +03:00
Skyth (Asilkan) ba522c0e42 Draw low quality text for custom UI that is directly part of the game. (#434) 2025-02-20 17:18:27 +03:00
Skyth (Asilkan) 0afd01ff7e Cleanup some of the unordered_map usage. (#432) 2025-02-19 20:32:11 +03:00
Skyth (Asilkan) 5ba4e927ab Port XEX patcher to XenonRecomp. (#433)
* Port XEX patcher to XenonRecomp.

* Update XenonRecomp submodule.
2025-02-19 20:31:01 +03:00
Skyth (Asilkan) f123ec7083 Fix logic for the grind booster HFR fix. (#431) 2025-02-19 01:54:38 +03:00
ĐeäTh b8ae355915 Remove separator empty line between error and error message (#430)
* remove separator empty line between error and error message

* remove trailing line breaks too
2025-02-18 21:06:03 +01:00
Skyth (Asilkan) 14faa17cd8 Implement workaround for Mesa triangle strip bug. (#428)
* Convert restart indices to degenerate triangles for Mesa.

* Check for Mesa to enable the triangle strip workaround.

* Remove _WIN32 ifndefs.
2025-02-18 21:15:50 +03:00
Hyper 4aeee49561 object_patches: fix rail booster sounds overlapping at HFR (#427) 2025-02-18 11:54:37 +03:00
Hyper 49cc504ced sdl2_driver: log errors from SDL_InitSubSystem and SDL_OpenAudioDevice (#425) 2025-02-17 20:01:43 +00:00
Hyper 91f874cbad Implemented max width for button guide strings for localisation (#421)
* button_guide: implemented max width for localisation

* button_guide: implemented max width for dual icon strings

* button_guide: scale max width internally
2025-02-17 19:30:33 +00:00
Skyth (Asilkan) df8234ab3b Fix append archives sometimes failing to replace files. (#420) 2025-02-17 00:00:49 +03:00
Skyth (Asilkan) c68b5247c7 Fix Select/Back in message window not getting localised correctly. (#418) 2025-02-16 20:59:29 +03:00
Hyper 910d043f19 Disable Chip hints for shoe upgrades (#413) 2025-02-16 13:29:04 +03:00
Hyper beac8339c2 Fix D-Pad support for bosses with 2D or overhead sections (#411) 2025-02-16 13:27:58 +03:00
Hyper 02c23384f3 Update Control Tutorial description to add notice about the Werehog critical attack prompt (#412) 2025-02-15 17:52:11 +00:00
Skyth (Asilkan) 868e0f922a Update PSO cache. (#410) 2025-02-14 23:42:30 +03:00
51 changed files with 1590 additions and 2055 deletions
-6
View File
@@ -7,9 +7,6 @@
[submodule "tools/XenosRecomp"]
path = tools/XenosRecomp
url = https://github.com/hedge-dev/XenosRecomp.git
[submodule "thirdparty/libmspack"]
path = thirdparty/libmspack
url = https://github.com/kyz/libmspack
[submodule "UnleashedRecompResources"]
path = UnleashedRecompResources
url = https://github.com/hedge-dev/UnleashedRecompResources.git
@@ -40,9 +37,6 @@
[submodule "thirdparty/concurrentqueue"]
path = thirdparty/concurrentqueue
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"]
path = thirdparty/magic_enum
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
```
2. Decompress and decrypt `default.xex`, apply the title update patch (`default.xexp`), and place the resulting file in `./UnleashedRecompLib/private/`.
2. Place `default.xex` and `default.xexp` 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.
5. Under Solution Explorer, right-click and choose "Switch to CMake Targets View".
+8 -17
View File
@@ -165,10 +165,8 @@ set(UNLEASHED_RECOMP_UI_CXX_SOURCES
set(UNLEASHED_RECOMP_INSTALL_CXX_SOURCES
"install/installer.cpp"
"install/iso_file_system.cpp"
"install/memory_mapped_file.cpp"
"install/update_checker.cpp"
"install/xcontent_file_system.cpp"
"install/xex_patcher.cpp"
"install/hashes/apotos_shamar.cpp"
"install/hashes/chunnan.cpp"
"install/hashes/empire_city_adabat.cpp"
@@ -201,8 +199,6 @@ set(UNLEASHED_RECOMP_THIRDPARTY_SOURCES
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot.cpp"
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot_demo.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"
)
@@ -212,11 +208,8 @@ set(UNLEASHED_RECOMP_THIRDPARTY_INCLUDES
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui"
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot"
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/json/include"
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/libmspack/libmspack/mspack"
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include"
"${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}/volk"
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/Vulkan-Headers/include"
@@ -500,8 +493,8 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/in
## Options Menu ##
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" ARRAY_NAME "g_achievement_notifications" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input.dds" ARRAY_NAME "g_allow_background_input" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/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/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_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/antialiasing_none.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_none.dds" ARRAY_NAME "g_antialiasing_none" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" ARRAY_NAME "g_antialiasing_2x" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" ARRAY_NAME "g_antialiasing_4x" COMPRESSION_TYPE "zstd")
@@ -510,9 +503,9 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/battle_theme.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/battle_theme.dds" ARRAY_NAME "g_battle_theme" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/brightness.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/brightness.dds" ARRAY_NAME "g_brightness" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_stereo.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_stereo.dds" ARRAY_NAME "g_channel_stereo" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_surround.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_surround.dds" ARRAY_NAME "g_channel_surround" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" ARRAY_NAME "g_control_tutorial_xb" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" ARRAY_NAME "g_control_tutorial_ps" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/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/controller_icons.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/controller_icons.dds" ARRAY_NAME "g_controller_icons" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/default.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/default.dds" ARRAY_NAME "g_default" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/effects_volume.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/effects_volume.dds" ARRAY_NAME "g_effects_volume" COMPRESSION_TYPE "zstd")
@@ -532,23 +525,21 @@ 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/music_attenuation.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/music_attenuation.dds" ARRAY_NAME "g_music_attenuation" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/music_volume.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/music_volume.dds" ARRAY_NAME "g_music_volume" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/resolution_scale.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/resolution_scale.dds" ARRAY_NAME "g_resolution_scale" COMPRESSION_TYPE "zstd")
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_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_x4096.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x4096.dds" ARRAY_NAME "g_shadow_resolution_x4096" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x8192.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x8192.dds" ARRAY_NAME "g_shadow_resolution_x8192" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/subtitles.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/subtitles.dds" ARRAY_NAME "g_subtitles" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_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/time_transition_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_xb.dds" ARRAY_NAME "g_time_of_day_transition_xbox" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" ARRAY_NAME "g_time_of_day_transition_playstation" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" ARRAY_NAME "g_transparency_antialiasing_false" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" ARRAY_NAME "g_transparency_antialiasing_true" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" ARRAY_NAME "g_ui_alignment_centre" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_edge.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_edge.dds" ARRAY_NAME "g_ui_alignment_edge" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vertical_camera.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vertical_camera.dds" ARRAY_NAME "g_vertical_camera" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/voice_language.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/voice_language.dds" ARRAY_NAME "g_voice_language" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration.dds" ARRAY_NAME "g_vibration" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/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_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_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")
+1
View File
@@ -60,6 +60,7 @@ PPC_FUNC(sub_822C1130)
}
App::s_deltaTime = ctx.f1.f64;
App::s_time += App::s_deltaTime;
// This function can also be called by the loading thread,
// which SDL does not like. To prevent the OS from thinking
+1
View File
@@ -14,6 +14,7 @@ public:
static inline ELanguage s_language;
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 Exit();
+11 -1
View File
@@ -1,6 +1,7 @@
#include <apu/audio.h>
#include <cpu/guest_thread.h>
#include <kernel/heap.h>
#include <os/logger.h>
#include <user/config.h>
static PPCFunc* g_clientCallback{};
@@ -29,6 +30,9 @@ static void CreateAudioDevice()
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);
}
@@ -36,7 +40,13 @@ void XAudioInitializeSystem()
{
SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback");
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();
}
+13
View File
@@ -15,10 +15,13 @@
{ reinterpret_cast<GuestShader*>(0x36DB3B40FA419EF6),reinterpret_cast<GuestShader*>(0x4FDE8FFB7DC1D1CE),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
{ reinterpret_cast<GuestShader*>(0x36DB3B40FA419EF6),reinterpret_cast<GuestShader*>(0xD56D0D7219E51F1D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x115813F8DBF6CCFF),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x3073F2C856F3333E),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x3382CD5552FAB33C),reinterpret_cast<GuestVertexDeclaration*>(0xB7BBCC93738C9DE4),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x6563290A54293E7A),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x6563290A54293E7A),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x6563290A54293E7A),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x6563290A54293E7A),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x7A8F23548FF778),reinterpret_cast<GuestVertexDeclaration*>(0xC64D046063DE2F63),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x85E3EE1021089A76),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x933E17818464BC39),reinterpret_cast<GuestVertexDeclaration*>(0xB7BBCC93738C9DE4),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
@@ -27,6 +30,7 @@
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0xB8F71746F39A1166),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0xF9F82EC882CD3D08),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0xF9F82EC882CD3D08),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x40E4064FE517DFD2),reinterpret_cast<GuestShader*>(0x11958CFF684E1F4B),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x4620B236DC38100C),reinterpret_cast<GuestShader*>(0xBBDB735BEACC8F41),reinterpret_cast<GuestVertexDeclaration*>(0x28FD2057B9BD5D1B),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::D32_FLOAT,1,false,0x10 },
{ reinterpret_cast<GuestShader*>(0x4620B236DC38100C),reinterpret_cast<GuestShader*>(0xBBDB735BEACC8F41),reinterpret_cast<GuestVertexDeclaration*>(0x2A6D72391BFFFA3C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x4620B236DC38100C),reinterpret_cast<GuestShader*>(0xBBDB735BEACC8F41),reinterpret_cast<GuestVertexDeclaration*>(0x2A6D72391BFFFA3C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::D32_FLOAT,1,false,0x11 },
@@ -53,11 +57,13 @@
{ reinterpret_cast<GuestShader*>(0x624F608ACB374E12),reinterpret_cast<GuestShader*>(0xA624AF834723B59),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x624F608ACB374E12),reinterpret_cast<GuestShader*>(0xA624AF834723B59),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x624F608ACB374E12),reinterpret_cast<GuestShader*>(0xA624AF834723B59),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x2CA0127E60EB4507),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x2E5AA3C0A9E32751),reinterpret_cast<GuestVertexDeclaration*>(0xB7BBCC93738C9DE4),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x326BB3169FF92317),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x3838E2D27966B21C),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x5A75A52C3F722625),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x86CD1B8641C60EE6),reinterpret_cast<GuestVertexDeclaration*>(0xC64D046063DE2F63),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x874793F8CC9C7EB0),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xB0F7121362A63137),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xB0F7121362A63137),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xB23ACF01C99C2988),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
@@ -65,6 +71,7 @@
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xC03A891201D4E9E7),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xCE7A73C836F03E6),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xD4D1534DD857403),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xD4D1534DD857403),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xD4D1534DD857403),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xE1748A1E1E38FC5F),reinterpret_cast<GuestVertexDeclaration*>(0x6538EB0019C3A29A),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xE1748A1E1E38FC5F),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
@@ -94,6 +101,7 @@
{ reinterpret_cast<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x9FA5AACB5B14A226),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0xC47F2F91BA2A5D86),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0xFB79F59782376846),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0xFF42BE2DBCE820C9),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x720D6E5EDA78433B),reinterpret_cast<GuestShader*>(0x96EACBACDE1AAFAA),reinterpret_cast<GuestVertexDeclaration*>(0xA81F28FA43A9B511),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
{ reinterpret_cast<GuestShader*>(0x720D6E5EDA78433B),reinterpret_cast<GuestShader*>(0x96EACBACDE1AAFAA),reinterpret_cast<GuestVertexDeclaration*>(0xA81F28FA43A9B511),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
{ reinterpret_cast<GuestShader*>(0x734799D14CC5177E),reinterpret_cast<GuestShader*>(0xC9978EB328E1066E),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
@@ -104,6 +112,7 @@
{ reinterpret_cast<GuestShader*>(0x86FE3502D5EC24AA),reinterpret_cast<GuestShader*>(0x68FCC0B90EBC457B),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x86FE3502D5EC24AA),reinterpret_cast<GuestShader*>(0x94A71CC9B94E3101),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x88F67387B88F932F),reinterpret_cast<GuestShader*>(0x49101E452DF2FE98),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
{ reinterpret_cast<GuestShader*>(0x8E4BB23465BD909E),reinterpret_cast<GuestShader*>(0x0),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::FRONT,RenderComparisonFunction::LESS_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x8E4BB23465BD909E),reinterpret_cast<GuestShader*>(0x0),reinterpret_cast<GuestVertexDeclaration*>(0xFFFDDC62D86892F1),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS_EQUAL,false,RenderBlendOperation::ADD,1,33554,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_LIST,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x8E4BB23465BD909E),reinterpret_cast<GuestShader*>(0x0),reinterpret_cast<GuestVertexDeclaration*>(0xFFFDDC62D86892F1),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS_EQUAL,false,RenderBlendOperation::ADD,1,33554,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x0 },
{ reinterpret_cast<GuestShader*>(0x8EA8F71BA3BE59E7),reinterpret_cast<GuestShader*>(0xA557DD8B24CD2B25),reinterpret_cast<GuestVertexDeclaration*>(0xEC0CD05EE1B1636),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_LIST,{ 28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::UNKNOWN,1,false,0x10 },
@@ -145,6 +154,7 @@
{ reinterpret_cast<GuestShader*>(0xA4CF0215A03D9571),reinterpret_cast<GuestShader*>(0xA3A659F1590CC180),reinterpret_cast<GuestVertexDeclaration*>(0x5A2395E29F93DA3C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_FAN,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
{ reinterpret_cast<GuestShader*>(0xA59B07C00039C660),reinterpret_cast<GuestShader*>(0x2E69CC2B4937A698),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xA59B07C00039C660),reinterpret_cast<GuestShader*>(0xF6FAD0CDA667264),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xA790E2F622DADAD8),reinterpret_cast<GuestShader*>(0xD56D0D7219E51F1D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
{ reinterpret_cast<GuestShader*>(0xA7C9D01F7AD3B9D0),reinterpret_cast<GuestShader*>(0x481905CF40E1678D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
{ reinterpret_cast<GuestShader*>(0xA7C9D01F7AD3B9D0),reinterpret_cast<GuestShader*>(0x481905CF40E1678D),reinterpret_cast<GuestVertexDeclaration*>(0xC64D046063DE2F63),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xAC38B793E9C54AC5),reinterpret_cast<GuestShader*>(0x24CAF5A2F1B2AF40),reinterpret_cast<GuestVertexDeclaration*>(0x3CB3EF6B1C43B8C),true,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
@@ -163,6 +173,8 @@
{ reinterpret_cast<GuestShader*>(0xBE3AD1D0FE788D2),reinterpret_cast<GuestShader*>(0x4CB3784D7108745F),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xBE3AD1D0FE788D2),reinterpret_cast<GuestShader*>(0xD57D71ED84D8F864),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xCF28F33974EC44F6),reinterpret_cast<GuestShader*>(0xD5EA32DB758EF0B8),reinterpret_cast<GuestVertexDeclaration*>(0x7F12180DC3A24B53),true,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0xB7BBCC93738C9DE4),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x96B8F9FDAAB9B658),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
@@ -196,6 +208,7 @@
{ reinterpret_cast<GuestShader*>(0xECC9C0BD668FE449),reinterpret_cast<GuestShader*>(0x4C4032F88196B450),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xECC9C0BD668FE449),reinterpret_cast<GuestShader*>(0xC7E2C782C058A625),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xECC9C0BD668FE449),reinterpret_cast<GuestShader*>(0xFB66DF5D27D3891D),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xF060DE53CF3B9BB8),reinterpret_cast<GuestShader*>(0xEAADA73091BF526C),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
{ reinterpret_cast<GuestShader*>(0xF066433D33B62D54),reinterpret_cast<GuestShader*>(0xE5256B7D753C9D5F),reinterpret_cast<GuestVertexDeclaration*>(0x3CB3EF6B1C43B8C),true,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
{ reinterpret_cast<GuestShader*>(0xF1D7C544D61D055C),reinterpret_cast<GuestShader*>(0x5A75A52C3F722625),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
{ reinterpret_cast<GuestShader*>(0xF58C10092C9EF1AF),reinterpret_cast<GuestShader*>(0x1DD6832FA7E79530),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
+1
View File
@@ -11,6 +11,7 @@
#define IMGUI_SHADER_MODIFIER_TITLE_BEVEL 8
#define IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL 9
#define IMGUI_SHADER_MODIFIER_RECTANGLE_BEVEL 10
#define IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT 11
#ifdef __cplusplus
@@ -220,6 +220,8 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
for (size_t i = 0; i < atlas->ConfigData.size(); i++)
{
double spaceAdvance = 0.0;
auto& config = atlas->ConfigData[i];
bool increaseSpacing = strstr(config.Name, "Seurat") != nullptr;
@@ -232,8 +234,15 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
glyph.getQuadAtlasBounds(u0, v0, u1, v1);
double advance = glyph.getAdvance();
if (increaseSpacing && glyph.getCodepoint() == ' ')
advance *= 1.5;
if (glyph.getCodepoint() == ' ')
{
if (increaseSpacing)
{
advance *= 1.5;
}
spaceAdvance = advance;
}
config.DstFont->AddGlyph(
&config,
@@ -248,6 +257,39 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
v0 / packer.height,
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();
}
@@ -12,6 +12,7 @@ struct PushConstants
uint GradientBottomLeft;
uint ShaderModifier;
uint Texture2DDescriptorIndex;
float2 DisplaySize;
float2 InverseDisplaySize;
float2 Origin;
float2 Scale;
+82 -39
View File
@@ -61,10 +61,10 @@ float4 SampleLinear(float2 uvTexspace)
float4 PixelAntialiasing(float2 uvTexspace)
{
if ((g_PushConstants.InverseDisplaySize.y / g_PushConstants.InverseDisplaySize.x) >= (4.0 / 3.0))
uvTexspace *= g_PushConstants.InverseDisplaySize.y * 720.0f;
if ((g_PushConstants.DisplaySize.x * g_PushConstants.InverseDisplaySize.y) >= (4.0 / 3.0))
uvTexspace *= g_PushConstants.InverseDisplaySize.y * 720.0;
else
uvTexspace *= g_PushConstants.InverseDisplaySize.x * 960.0f;
uvTexspace *= g_PushConstants.InverseDisplaySize.x * 960.0;
float2 seam = floor(uvTexspace + 0.5);
uvTexspace = (uvTexspace - seam) / fwidth(uvTexspace) + seam;
@@ -78,6 +78,51 @@ float median(float r, float g, float 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 color = interpolators.Color;
@@ -86,52 +131,50 @@ float4 main(in Interpolators interpolators) : SV_Target
if (g_PushConstants.Texture2DDescriptorIndex != 0)
{
Texture2D<float4> texture = g_Texture2DDescriptorHeap[g_PushConstants.Texture2DDescriptorIndex & 0x7FFFFFFF];
float4 textureColor = texture.Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
if ((g_PushConstants.Texture2DDescriptorIndex & 0x80000000) != 0)
{
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)
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT)
{
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.8), 32.0));
float scale;
float invScale;
if ((g_PushConstants.DisplaySize.x * g_PushConstants.InverseDisplaySize.y) >= (4.0 / 3.0))
{
scale = g_PushConstants.InverseDisplaySize.y * 720.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 if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL)
else
{
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);
color = SampleSdfFont(color, texture, interpolators.UV, 1.0 / fwidth(interpolators.UV));
}
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
{
color *= textureColor;
color *= texture.Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
}
}
+194
View File
@@ -285,6 +285,8 @@ static bool g_vulkan = false;
static constexpr bool g_vulkan = true;
#endif
static bool g_mesaTriangleStripWorkaround = false;
static constexpr bool g_hardwareResolve = true;
static constexpr bool g_hardwareDepthResolve = true;
@@ -1338,6 +1340,7 @@ struct ImGuiPushConstants
ImU32 gradientBottomLeft{};
uint32_t shaderModifier{};
uint32_t texture2DDescriptorIndex{};
ImVec2 displaySize{};
ImVec2 inverseDisplaySize{};
ImVec2 origin{ 0.0f, 0.0f };
ImVec2 scale{ 1.0f, 1.0f };
@@ -1699,6 +1702,14 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
g_vulkan = (interfaceFunction == CreateVulkanInterfaceWrapper);
#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;
}
}
@@ -2318,6 +2329,7 @@ static void DrawProfiler()
ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "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("Triangle Strip Workaround: %s", g_mesaTriangleStripWorkaround ? "Enabled" : "Disabled");
ImGui::NewLine();
ImGui::Text("API: %s", g_vulkan ? "Vulkan" : "D3D12");
@@ -2485,6 +2497,7 @@ static void ProcDrawImGui(const RenderCommand& cmd)
commandList->setViewports(RenderViewport(drawData.DisplayPos.x, drawData.DisplayPos.y, drawData.DisplaySize.x, drawData.DisplaySize.y));
ImGuiPushConstants pushConstants{};
pushConstants.displaySize = drawData.DisplaySize;
pushConstants.inverseDisplaySize = { 1.0f / drawData.DisplaySize.x, 1.0f / drawData.DisplaySize.y };
commandList->setGraphicsPushConstants(0, &pushConstants);
@@ -7402,6 +7415,187 @@ 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_82BE6230, DestructResource);
+1 -1
View File
@@ -598,5 +598,5 @@ XexPatcher::Result Installer::checkGameUpdateCompatibility(const std::filesystem
}
std::vector<uint8_t> patchedBytes;
return XexPatcher::apply(xexBytes, patchBytes, patchedBytes, true);
return XexPatcher::apply(xexBytes.data(), xexBytes.size(), patchBytes.data(), patchBytes.size(), patchedBytes, true);
}
+1 -1
View File
@@ -4,7 +4,7 @@
#include <set>
#include "virtual_file_system.h"
#include "xex_patcher.h"
#include <xex_patcher.h>
enum class DLC {
Unknown,
+1 -1
View File
@@ -16,7 +16,7 @@
#include "virtual_file_system.h"
#include "memory_mapped_file.h"
#include <memory_mapped_file.h>
struct ISOFileSystem : VirtualFileSystem
{
@@ -1,169 +0,0 @@
#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
}
@@ -1,32 +0,0 @@
#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 "memory_mapped_file.h"
#include <memory_mapped_file.h>
enum class XContentVolumeType
{
-693
View File
@@ -1,693 +0,0 @@
// 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
@@ -1,35 +0,0 @@
// 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>";
extern std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_locale;
extern std::unordered_map<std::string_view, std::unordered_map<ELanguage, std::string>> g_locale;
std::string& Localise(const char* key);
std::string& Localise(const std::string_view& key);
+19 -19
View File
@@ -106,33 +106,33 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
return 0;
}
auto* xex = reinterpret_cast<XEX_HEADER*>(loadResult.data());
auto security = reinterpret_cast<XEX2_SECURITY_INFO*>((char*)xex + xex->AddressOfSecurityInfo);
auto format = Xex2FindOptionalHeader<XEX_FILE_FORMAT_INFO>(xex, XEX_HEADER_FILE_FORMAT_INFO);
auto entry = *Xex2FindOptionalHeader<uint32_t>(xex, XEX_HEADER_ENTRY_POINT);
auto* header = reinterpret_cast<const Xex2Header*>(loadResult.data());
auto* security = reinterpret_cast<const Xex2SecurityInfo*>(loadResult.data() + header->securityOffset);
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));
ByteSwapInplace(entry);
auto srcData = (char *)xex + xex->SizeOfHeader;
auto destData = (char *)g_memory.Translate(security->ImageBase);
if (format->CompressionType == 0)
auto srcData = loadResult.data() + header->headerSize;
auto destData = reinterpret_cast<uint8_t*>(g_memory.Translate(security->loadAddress));
if (fileFormatInfo->compressionType == XEX_COMPRESSION_NONE)
{
memcpy(destData, srcData, security->SizeOfImage);
memcpy(destData, srcData, security->imageSize);
}
else if (format->CompressionType == 1)
else if (fileFormatInfo->compressionType == XEX_COMPRESSION_BASIC)
{
auto numBlocks = (format->SizeOfHeader / sizeof(XEX_BASIC_FILE_COMPRESSION_INFO)) - 1;
auto blocks = reinterpret_cast<const XEX_BASIC_FILE_COMPRESSION_INFO*>(format + 1);
auto* blocks = reinterpret_cast<const Xex2FileBasicCompressionBlock*>(fileFormatInfo + 1);
const size_t numBlocks = (fileFormatInfo->infoSize / sizeof(Xex2FileBasicCompressionInfo)) - 1;
for (size_t i = 0; i < numBlocks; i++)
{
memcpy(destData, srcData, blocks[i].SizeOfData);
memcpy(destData, srcData, blocks[i].dataSize);
srcData += blocks[i].SizeOfData;
destData += blocks[i].SizeOfData;
memset(destData, 0, blocks[i].SizeOfPadding);
srcData += blocks[i].dataSize;
destData += blocks[i].dataSize;
destData += blocks[i].SizeOfPadding;
memset(destData, 0, blocks[i].zeroSize);
destData += blocks[i].zeroSize;
}
}
else
@@ -140,9 +140,9 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
assert(false && "Unknown compression type.");
}
auto res = Xex2FindOptionalHeader<XEX_RESOURCE_INFO>(xex, XEX_HEADER_RESOURCE_INFO);
auto res = reinterpret_cast<const Xex2ResourceInfo*>(getOptHeaderPtr(loadResult.data(), 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;
}
+66 -20
View File
@@ -562,14 +562,68 @@ PPC_FUNC(sub_82E0D3E8)
g_userHeap.Free(newArlFileData);
}
// Load elements have an unused "pretty name" field. We will use this field to store the archive file path,
// prefixed with a magic string. When the first load detects this string, it will load append archives
// and then clear the field to prevent remaining splits from loading the append archives again.
// We cannot rely on .ar.00 being the first split to be loaded, so this approach is necessary.
static thread_local uint32_t g_prefixedArFilePath = NULL;
// Hedgehog::Database::CDatabaseLoader::LoadArchives
PPC_FUNC_IMPL(__imp__sub_82E0CC38);
PPC_FUNC(sub_82E0CC38)
{
if (g_mods.empty())
{
__imp__sub_82E0CC38(ctx, base);
return;
}
auto r3 = ctx.r3;
auto r4 = ctx.r4;
auto r5 = ctx.r5;
auto r6 = ctx.r6;
auto r7 = ctx.r7;
auto r8 = ctx.r8;
const char* arFilePath = reinterpret_cast<const char*>(base + PPC_LOAD_U32(r5.u32));
// __HH_ALLOC
ctx.r3.u32 = 22 + strlen(arFilePath);
sub_822C0988(ctx, base);
char* prefixedArFilePath = reinterpret_cast<char*>(base + ctx.r3.u32);
*reinterpret_cast<be<uint32_t>*>(prefixedArFilePath) = 1;
strcpy(prefixedArFilePath + 0x4, "/UnleashedRecomp/");
strcpy(prefixedArFilePath + 0x15, arFilePath);
ctx.r1.u32 -= 0x10;
uint32_t stackSpace = ctx.r1.u32;
PPC_STORE_U32(stackSpace, static_cast<uint32_t>(reinterpret_cast<uint8_t*>(prefixedArFilePath) - base) + 0x4);
g_prefixedArFilePath = stackSpace;
ctx.r3 = r3;
ctx.r4 = r4;
ctx.r5 = r5;
ctx.r6 = r6;
ctx.r7 = r7;
ctx.r8 = r8;
__imp__sub_82E0CC38(ctx, base);
// Hedgehog::Base::CSharedString::~CSharedString
ctx.r3.u32 = stackSpace;
sub_82DFB148(ctx, base);
g_prefixedArFilePath = NULL;
ctx.r1.u32 += 0x10;
}
// Hedgehog::Database::SLoadElement::SLoadElement
PPC_FUNC_IMPL(__imp__sub_82E140D8);
PPC_FUNC(sub_82E140D8)
{
// Store archive name as the pretty name to use it later for append archive loading.
// This is always set to an empty string for archives, so it should be safe to replace.
if (!g_mods.empty() && PPC_LOAD_U32(ctx.r5.u32) == 0x8200A621)
ctx.r5.u32 = ctx.r6.u32;
// Store the prefixed archive file path as the pretty name. It's unused for archives we want to append to.
if (!g_mods.empty() && PPC_LOAD_U32(ctx.r5.u32) == 0x8200A621 && g_prefixedArFilePath != NULL)
ctx.r5.u32 = g_prefixedArFilePath;
__imp__sub_82E140D8(ctx, base);
}
@@ -584,25 +638,17 @@ PPC_FUNC(sub_82E0B500)
return;
}
std::u8string_view arFilePathU8(reinterpret_cast<const char8_t*>(base + PPC_LOAD_U32(ctx.r5.u32)));
size_t index = arFilePathU8.find(u8".ar.00");
if (index == (arFilePathU8.size() - 6))
uint32_t prefixedArFilePath = PPC_LOAD_U32(ctx.r5.u32);
std::u8string_view arFilePathU8(reinterpret_cast<const char8_t*>(base + prefixedArFilePath));
if (!arFilePathU8.starts_with(u8"/UnleashedRecomp/"))
{
arFilePathU8.remove_suffix(3);
__imp__sub_82E0B500(ctx, base);
return;
}
else
{
index = arFilePathU8.find(u8".ar");
if (index != (arFilePathU8.size() - 3) ||
arFilePathU8.starts_with(u8"tg-") ||
arFilePathU8.starts_with(u8"gia-") ||
arFilePathU8.starts_with(u8"gi-texture-"))
{
__imp__sub_82E0B500(ctx, base);
return;
}
}
// Immediately clear the string, so the remaining splits don't load append archives again.
PPC_STORE_U8(prefixedArFilePath, 0x00);
arFilePathU8.remove_prefix(0x11);
auto r3 = ctx.r3; // Callback
auto r4 = ctx.r4; // Database
@@ -1,5 +1,4 @@
#include <os/registry.h>
#include <unordered_map>
inline const wchar_t* g_registryRoot = L"Software\\UnleashedRecomp";
@@ -172,7 +172,7 @@ PPC_FUNC(sub_824B0930)
if (*SWA::SGlobals::ms_IsRenderHud && pHudPause->m_IsShown && !pHudPause->m_Submenu && pHudPause->m_Transition == SWA::eTransitionType_Undefined)
{
ButtonGuide::Open(Button("Achievements_Name", EButtonIcon::Back, EButtonAlignment::Left, EFontQuality::Low));
ButtonGuide::Open(Button("Achievements_Name", FLT_MAX, EButtonIcon::Back, EButtonAlignment::Left, EFontQuality::Low));
g_isClosed = false;
}
else if (!g_isClosed)
+36 -2
View File
@@ -70,10 +70,9 @@ void ObjBigBarrelSetPositionMidAsmHook(PPCRegister& r3, PPCRegister& r4)
}
}
// SWA::CExBullet::AddCallback
// 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.
// SWA::CExBullet::AddCallback
PPC_FUNC_IMPL(__imp__sub_82B14CC0);
PPC_FUNC(sub_82B14CC0)
{
@@ -99,3 +98,38 @@ PPC_FUNC(sub_82B14CC0)
__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;
}
}
+5 -2
View File
@@ -1,6 +1,6 @@
#pragma once
inline std::array<const char*, 14> g_credits =
inline std::array<const char*, 17> g_credits =
{
"Skyth",
"Hyper",
@@ -15,5 +15,8 @@ inline std::array<const char*, 14> g_credits =
"LadyLunanova",
"LJSTAR",
"Goalringmod27",
"M&M"
"M&M",
"DaGuAr",
"brianuuuSonic",
"Kitzuku"
};
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_MILESTONE="Beta 3"
VERSION_MILESTONE="Release Candidate 1"
VERSION_MAJOR=1
VERSION_MINOR=0
VERSION_REVISION=0
+1 -1
View File
@@ -763,7 +763,7 @@ void AchievementMenu::Open()
return std::get<1>(a) > std::get<1>(b);
});
ButtonGuide::Open(Button("Common_Back", EButtonIcon::B));
ButtonGuide::Open(Button("Common_Back", FLT_MAX, EButtonIcon::B, EFontQuality::Low));
ResetSelection();
Game_PlaySound("sys_actstg_pausewinopen");
@@ -183,6 +183,9 @@ void AchievementOverlay::Draw()
IM_COL32(255, 255, 255, 255) // col
);
// Use low quality text.
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
// Draw header text.
DrawTextWithShadow
(
@@ -208,6 +211,9 @@ void AchievementOverlay::Draw()
1.0f, // radius
IM_COL32(0, 0, 0, 255) // shadowColour
);
// Reset low quality text shader modifier.
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
}
else
{
+62 -67
View File
@@ -14,7 +14,6 @@
constexpr float DEFAULT_SIDE_MARGINS = 379;
ImFont* g_fntNewRodin;
ImFont* g_fntNewRodinLQ;
std::unique_ptr<GuestTexture> g_upControllerIcons;
std::unique_ptr<GuestTexture> g_upKBMIcons;
@@ -144,79 +143,74 @@ std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon
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,
EButtonAlignment alignment, ImVec2 iconMin, ImVec2 iconMax, EFontQuality fontQuality,
ImVec2 textSize, float fontSize, const char* text)
float textWidth, float maxTextWidth, float textScale, float fontSize, const char* text)
{
auto drawList = ImGui::GetBackgroundDrawList();
auto _icon = icon;
auto iconWidth = Scale(g_iconWidths[icon]);
auto dualIconMarginX = Scale(25);
auto textMarginY = regionMin.y + Scale(9.0f);
if (icon == EButtonIcon::LBRB)
{
_icon = EButtonIcon::LB;
}
else if (icon == EButtonIcon::LTRT)
{
_icon = EButtonIcon::LT;
}
else
{
dualIconMarginX = 0;
}
ImVec2 textPos;
if (icon == EButtonIcon::LBRB || icon == EButtonIcon::LTRT)
{
iconMin = alignment == EButtonAlignment::Left
? ImVec2(/* X */ regionMin.x + *offset - dualIconMarginX * 3, /* Y */ iconMin.y)
: ImVec2(/* X */ regionMax.x - *offset - textSize.x - iconWidth, /* Y */ iconMin.y);
auto iconMarginX = Scale(16);
iconMax = alignment == EButtonAlignment::Left
? ImVec2(iconMin.x + iconWidth, iconMax.y)
: ImVec2(iconMin.x, iconMax.y);
}
iconMin.x = alignment == EButtonAlignment::Left
? regionMin.x + *offset - maxTextWidth + (iconWidth / 2)
: regionMax.x - *offset - maxTextWidth - (iconWidth / 2) - iconMarginX;
auto btnIcon = GetButtonIcon(_icon);
drawList->AddImage(std::get<1>(btnIcon), iconMin, iconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
iconMax.x = iconMin.x + iconWidth;
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);
// 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(/* X */ regionMin.x + *offset + textSize.x + dualIconMarginX * 2, /* Y */ iconMin.y)
: ImVec2(/* X */ regionMax.x - *offset + textSize.x - dualIconMarginX, /* Y */ iconMin.y);
? 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)));
*offset += dualIconMarginX + iconWidth;
textPos = { (iconMax.x + ((dualIconMin.x - iconMax.x) - maxTextWidth + std::max(0.0f, maxTextWidth - textWidth)) / 2) + Scale(2), textMarginY};
*offset += iconWidth;
}
else
{
auto btnIcon = GetButtonIcon(icon);
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 });
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.
drawList->AddText(g_fntNewRodin, fontSize, textPos, IM_COL32(255, 255, 255, 127), text);
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
}
SetScale({ 1.0f, 1.0f });
SetOrigin({ 0.0f, 0.0f });
}
void ButtonGuide::Init()
@@ -224,8 +218,6 @@ void ButtonGuide::Init()
auto& io = ImGui::GetIO();
g_fntNewRodin = ImFontAtlasSnapshot::GetFont("FOT-NewRodinPro-M.otf");
g_fntNewRodinLQ = ImFontAtlasSnapshot::GetFont("FOT-NewRodinPro-M.otf");
g_upControllerIcons = LOAD_ZSTD_TEXTURE(g_controller);
g_upKBMIcons = LOAD_ZSTD_TEXTURE(g_kbm);
}
@@ -241,10 +233,9 @@ void ButtonGuide::Draw()
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) };
auto textMarginX = Scale(57);
auto textMarginY = Scale(8);
auto textMarginX = Scale(21.25f);
auto iconMarginX = Scale(4);
auto fontSize = Scale(22.5f);
auto fontSize = Scale(21.8f);
auto offsetLeft = 0.0f;
auto offsetRight = 0.0f;
@@ -260,18 +251,20 @@ void ButtonGuide::Draw()
if (btn.Visibility && !*btn.Visibility)
continue;
auto str = Localise(btn.Name.c_str()).c_str();
auto str = Localise(btn.Name).c_str();
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str);
auto textWidth = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str).x;
auto maxWidth = btn.MaxWidth == FLT_MAX ? textWidth : Scale(btn.MaxWidth);
auto textScale = std::min(1.0f, maxWidth / textWidth);
if (i > 0)
offsetLeft += textSize.x + iconWidth + textMarginX;
offsetLeft += maxWidth + iconWidth + textMarginX;
ImVec2 iconMin = { regionMin.x + offsetLeft - iconWidth - iconMarginX, regionMin.y };
ImVec2 iconMax = { regionMin.x + offsetLeft - iconMarginX, regionMin.y + iconHeight };
DrawGuide(&offsetLeft, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, str);
DrawGuide(&offsetLeft, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textWidth, maxWidth, textScale, fontSize, str);
}
// Draw right aligned icons.
@@ -285,18 +278,20 @@ void ButtonGuide::Draw()
if (btn.Visibility && !*btn.Visibility)
continue;
auto str = Localise(btn.Name.c_str()).c_str();
auto str = Localise(btn.Name).c_str();
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str);
auto textWidth = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str).x;
auto maxWidth = btn.MaxWidth == FLT_MAX ? textWidth : Scale(btn.MaxWidth);
auto textScale = std::min(1.0f, maxWidth / textWidth);
if (i < g_buttons.size() - 1)
offsetRight += textSize.x + iconWidth + textMarginX;
offsetRight += maxWidth + iconWidth + textMarginX;
ImVec2 iconMin = { regionMax.x - offsetRight - iconWidth - iconMarginX, regionMin.y };
ImVec2 iconMax = { regionMax.x - offsetRight - iconMarginX, regionMin.y + iconHeight };
DrawGuide(&offsetRight, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, str);
DrawGuide(&offsetRight, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textWidth, maxWidth, textScale, fontSize, str);
}
}
+9 -5
View File
@@ -40,19 +40,23 @@ class Button
{
public:
std::string Name{};
float MaxWidth{ FLT_MAX };
EButtonIcon Icon{};
EButtonAlignment Alignment{ EButtonAlignment::Right };
EFontQuality FontQuality{ EFontQuality::High };
bool* Visibility{ nullptr };
Button(std::string name, EButtonIcon icon, EButtonAlignment alignment, EFontQuality fontQuality = EFontQuality::High, bool* visibility = nullptr)
: Name(name), Icon(icon), Alignment(alignment), FontQuality(fontQuality), Visibility(visibility) {}
Button(std::string name, float maxWidth, EButtonIcon icon, EButtonAlignment alignment, EFontQuality fontQuality = EFontQuality::High, bool* visibility = nullptr)
: Name(name), MaxWidth(maxWidth), Icon(icon), Alignment(alignment), FontQuality(fontQuality), Visibility(visibility) {}
Button(std::string name, EButtonIcon icon, EButtonAlignment alignment, bool* visibility) : Name(name), Icon(icon), Alignment(alignment), Visibility(visibility) {}
Button(std::string name, float maxWidth, EButtonIcon icon, EButtonAlignment alignment, bool* visibility)
: Name(name), MaxWidth(maxWidth), Icon(icon), Alignment(alignment), Visibility(visibility) {}
Button(std::string name, EButtonIcon icon, bool* visibility) : Name(name), Icon(icon), Visibility(visibility) {}
Button(std::string name, float maxWidth, EButtonIcon icon, bool* visibility)
: Name(name), MaxWidth(maxWidth), Icon(icon), Visibility(visibility) {}
Button(std::string name, EButtonIcon icon) : Name(name), Icon(icon) {}
Button(std::string name, float maxWidth, EButtonIcon icon, EFontQuality fontQuality = EFontQuality::High)
: Name(name), MaxWidth(maxWidth), Icon(icon), FontQuality(fontQuality) {}
};
class ButtonGuide
+136 -3
View File
@@ -45,6 +45,9 @@ void ResetGradient()
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);
callbackData->setShaderModifier.shaderModifier = shaderModifier;
}
@@ -461,17 +464,39 @@ std::vector<std::string> Split(const char* strStart, const ImFont* font, float f
const bool wordWrapEnabled = (maxWidth > 0.0f);
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)
{
if (wordWrapEnabled)
{
if (wordWrapEOL == nullptr)
{
wordWrapEOL = font->CalcWordWrapPositionA(scale, str, strEnd, maxWidth - lineWidth);
wordWrapEOL = CalcWordWrapPositionA(font, scale, str, strEnd, maxWidth - lineWidth);
}
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)
textWidth = lineWidth;
@@ -645,7 +670,7 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidt
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)
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)
{
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
@@ -653,8 +678,14 @@ void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, c
auto lines = Split(input.first.c_str(), font, fontSize, maxWidth);
for (auto& line : lines)
{
line = ReAddRubyAnnotations(line, input.second);
if (!line.empty() && line.substr(0, 3) != "" && leadingSpace)
{
line.insert(0, " ");
}
}
auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines);
auto offsetY = 0.0f;
@@ -823,3 +854,105 @@ void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha)
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;
}
+2 -1
View File
@@ -72,7 +72,7 @@ std::vector<std::string> RemoveAnnotationFromParagraph(const std::vector<std::st
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 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);
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);
float Lerp(float a, float b, float t);
float Cubic(float a, float b, float t);
float Hermite(float a, float b, float t);
@@ -81,3 +81,4 @@ ImU32 ColourLerp(ImU32 c0, ImU32 c1, float t);
void DrawVersionString(const ImFont* font, const ImU32 col = IM_COL32(255, 255, 255, 70));
void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop = false);
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);
+18 -6
View File
@@ -736,6 +736,14 @@ static void DrawDescriptionContainer()
}
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);
}
@@ -769,6 +777,8 @@ static void DrawDescriptionContainer()
textX += annotationFontSize;
textY += annotationFontSize;
lineWidth += annotationFontSize;
}
drawList->PushClipRect(clipRectMin, clipRectMax, false);
@@ -788,7 +798,9 @@ static void DrawDescriptionContainer()
[=](const char* str, float size, ImVec2 pos)
{
DrawTextBasic(g_seuratFont, size, pos, IM_COL32(255, 255, 255, 255 * textAlpha), str);
}
},
false,
Config::Language == ELanguage::Japanese
);
drawList->PopClipRect();
@@ -872,7 +884,7 @@ static void DrawDescriptionContainer()
if (g_currentPage == WizardPage::InstallSucceeded && textAlpha >= 1.0)
{
ButtonGuide::Open(Button("Common_Select", selectIcon));
ButtonGuide::Open(Button("Common_Select", 115.0f, selectIcon));
}
else if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
{
@@ -884,15 +896,15 @@ static void DrawDescriptionContainer()
std::array<Button, 2> buttons =
{
Button("Common_Select", selectIcon),
Button(backKey, backIcon)
Button("Common_Select", 115.0f, selectIcon),
Button(backKey, FLT_MAX, backIcon)
};
ButtonGuide::Open(buttons);
}
else if (g_currentPage == WizardPage::Installing)
{
ButtonGuide::Open(Button("Common_Cancel", backIcon));
ButtonGuide::Open(Button("Common_Cancel", FLT_MAX, backIcon));
}
else
{
@@ -1399,7 +1411,7 @@ static void DrawNavigationButton()
float squashRatio;
constexpr float NAV_BUTTON_MAX_TEXT_WIDTH = 90.0f;
const char *nextButtonKey = "Installer_Button_Next";
std::string_view nextButtonKey = "Installer_Button_Next";
if (skipButton)
{
nextButtonKey = "Installer_Button_Skip";
+37 -9
View File
@@ -223,6 +223,10 @@ void DrawButton(int rowIndex, float yOffset, float width, float height, std::str
auto fontSize = Scale(28);
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
(
g_fntSeurat,
@@ -231,6 +235,10 @@ 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),
text.c_str()
);
// Reset the shader modifier.
if (App::s_isInit)
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
}
void DrawNextButtonGuide(bool isController, bool isKeyboard)
@@ -241,11 +249,16 @@ void DrawNextButtonGuide(bool isController, bool isKeyboard)
? EButtonIcon::Enter
: EButtonIcon::LMB;
// Always show controller prompt in-game.
if (App::s_isInit)
icon = EButtonIcon::A;
auto fontQuality = EFontQuality::High;
ButtonGuide::Open(Button("Common_Next", icon));
// Always show controller prompt and low quality text in-game.
if (App::s_isInit)
{
icon = EButtonIcon::A;
fontQuality = EFontQuality::Low;
}
ButtonGuide::Open(Button("Common_Next", FLT_MAX, icon, fontQuality));
}
static void ResetSelection()
@@ -338,6 +351,10 @@ void MessageWindow::Draw()
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
(
g_fntSeurat,
@@ -353,12 +370,16 @@ void MessageWindow::Draw()
},
[=](const char* str, float size, ImVec2 pos)
{
DrawTextWithShadow(g_fntSeurat, size, pos, IM_COL32(255, 255, 255, 255), str, 1.0f);
DrawTextWithShadow(g_fntSeurat, size, pos, IM_COL32(255, 255, 255, 255), str, 1.5f, 1.5f);
},
true
);
// Reset the shader modifier.
if (App::s_isInit)
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
drawList->PopClipRect();
if (g_buttons.size())
@@ -423,10 +444,17 @@ void MessageWindow::Draw()
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 =
{
Button("Common_Select", selectIcon),
Button("Common_Back", backIcon),
Button("Common_Select", 115.0f, selectIcon, fontQuality),
Button("Common_Back", FLT_MAX, backIcon, fontQuality),
};
ButtonGuide::Open(buttons);
@@ -470,8 +498,8 @@ void MessageWindow::Draw()
std::array<Button, 2> buttons =
{
Button(Localise("Common_Select"), EButtonIcon::LMB),
Button(Localise("Common_Back"), EButtonIcon::Escape),
Button("Common_Select", 115.0f, EButtonIcon::LMB),
Button("Common_Back", FLT_MAX, EButtonIcon::Escape),
};
ButtonGuide::Open(buttons);
+13 -11
View File
@@ -449,11 +449,8 @@ static bool DrawCategories()
auto inputState = SWA::CInputState::GetInstance();
bool moveLeft = !g_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_LeftBumper) ||
inputState->GetPadState().IsTapped(SWA::eKeyState_LeftTrigger));
bool moveRight = !g_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper) ||
inputState->GetPadState().IsTapped(SWA::eKeyState_RightTrigger));
bool moveLeft = !g_lockedOnOption && inputState->GetPadState().IsTapped(SWA::eKeyState_LeftBumper);
bool moveRight = !g_lockedOnOption && inputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper);
if (moveLeft)
{
@@ -1497,6 +1494,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
auto textX = clipRectMin.x - Scale(0.5f);
auto textY = thumbnailMax.y + offsetY;
float lineWidth = clipRectMax.x - clipRectMin.x;
if (Config::Language == ELanguage::Japanese)
{
@@ -1511,9 +1509,13 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
clipRectMax.x += 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, clipRectMax.x - clipRectMin.x, 5.0f, desc.c_str());
auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, lineWidth, 5.0f, desc.c_str());
drawList->PushClipRect(clipRectMin, clipRectMax, false);
@@ -1589,7 +1591,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
(
g_seuratFont,
fontSize,
clipRectMax.x - clipRectMin.x,
lineWidth,
{ textX, textY - scrollOffset },
5.0f,
desc.c_str(),
@@ -1790,10 +1792,10 @@ void OptionsMenu::Open(bool isPause, SWA::EMenuType pauseMenuType)
std::array<Button, 4> buttons =
{
Button("Common_Switch", EButtonIcon::LBRB, EButtonAlignment::Left, &g_isControlsVisible),
Button("Common_Reset", EButtonIcon::X, &g_canReset),
Button("Common_Select", EButtonIcon::A, &g_isControlsVisible),
Button("Common_Back", EButtonIcon::B, &g_isControlsVisible)
Button("Common_Switch", 115.0f, EButtonIcon::LBRB, EButtonAlignment::Left, &g_isControlsVisible),
Button("Common_Reset", 110.0f, EButtonIcon::X, &g_canReset),
Button("Common_Select", 115.0f, EButtonIcon::A, &g_isControlsVisible),
Button("Common_Back", 65.0f, EButtonIcon::B, &g_isControlsVisible)
};
ButtonGuide::Open(buttons);
+56 -42
View File
@@ -2,9 +2,9 @@
#include <decompressor.h>
#include <hid/hid.h>
// TODO (Hyper): lower the resolution of these textures once final.
#include <res/images/options_menu/thumbnails/achievement_notifications.dds.h>
#include <res/images/options_menu/thumbnails/allow_background_input.dds.h>
#include <res/images/options_menu/thumbnails/allow_background_input_xb.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_2x.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/channel_stereo.dds.h>
#include <res/images/options_menu/thumbnails/channel_surround.dds.h>
#include <res/images/options_menu/thumbnails/control_tutorial_xb.dds.h>
#include <res/images/options_menu/thumbnails/control_tutorial_ps.dds.h>
#include <res/images/options_menu/thumbnails/control_tutorial_xb.dds.h>
#include <res/images/options_menu/thumbnails/controller_icons.dds.h>
#include <res/images/options_menu/thumbnails/default.dds.h>
#include <res/images/options_menu/thumbnails/effects_volume.dds.h>
@@ -35,23 +35,21 @@
#include <res/images/options_menu/thumbnails/movie_scale_fill.dds.h>
#include <res/images/options_menu/thumbnails/music_attenuation.dds.h>
#include <res/images/options_menu/thumbnails/music_volume.dds.h>
#include <res/images/options_menu/thumbnails/resolution_scale.dds.h>
#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_x1024.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_x8192.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_ps.dds.h>
#include <res/images/options_menu/thumbnails/time_transition_xb.dds.h>
#include <res/images/options_menu/thumbnails/transparency_antialiasing_false.dds.h>
#include <res/images/options_menu/thumbnails/transparency_antialiasing_true.dds.h>
#include <res/images/options_menu/thumbnails/ui_alignment_centre.dds.h>
#include <res/images/options_menu/thumbnails/ui_alignment_edge.dds.h>
#include <res/images/options_menu/thumbnails/vertical_camera.dds.h>
#include <res/images/options_menu/thumbnails/voice_language.dds.h>
#include <res/images/options_menu/thumbnails/vibration.dds.h>
#include <res/images/options_menu/thumbnails/vibration_ps.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_off.dds.h>
#include <res/images/options_menu/thumbnails/window_size.dds.h>
@@ -59,7 +57,15 @@
#define VALUE_THUMBNAIL_MAP(type) std::unordered_map<type, std::unique_ptr<GuestTexture>>
static std::unordered_map<std::string_view, std::unique_ptr<GuestTexture>> g_namedThumbnails;
static std::unique_ptr<GuestTexture> g_defaultThumbnail;
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 VALUE_THUMBNAIL_MAP(ETimeOfDayTransition) g_timeOfDayTransitionThumbnails;
@@ -76,14 +82,17 @@ static VALUE_THUMBNAIL_MAP(EUIAlignmentMode) g_uiAlignmentThumbnails;
void LoadThumbnails()
{
g_namedThumbnails["Default"] = LOAD_ZSTD_TEXTURE(g_default);
g_namedThumbnails["WindowSize"] = LOAD_ZSTD_TEXTURE(g_window_size);
g_namedThumbnails["ControlTutorialXB"] = LOAD_ZSTD_TEXTURE(g_control_tutorial_xb);
g_namedThumbnails["ControlTutorialPS"] = LOAD_ZSTD_TEXTURE(g_control_tutorial_ps);
g_defaultThumbnail = LOAD_ZSTD_TEXTURE(g_default);
g_controlTutorialXBThumbnail = LOAD_ZSTD_TEXTURE(g_control_tutorial_xb);
g_controlTutorialPSThumbnail = 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::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::AchievementNotifications] = LOAD_ZSTD_TEXTURE(g_achievement_notifications);
@@ -92,8 +101,6 @@ void LoadThumbnails()
g_configThumbnails[&Config::HorizontalCamera] = LOAD_ZSTD_TEXTURE(g_horizontal_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::MasterVolume] = LOAD_ZSTD_TEXTURE(g_master_volume);
g_configThumbnails[&Config::MusicVolume] = LOAD_ZSTD_TEXTURE(g_music_volume);
@@ -107,8 +114,8 @@ void LoadThumbnails()
g_configThumbnails[&Config::WindowSize] = LOAD_ZSTD_TEXTURE(g_window_size);
g_configThumbnails[&Config::Monitor] = LOAD_ZSTD_TEXTURE(g_monitor);
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::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
g_vsyncThumbnails[false] = LOAD_ZSTD_TEXTURE(g_vsync_off);
g_vsyncThumbnails[true] = LOAD_ZSTD_TEXTURE(g_vsync_on);
@@ -124,7 +131,6 @@ void LoadThumbnails()
g_transparencyAntiAliasingThumbnails[false] = LOAD_ZSTD_TEXTURE(g_transparency_antialiasing_false);
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::x1024] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x1024);
g_shadowResolutionThumbnails[EShadowResolution::x2048] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x2048);
@@ -143,8 +149,6 @@ void LoadThumbnails()
g_uiAlignmentThumbnails[EUIAlignmentMode::Centre] = LOAD_ZSTD_TEXTURE(g_ui_alignment_centre);
g_uiAlignmentThumbnails[EUIAlignmentMode::Edge] = LOAD_ZSTD_TEXTURE(g_ui_alignment_edge);
g_configThumbnails[&Config::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
}
template<typename T>
@@ -156,40 +160,50 @@ bool TryGetValueThumbnail(const IConfigDef* cfg, VALUE_THUMBNAIL_MAP(T)* thumbna
if (!cfg->GetValue())
return false;
auto result = thumbnails->at(*(T*)cfg->GetValue()).get();
T value = *(T*)cfg->GetValue();
if (!result)
return false;
if constexpr (std::is_same_v<T, EShadowResolution>)
{
if (value == EShadowResolution::Original)
value = EShadowResolution::x1024;
}
*texture = result;
auto findResult = thumbnails->find(value);
return true;
}
if (findResult != thumbnails->end())
{
*texture = findResult->second.get();
return true;
}
GuestTexture* GetThumbnail(const std::string_view name)
{
if (!g_namedThumbnails.count(name))
return g_namedThumbnails["Default"].get();
return g_namedThumbnails[name].get();
return false;
}
GuestTexture* GetThumbnail(const IConfigDef* cfg)
{
if (!g_configThumbnails.count(cfg))
auto findResult = g_configThumbnails.find(cfg);
if (findResult == g_configThumbnails.end())
{
auto texture = g_namedThumbnails["Default"].get();
auto texture = g_defaultThumbnail.get();
bool isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation;
if (Config::ControllerIcons == EControllerIcons::Auto)
isPlayStation = hid::g_inputDeviceController == hid::EInputDevice::PlayStation;
if (cfg == &Config::ControlTutorial)
{
bool isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation;
if (Config::ControllerIcons == EControllerIcons::Auto)
isPlayStation = hid::g_inputDeviceController == hid::EInputDevice::PlayStation;
texture = isPlayStation ? g_namedThumbnails["ControlTutorialPS"].get() : g_namedThumbnails["ControlTutorialXB"].get();
texture = isPlayStation ? g_controlTutorialPSThumbnail.get() : g_controlTutorialXBThumbnail.get();
}
if (cfg == &Config::TimeOfDayTransition)
else if (cfg == &Config::Vibration)
{
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);
}
@@ -237,5 +251,5 @@ GuestTexture* GetThumbnail(const IConfigDef* cfg)
return texture;
}
return g_configThumbnails[cfg].get();
return findResult->second.get();
}
@@ -5,5 +5,4 @@
void LoadThumbnails();
GuestTexture* GetThumbnail(const std::string_view name);
GuestTexture* GetThumbnail(const IConfigDef* cfg);
+48 -58
View File
@@ -511,43 +511,33 @@ std::string_view ConfigDef<T, isHidden>::GetName() const
template<typename T, bool isHidden>
std::string ConfigDef<T, isHidden>::GetNameLocalised(ELanguage language) const
{
if (!Locale)
return Name;
if (!Locale->count(language))
if (Locale != nullptr)
{
if (Locale->count(ELanguage::English))
{
return std::get<0>(Locale->at(ELanguage::English));
}
else
{
return Name;
}
auto languageFindResult = Locale->find(language);
if (languageFindResult == Locale->end())
languageFindResult = Locale->find(ELanguage::English);
if (languageFindResult != Locale->end())
return std::get<0>(languageFindResult->second);
}
return std::get<0>(Locale->at(language));
return Name;
}
template<typename T, bool isHidden>
std::string ConfigDef<T, isHidden>::GetDescription(ELanguage language) const
{
if (!Locale)
return "";
if (!Locale->count(language))
if (Locale != nullptr)
{
if (Locale->count(ELanguage::English))
{
return std::get<1>(Locale->at(ELanguage::English));
}
else
{
return "";
}
auto languageFindResult = Locale->find(language);
if (languageFindResult == Locale->end())
languageFindResult = Locale->find(ELanguage::English);
if (languageFindResult != Locale->end())
return std::get<1>(languageFindResult->second);
}
return std::get<1>(Locale->at(language));
return "";
}
template<typename T, bool isHidden>
@@ -578,27 +568,27 @@ std::string ConfigDef<T, isHidden>::GetValueLocalised(ELanguage language) const
: Localise("Common_Off");
}
if (!locale)
return ToString(false);
if (!locale->count(language))
if (locale != nullptr)
{
if (locale->count(ELanguage::English))
ELanguage languages[] = { language, ELanguage::English };
for (auto languageToFind : languages)
{
language = ELanguage::English;
}
else
{
return ToString(false);
auto languageFindResult = locale->find(languageToFind);
if (languageFindResult != locale->end())
{
auto valueFindResult = languageFindResult->second.find(Value);
if (valueFindResult != languageFindResult->second.end())
return std::get<0>(valueFindResult->second);
}
if (languageToFind == ELanguage::English)
break;
}
}
auto strings = locale->at(language);
if (!strings.count(Value))
return ToString(false);
return std::get<0>(strings.at(Value));
return ToString(false);
}
template<typename T, bool isHidden>
@@ -615,27 +605,27 @@ std::string ConfigDef<T, isHidden>::GetValueDescription(ELanguage language) cons
return "";
}
if (!locale)
return "";
if (!locale->count(language))
if (locale != nullptr)
{
if (locale->count(ELanguage::English))
ELanguage languages[] = { language, ELanguage::English };
for (auto languageToFind : languages)
{
language = ELanguage::English;
}
else
{
return "";
auto languageFindResult = locale->find(languageToFind);
if (languageFindResult != locale->end())
{
auto valueFindResult = languageFindResult->second.find(Value);
if (valueFindResult != languageFindResult->second.end())
return std::get<1>(valueFindResult->second);
}
if (languageToFind == ELanguage::English)
break;
}
}
auto strings = locale->at(language);
if (!strings.count(Value))
return "";
return std::get<1>(strings.at(Value));
return "";
}
template<typename T, bool isHidden>
+1
View File
@@ -91,5 +91,6 @@ CONFIG_DEFINE_HIDDEN("Codes", bool, SaveScoreAtCheckpoints, false);
CONFIG_DEFINE_HIDDEN("Codes", bool, SkipIntroLogos, false);
CONFIG_DEFINE_HIDDEN("Codes", bool, UseArrowsForTimeOfDayTransition, false);
CONFIG_DEFINE_HIDDEN("Codes", bool, UseOfficialTitleOnTitleBar, false);
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableLowResolutionFontOnCustomUI, false);
CONFIG_DEFINE("Update", time_t, LastChecked, 0);
+4 -1
View File
@@ -28,7 +28,10 @@ endforeach()
add_custom_command(
OUTPUT ${UNLEASHED_RECOMP_PPC_RECOMPILED_SOURCES}
COMMAND $<TARGET_FILE:XenonRecomp>
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex" "${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml"
DEPENDS
"${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")
+40 -3
View File
@@ -1,5 +1,7 @@
[main]
file_path = "../private/default.xex"
patch_file_path = "../private/default.xexp"
patched_file_path = "../private/default_patched.xex"
out_directory_path = "../ppc"
switch_table_file_path = "SWA_switch_tables.toml"
@@ -176,6 +178,12 @@ name = "DisableHintsMidAsmHook"
address = 0x829E409C
jump_address_on_true = 0x829E40A0
# Disable Chip hints for shoe upgrades
[[midasm_hook]]
name = "DisableHintsMidAsmHook"
address = 0x82691CB0
jump_address_on_true = 0x82691E24
# Disable navigation volumes
[[midasm_hook]]
name = "DisableControlTutorialMidAsmHook"
@@ -608,13 +616,13 @@ jump_address = 0x82585480
name = "LoadingScreenControllerMidAsmHook"
address = 0x824DC9D4
# SWA::Player::CPlayerSpeedPostureInputOnPath
# SWA::Player::CPlayerSpeedPostureInputOnPath / SWA::Player::CPlayerSpeedPostureInputForcePath / SWA::Player::CPlayerSpeedPostureInput2DStandard
[[midasm_hook]]
name = "PostureDPadSupportInvertYMidAsmHook"
address = 0x8234F194
registers = ["r31", "f13", "f0"]
# SWA::Player::CPlayerSpeedPostureInputOnPathLocal
# SWA::Player::CPlayerSpeedPostureInputPathLocal
[[midasm_hook]]
name = "PostureDPadSupportMidAsmHook"
address = 0x8234F610
@@ -722,7 +730,7 @@ name = "PostureDPadSupportXMidAsmHook"
address = 0x8266B6AC
registers = ["r29", "f0"]
# SWA::Player::CSonicStateStompingLand
# SWA::Player::CPlayerSpeedStateNormalDamageStandUp / SWA::Player::CSonicStateStartEvent / SWA::Player::CSonicStateStompingLand
[[midasm_hook]]
name = "PostureDPadSupportMidAsmHook"
address = 0x8231F824
@@ -771,6 +779,30 @@ address = 0x82454104
registers = ["r29", "f28", "f27"]
after_instruction = true
# SWA::CBossEggBeetle
[[midasm_hook]]
name = "PostureDPadSupportXMidAsmHook"
address = 0x829A4FCC
registers = ["r29", "f13"]
# SWA::CBossEggRayBird (horizontal)
[[midasm_hook]]
name = "PostureDPadSupportXMidAsmHook"
address = 0x829BA7E0
registers = ["r21", "f13"]
# SWA::CBossEggRayBird (vertical)
[[midasm_hook]]
name = "PostureDPadSupportYMidAsmHook"
address = 0x829C53E8
registers = ["r21", "f13"]
# SWA::CBossEggLancer
[[midasm_hook]]
name = "PostureDPadSupportXMidAsmHook"
address = 0x82A55A48
registers = ["r21", "f13"]
# SWA::CWorldMapCamera - disable rotation deadzone for touch
[[midasm_hook]]
name = "WorldMapDeadzoneMidAsmHook"
@@ -1056,3 +1088,8 @@ registers = ["r4"]
name = "AnimationDataMakeMidAsmHook"
address = 0x82BB38E4
registers = ["r31", "r29", "r28"]
[[midasm_hook]]
name = "ObjGrindDashPanelAllocMidAsmHook"
address = 0x82614948
registers = ["r3"]
@@ -38,6 +38,16 @@
"path": "private/default.xex",
"dest": "UnleashedRecompLib/private"
},
{
"type": "file",
"path": "private/default.xexp",
"dest": "UnleashedRecompLib/private"
},
{
"type": "file",
"path": "private/default_patched.xex",
"dest": "UnleashedRecompLib/private"
},
{
"type": "file",
"path": "private/shader.ar",
-223
View File
@@ -1,223 +0,0 @@
/*
*
* 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
Submodule thirdparty/libmspack deleted from 305907723a
Submodule thirdparty/tiny-AES-c deleted from 23856752fb